score:3

Accepted answer

On top of the comment about re-appending the groups and the answer about splitting the selection, you have to change the text position in your update selection...

labelArcs.transition().duration(1000)
    .attr("transform", (d) => `translate(${arcLabels.centroid(d)})`);

...as well as changing the text values in the <tspan> elements:

labelArcs.select(".type")
    .text((d) => d.data.type);

labelArcs.select(".value")
    .text((d) => commaFormat(d.data.percentage).toLocaleString() + " %");

Here is the resulting code:

async function draw() {
  // Data
  let dataset;
  let dataTime;
  const commaFormat = d3.format(",");
  const timeFormat = d3.timeFormat("%d-%m-%Y %I:%M");

  // Dimensions
  let dimensions = {
    width: 700,
    height: 700,
    margins: 10,
  };

  dimensions.ctrWidth = dimensions.width - dimensions.margins * 2;
  dimensions.ctrHeight = dimensions.height - dimensions.margins * 2;
  const radius = dimensions.ctrHeight / 3;

  // Draw Image
  const svg = d3
    .select("#chart-area")
    .append("svg")
    .attr("width", dimensions.width)
    .attr("height", dimensions.height);

  const ctr = svg
    .append("g") // <g>
    .attr(
      "transform",
      `translate(${dimensions.margins}, ${dimensions.margins})`
    );

  const arc = d3
    .arc()
    .outerRadius(radius)
    .innerRadius(radius * 0.8);

  const arcLabels = d3
    .arc()
    .outerRadius(radius * 1.2)
    .innerRadius(radius * 1.2);

  const arcGroup = ctr
    .append("g")
    .attr(
      "transform",
      `translate(${dimensions.ctrHeight / 2}, ${dimensions.ctrWidth / 2})`
    );

  const dataTimestamp = svg
    .append("text")
    .attr(
      "transform",
      `translate(${dimensions.ctrHeight / 2}, ${dimensions.ctrWidth / 2})`
    )
    .attr("text-anchor", "middle")
    .append("tspan")
    .attr("x", "+0.2em")
    .attr("y", "+2.5em")
    .attr("font-size", 20);

  //Labels
  const labelsGroup = ctr
    .append("g")
    .attr(
      "transform",
      `translate(${dimensions.ctrHeight / 2}, ${dimensions.ctrWidth / 2})`
    );

  d3.json("https://raw.githubusercontent.com/1crisl/test/main/data.json").then((data) => {
    const timeArray = data.map((record) => {
      return record.unixTime;
    });
    const minTime = d3.min(timeArray);
    const maxTime = d3.max(timeArray);
    let i = timeArray.length - 1;
    $("#dateLabel1").text(timeFormat(minTime));
    $("#dateLabel2").text(timeFormat(maxTime));
    $("#date-slider").slider({
      max: timeArray.length - 1,
      min: 0,
      value: timeArray.length - 1,
      change: (event, ui) => {
        i = $("#date-slider").slider("value");
        dataTime = data[i].unixTime;
        dataset = data[i].data.filter(function(obj) {
          return obj.percentage > "1";
        });
        update();
      },
    });
    dataTime = data[i].unixTime;
    dataset = data[i].data.filter(function(obj) {
      return obj.percentage > "1";
    });
    update();
  });

  function update() {
    // Scales
    const colors = d3.quantize(d3.interpolateSpectral, dataset.length); //Generates a colour for each item in the dataset array
    const colorScale = d3
      .scaleOrdinal()
      .domain(dataset.map((d) => d.type))
      .range(colors);
    //Define Pie Chart
    const generationPie = d3
      .pie()
      .padAngle(0.005)
      .value((d) => d.generation)
      .sort(null);
    //Pass dataset into Pie Chart
    const slices = generationPie(dataset);
    //JOIN DATA
    const arcs = arcGroup.selectAll("path").data(slices);
    //ENTER NEW DATA
    arcs
      .enter()
      .append("path")
      .attr("d", arc)
      .attr("fill", (d) => colorScale(d.data.type))
      .each(function(d) {
        this._current = d;
      });
    //UPDATE
    arcs.transition().duration(1000).attrTween("d", arcTween);
    //REMOVE OLD DATA
    arcs.exit().remove();

    function arcTween(a) {
      var i = d3.interpolate(this._current, a);
      this._current = i(0);
      return function(t) {
        return arc(i(t));
      };
    }
    //==============================================================

    //Data timestamp
    //Join
    const dataTimeLabel = dataTimestamp.text(timeFormat(dataTime));
    //Update
    dataTimeLabel.transition().duration(1000);
    //ENTER
    dataTimeLabel.enter().text(timeFormat(dataTime));
    //REMOVE
    dataTimeLabel.exit().remove();

    //==============================================================

    //JOIN
    const labelArcs = labelsGroup.selectAll("text").data(slices, d => d.data.type);
    //ENTER
    const textGroup = labelArcs
      .enter()
      .append("text")
      .attr("transform", (d) => `translate(${arcLabels.centroid(d)})`);

    textGroup
      .append("tspan")
      .attr("font-weight", "bold")
      .attr("font-size", 14)
      .attr("x", "-2em")
      .attr("class", "type")
      .text((d) => d.data.type);

    textGroup
      .append("tspan")
      .attr("x", "-2.3em")
      .attr("y", "+1.2em")
      .attr("fill-opacity", 0.7)
      .attr("font-size", 12)
      .attr("class", "value")
      .text((d) => commaFormat(d.data.percentage).toLocaleString() + " %");

    //UPDATE
    labelArcs.select(".type")
      .text((d) => d.data.type);

    labelArcs.select(".value")
      .text((d) => commaFormat(d.data.percentage).toLocaleString() + " %");

    labelArcs.transition().duration(1000)
      .attr("transform", (d) => `translate(${arcLabels.centroid(d)})`);


    //REMOVE
    labelArcs.exit().remove();
  }
}

draw();
<!doctype html>
<html>

<head>
  <meta charset="utf-8">
  <meta name="description" content="">
  <title>Visualisation</title>
  <!-- Bootstrap -->
  <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
  <!-- jQueryUI styling -->
  <link rel="stylesheet" href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
</head>

<body>

  <!-- Bootstrap grid setup -->
  <div class="container">
    <div class="row">
      <div class="col-md-12 d-flex justify-content-center">
        <div id="chart-area"></div>
      </div>
      <div class="col-md-12 d-flex justify-content-center">
        <div id="slider-div">
          <label>Data Extent</label>
          <br>
          <label><span id="dateLabel1">01/01/2000</span> to <span id="dateLabel2">18/03/2021</span></label>
          <div id="date-slider"></div>
        </div>
      </div>
    </div>
  </div>

  <!-- External JS libraries -->
  <script src="https://d3js.org/d3.v5.min.js"></script>
  <script src="https://code.jquery.com/jquery-3.5.1.min.js" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script>
  <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
  <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script>
  <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js" integrity="sha256-VazP97ZCwtekAsvgPBSUwPFKdrwD3unUfSGVYrahUqU=" crossorigin="anonymous"></script>
  <!-- Custom JS -->
  <script src="js/main.js"></script>
</body>

</html>

PS: your percentages are way off.

score:1

Try to split code:

const textGroup = labelArcs
      .enter()
      .append("text")
      .attr("transform", (d) => `translate(${arcLabels.centroid(d)})`)
      
textGroup.append("tspan")
      .attr("font-weight", "bold")
      .attr("font-size", 14)
      .attr("x", "-2em")
      .text((d) => d.data.type)
      
textGroup.append("tspan")
      .attr("x", "-2.3em")
      .attr("y", "+1.2em")
      .attr("fill-opacity", 0.7)
      .attr("font-size", 12)
      .text((d) => commaFormat(d.data.percentage).toLocaleString() + " %")

If it does not help, please provide a snippet of a fiddle to work with


Related Query

More Query from same tag