0
votes

I am relatively new to javascript. Recently I was tasked to create a dashboard and thus I started using amcharts.js for my visualisations.

Hence, I would like to ask for guidance in order to create a pie of a pie of a pie chart (Basically adding another layer to this example as provided by amcharts https://www.amcharts.com/demos/pie-of-a-pie/.

I have tried for quite some time myself but was unsuccessful as seen here https://codepen.io/zxlow/pen/wvvJrZJ

// Themes begin
am4core.useTheme(am4themes_dataviz);
am4core.useTheme(am4themes_animated);
// Themes end

var container = am4core.create("chartdiv", am4core.Container);
container.width = am4core.percent(100);
container.height = am4core.percent(100);
container.layout = "horizontal";


var chart = container.createChild(am4charts.PieChart);

// Add data
chart.data = [{
  "country": "Lithuania",
  "litres": 500,
  "subData": [{ name: "A", value: 200 }, 
              { name: "B", value: 150 }, 
              { name: "C", value: 100 },
              { name: "D", value: 50,
                subData: [{name: "D2", value: 35,
                      name: "D3", value: 15}]
              }]
}, {
  "country": "Czech Republic",
  "litres": 300
}, {
  "country": "Ireland",
  "litres": 200
}, {
  "country": "Germany",
  "litres": 150
}, {
  "country": "Australia",
  "litres": 140
}, {
  "country": "Austria",
  "litres": 120
}];

// Add and configure Series
var pieSeries = chart.series.push(new am4charts.PieSeries());
pieSeries.dataFields.value = "litres";
pieSeries.dataFields.category = "country";
pieSeries.slices.template.states.getKey("active").properties.shiftRadius = 0;
pieSeries.labels.template.disabled = true;
//pieSeries.labels.template.text = "{category}\n{value.percent.formatNumber('#.#')}%";

pieSeries.slices.template.events.on("hit", function(event) {
  selectSlice(event.target.dataItem);
})

var chart2 = container.createChild(am4charts.PieChart);
chart2.width = am4core.percent(30);
chart2.radius = am4core.percent(80);

// Add and configure Series
var pieSeries2 = chart2.series.push(new am4charts.PieSeries());
pieSeries2.dataFields.value = "value";
pieSeries2.dataFields.category = "name";
pieSeries2.slices.template.states.getKey("active").properties.shiftRadius = 0;
//pieSeries2.labels.template.radius = am4core.percent(50);
//pieSeries2.labels.template.inside = true;
//pieSeries2.labels.template.fill = am4core.color("#ffffff");
pieSeries2.labels.template.disabled = true;
pieSeries2.ticks.template.disabled = true;
pieSeries2.alignLabels = false;
pieSeries2.events.on("positionchanged", updateLines);

var interfaceColors = new am4core.InterfaceColorSet();

var chart3 = container.createChild(am4charts.PieChart);
chart3.width = am4core.percent(30);
chart3.radius = am4core.percent(80);

// Add and configure Series
var pieSeries3 = chart3.series.push(new am4charts.PieSeries());
pieSeries3.dataFields.value = "litres";
pieSeries3.dataFields.category = "country";
pieSeries3.slices.template.states.getKey("active").properties.shiftRadius = 0;
pieSeries3.labels.template.disabled = true;
//pieSeries.labels.template.text = "{category}\n{value.percent.formatNumber('#.#')}%";

pieSeries.slices.template.events.on("hit", function(event) {
  selectSlice(event.target.dataItem);
})

var line1 = container.createChild(am4core.Line);
line1.strokeDasharray = "2,2";
line1.strokeOpacity = 0.5;
line1.stroke = interfaceColors.getFor("alternativeBackground");
line1.isMeasured = false;

var line2 = container.createChild(am4core.Line);
line2.strokeDasharray = "2,2";
line2.strokeOpacity = 0.5;
line2.stroke = interfaceColors.getFor("alternativeBackground");
line2.isMeasured = false;

var selectedSlice;

function selectSlice(dataItem) {

  selectedSlice = dataItem.slice;

  var fill = selectedSlice.fill;

  var count = dataItem.dataContext.subData.length;
  pieSeries2.colors.list = [];
  for (var i = 0; i < count; i++) {
    pieSeries2.colors.list.push(fill.brighten(i * 2 / count));
  }

  chart2.data = dataItem.dataContext.subData;
  pieSeries2.appear();

  var middleAngle = selectedSlice.middleAngle;
  var firstAngle = pieSeries.slices.getIndex(0).startAngle;
  var animation = pieSeries.animate([{ property: "startAngle", to: firstAngle - middleAngle }, { property: "endAngle", to: firstAngle - middleAngle + 360 }], 600, am4core.ease.sinOut);
  animation.events.on("animationprogress", updateLines);

  selectedSlice.events.on("transformed", updateLines);

//  var animation = chart2.animate({property:"dx", from:-container.pixelWidth / 2, to:0}, 2000, am4core.ease.elasticOut)
//  animation.events.on("animationprogress", updateLines)
}


function updateLines() {
  if (selectedSlice) {
    var p11 = { x: selectedSlice.radius * am4core.math.cos(selectedSlice.startAngle), y: selectedSlice.radius * am4core.math.sin(selectedSlice.startAngle) };
    var p12 = { x: selectedSlice.radius * am4core.math.cos(selectedSlice.startAngle + selectedSlice.arc), y: selectedSlice.radius * am4core.math.sin(selectedSlice.startAngle + selectedSlice.arc) };

    p11 = am4core.utils.spritePointToSvg(p11, selectedSlice);
    p12 = am4core.utils.spritePointToSvg(p12, selectedSlice);

    var p21 = { x: 0, y: -pieSeries2.pixelRadius };
    var p22 = { x: 0, y: pieSeries2.pixelRadius };

    p21 = am4core.utils.spritePointToSvg(p21, pieSeries2);
    p22 = am4core.utils.spritePointToSvg(p22, pieSeries2);

    line1.x1 = p11.x;
    line1.x2 = p21.x;
    line1.y1 = p11.y;
    line1.y2 = p21.y;

    line2.x1 = p12.x;
    line2.x2 = p22.x;
    line2.y1 = p12.y;
    line2.y2 = p22.y;
  }
}

chart.events.on("datavalidated", function() {
  setTimeout(function() {
    selectSlice(pieSeries.dataItems.getIndex(0));
  }, 1000);
});

Your kind help is greatly appreciated.

2
try changing the piesries to pieseries2 on the 2nd instance - Arijit Mukherjee
you ned another function like selectslice for the 3rd pieseries - Arijit Mukherjee

2 Answers

0
votes

Please find this Fiddle Working Fiddle

You need to copy selectslice and updatelines functions or modify with parameters as well as you need new lines to redraw on the click of the 3rd pie on click of A of Lithuania you ca see the 3rd Pie

0
votes

sorry, a little bit late, I took your code, and I modify some things, there is an example of a 3 pie chart together based on yours.

Pie of a pie of a pie

am4core.ready(function() {


// Themes end

var container = am4core.create("pie_chart", am4core.Container);
container.width = am4core.percent(100);
container.height = am4core.percent(100);
container.layout = "horizontal";

var chart = container.createChild(am4charts.PieChart);

// Add data
chart.data = [{
  "exist": "yes",
  "number": 500,
  "subData": [{ name: "A", value: 200,"subData": 
                                      [{ name: "X", value: 20 }, 
                                       { name: "Y", value: 15 }, 
                                       { name: "Z", value: 10 }, { name: "U", value: 5 }
                                      ] 
              }, { name: "B", value: 150, "subData": 
                                      [{ name: "X", value: 20 }, 
                                       { name: "Y", value: 15 }, 
                                       { name: "Z", value: 10 }, { name: "U", value: 5 }
                                      ] }, 
              { name: "C", value: 100,"subData": 
                                      [{ name: "X", value: 20 }, 
                                       { name: "Y", value: 15 }, 
                                       { name: "Z", value: 10 }, { name: "U", value: 5 }
                                      ]  },
              
                { name: "D", value: 100,"subData": 
                                      [{ name: "X", value: 20 }, 
                                       { name: "Y", value: 15 }, 
                                       { name: "Z", value: 10 }, { name: "U", value: 5 }
                                      ]  }
             
             ]
}, {
  "exist": "No",
  "number": 300
}];

// Add and configure Series
var pieSeries = chart.series.push(new am4charts.PieSeries());
pieSeries.dataFields.value = "number";
pieSeries.dataFields.category = "exist";
pieSeries.slices.template.states.getKey("active").properties.shiftRadius = 0;

pieSeries.labels.template.disabled = false;
pieSeries.ticks.template.disabled = false;
//pieSeries.labels.template.text = "{category}\n{value.percent.formatNumber('#.#')}%";

//Override original colors

/*pieSeries.slices.template.stroke = am4core.color("#fff");
pieSeries.slices.template.strokeWidth = 1.5;
pieSeries.slices.template.strokeOpacity = 1;*/

pieSeries.slices.template.events.on("hit", function(event) {
  selectSlice(event.target.dataItem);
})

var chart2 = container.createChild(am4charts.PieChart);
chart2.width = am4core.percent(80);
chart2.radius = am4core.percent(70);

// Add and configure Series
var pieSeries2 = chart2.series.push(new am4charts.PieSeries());
pieSeries2.dataFields.value = "value";
pieSeries2.dataFields.category = "name";
pieSeries2.slices.template.states.getKey("active").properties.shiftRadius = 0;
//pieSeries2.labels.template.radius = am4core.percent(50);
//pieSeries2.labels.template.inside = true;
//pieSeries2.labels.template.fill = am4core.color("#ffffff");
pieSeries2.labels.template.disabled = false;
pieSeries2.ticks.template.disabled = false;
pieSeries2.alignLabels = false;
pieSeries2.events.on("positionchanged", updateLines);

//pieSeries2.slices.template.stroke = am4core.color("#fff");
//pieSeries2.slices.template.strokeWidth = 1.5;
//pieSeries2.slices.template.strokeOpacity = 1;



  //update
pieSeries2.slices.template.events.on("hit", function(event) {
  selectSlice2(event.target.dataItem);
})


pieSeries2.slices.template.events.on("hit", function(ev) {
  var series = ev.target.dataItem.component;
  series.slices.each(function(item) {
    if (item.isActive && item != ev.target) {
      item.isActive = false;
    }
  })
});
 
pieSeries2.events.on("positionchanged", updateLines);

var chart3 = container.createChild(am4charts.PieChart);
chart3.width = am4core.percent(70);
chart3.radius = am4core.percent(70);

// Add and configure Series
var pieSeries3 = chart3.series.push(new am4charts.PieSeries());
pieSeries3.dataFields.value = "value";
pieSeries3.dataFields.category = "name";
pieSeries3.slices.template.states.getKey("active").properties.shiftRadius = 0;
 
pieSeries3.slices.template.stroke = am4core.color("#fff");
pieSeries3.slices.template.strokeWidth = 1.5;
pieSeries3.slices.template.strokeOpacity = 1;

pieSeries3.labels.template.disabled = true;
pieSeries3.ticks.template.disabled = true;
pieSeries3.events.on("positionchanged", updateLines2);

  //endupdate
var interfaceColors = new am4core.InterfaceColorSet();

var line1 = container.createChild(am4core.Line);
line1.strokeDasharray = "2,2";
line1.strokeOpacity = 0.5;
line1.stroke = interfaceColors.getFor("alternativeBackground");
line1.isMeasured = false;

var line2 = container.createChild(am4core.Line);
line2.strokeDasharray = "2,2";
line2.strokeOpacity = 0.5;
line2.stroke = interfaceColors.getFor("alternativeBackground");
line2.isMeasured = false;

var interfaceColors2 = new am4core.InterfaceColorSet();

var line3 = container.createChild(am4core.Line);
line3.strokeDasharray = "2,2";
line3.strokeOpacity = 0.5;
line3.stroke = interfaceColors2.getFor("alternativeBackground");
line3.isMeasured = false;

var line4 = container.createChild(am4core.Line);
line4.strokeDasharray = "2,2";
line4.strokeOpacity = 0.5;
line4.stroke = interfaceColors2.getFor("alternativeBackground");
line4.isMeasured = false;

var selectedSlice;

function selectSlice(dataItem) {

  selectedSlice = dataItem.slice;

  var fill = selectedSlice.fill;

  var count = dataItem.dataContext.subData.length;
  pieSeries2.colors.list = ["#cb2542", "#f2c33a", "#63c66e"].map(function(color) {
  return new am4core.color(color);
});
  for (var i = 0; i < count; i++) {
    pieSeries2.colors.list.push(fill.brighten(i * 2 / count));
  }

  chart2.data = dataItem.dataContext.subData;
  pieSeries2.appear();

  var middleAngle = selectedSlice.middleAngle;
  var firstAngle = pieSeries.slices.getIndex(0).startAngle;
  var animation = pieSeries.animate([{ property: "startAngle", to: firstAngle - middleAngle }, { property: "endAngle", to: firstAngle - middleAngle + 360 }], 600, am4core.ease.sinOut);
  animation.events.on("animationprogress", updateLines);

  selectedSlice.events.on("transformed", updateLines);
  
  
//  var animation = chart2.animate({property:"dx", from:-container.pixelWidth / 2, to:0}, 2000, am4core.ease.elasticOut)
//  animation.events.on("animationprogress", updateLines)
}

//update
  
var selectedSlice2;

function selectSlice2(dataItem) {

  selectedSlice2 = dataItem.slice;

  var fill = selectedSlice2.fill;

  var count = dataItem.dataContext.subData.length;
  pieSeries3.colors.list = [];
  for (var i = 0; i < count; i++) {
    pieSeries3.colors.list.push(fill.brighten(i * 2.5 / count));
  }

  chart3.data = dataItem.dataContext.subData;
  pieSeries3.appear();

  var middleAngle2 = selectedSlice2.middleAngle + 10;
  var firstAngle2 = pieSeries2.slices.getIndex(0).startAngle + 10;
  var animation2 = pieSeries2.animate([{ property: "startAngle", to: firstAngle2 - middleAngle2 }, { property: "endAngle", to: firstAngle2 - middleAngle2 + 360 }], 600, am4core.ease.sinOut);
  animation2.events.on("animationprogress", updateLines2);

  selectedSlice2.events.on("transformed", updateLines2);
}

function updateLines2() {
  if (selectedSlice2) {
    var p11 = { x: selectedSlice2.radius * am4core.math.cos(selectedSlice2.startAngle), y: selectedSlice2.radius * am4core.math.sin(selectedSlice2.startAngle) };
    var p12 = { x: selectedSlice2.radius * am4core.math.cos(selectedSlice2.startAngle + selectedSlice2.arc), y: selectedSlice2.radius * am4core.math.sin(selectedSlice2.startAngle + selectedSlice2.arc) };

    p11 = am4core.utils.spritePointToSvg(p11, selectedSlice2);
    p12 = am4core.utils.spritePointToSvg(p12, selectedSlice2);

    var p21 = { x: 0, y: -pieSeries3.pixelRadius };
    var p22 = { x: 0, y: pieSeries3.pixelRadius };

    p21 = am4core.utils.spritePointToSvg(p21, pieSeries3);
    p22 = am4core.utils.spritePointToSvg(p22, pieSeries3);

    line3.x1 = p11.x;
    line3.x2 = p21.x;
    line3.y1 = p11.y;
    line3.y2 = p21.y;

    line4.x1 = p12.x;
    line4.x2 = p22.x;
    line4.y1 = p12.y;
    line4.y2 = p22.y;
  }
}
  //endupdate



function updateLines() {
  if (selectedSlice) {
    var p11 = { x: selectedSlice.radius * am4core.math.cos(selectedSlice.startAngle), y: selectedSlice.radius * am4core.math.sin(selectedSlice.startAngle) };
    var p12 = { x: selectedSlice.radius * am4core.math.cos(selectedSlice.startAngle + selectedSlice.arc), y: selectedSlice.radius * am4core.math.sin(selectedSlice.startAngle + selectedSlice.arc) };

    p11 = am4core.utils.spritePointToSvg(p11, selectedSlice);
    p12 = am4core.utils.spritePointToSvg(p12, selectedSlice);

    var p21 = { x: 0, y: -pieSeries2.pixelRadius };
    var p22 = { x: 0, y: pieSeries2.pixelRadius };

    p21 = am4core.utils.spritePointToSvg(p21, pieSeries2);
    p22 = am4core.utils.spritePointToSvg(p22, pieSeries2);

    line1.x1 = p11.x;
    line1.x2 = p21.x;
    line1.y1 = p11.y;
    line1.y2 = p21.y;

    line2.x1 = p12.x;
    line2.x2 = p22.x;
    line2.y1 = p12.y;
    line2.y2 = p22.y;
  }
}

chart.events.on("datavalidated", function() {
//$("#jsonData").html( "pieSeries.dataItems.getIndex(0)");
  //alert("msg " + JSON.stringify(pieSeries.dataItems.getIndex(0)));
  setTimeout(function() {
    selectSlice(pieSeries.dataItems.getIndex(0));
  }, 1000);
     
});


}); // end am4core.ready
body {
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
}

#chartdiv {
  width: 100%;
  height: 500px;
}
<script src="https://www.amcharts.com/lib/4/core.js"></script>
<script src="https://www.amcharts.com/lib/4/charts.js"></script>
<script src="https://www.amcharts.com/lib/4/themes/dataviz.js"></script>
<script src="https://www.amcharts.com/lib/4/themes/animated.js"></script>
<div id="pie_chart"></div>