amCharts 4:外部数据源 - JSON 来自数据库的输出

amCharts 4: External Data Source - JSON Output from Database

仍在尝试使用外部数据源来掌握 amCharts 4,这是我之前问题的后续...

我使用静态数据创建了一个水平堆叠图表,效果很好(下面的代码片段)。

然而,当在同一图表上使用外部数据源时,我没有得到相同的结果,因为 JSON 输出不同。

这是因为外部数据库 table 列和行是相反的(从静态数据),不幸的是无法在源代码中更改。

我浏览了 amCharts 文档和演示图表,并尝试了各种方法来实现与静态数据版本相同的图表,但没有成功。

例如尝试了 inversed opposite rotate 属性,以及重新配置图表系列和轴。

也许,parseended事件可以用来重新映射外部数据,但老实说我不知道​​怎么做。

我已经走到了死胡同,不知道怎么做,或者什么是正确的(或最佳实践)方法?

每个图表的代码(和数据结构)如下所示。

非常感谢任何帮助。提前致谢。


静态数据图表(正确)

// Create chart instance
var chart = am4core.create("chartdiv", am4charts.XYChart);

// Add data
var chartdata = [{
  "Name": "Question 1 Shows Here",
  "Yes Please": 75,
  "Maybe": 45,
  "No Thanks": 19
}, {
  "Name": "Question 2 Shows Here",
  "Yes Please": 35,
  "Maybe": 43,
  "No Thanks": 26
}, {
  "Name": "Question 3 Shows Here",
  "Yes Please": 57,
  "Maybe": 24,
  "No Thanks": 8
}];

chart.data = chartdata;

// Create axes
var categoryAxis = chart.yAxes.push(new am4charts.CategoryAxis());
categoryAxis.dataFields.category = "Name";
categoryAxis.renderer.grid.template.location = 0;
categoryAxis.renderer.minGridDistance = 20;

var valueAxis = chart.xAxes.push(new am4charts.ValueAxis());
valueAxis.numberFormatter.numberFormat = "#";
valueAxis.min = 0;
valueAxis.transitionDuration = 200;
valueAxis.interpolationDuration = 200;
valueAxis.rangeChangeDuration = 200;

// Create series
var series = chart.series.push(new am4charts.ColumnSeries());
series.dataFields.valueX = "Yes Please";
series.dataFields.categoryY = "Name";
series.name = "Yes Please";
series.tooltipText = "{name}: [bold]{valueX}[/]";
series.stacked = true;

var series2 = chart.series.push(new am4charts.ColumnSeries());
series2.dataFields.valueX = "Maybe";
series2.dataFields.categoryY = "Name";
series2.name = "Maybe";
series2.tooltipText = "{name}: [bold]{valueX}[/]";
series2.stacked = true;

var series3 = chart.series.push(new am4charts.ColumnSeries());
series3.dataFields.valueX = "Don’t Know";
series3.dataFields.categoryY = "Name";
series3.name = "Don’t Know";
series3.tooltipText = "{name}: [bold]{valueX}[/]";
series3.stacked = true;

var series4 = chart.series.push(new am4charts.ColumnSeries());
series4.dataFields.valueX = "No Thanks";
series4.dataFields.categoryY = "Name";
series4.name = "No Thanks";
series4.tooltipText = "{name}: [bold]{valueX}[/]";
series4.stacked = true;

// Add cursor
chart.cursor = new am4charts.XYCursor();
chart.cursor.behavior = "zoomXY";

// Add legend
chart.legend = new am4charts.Legend();
chart.legend.position = "bottom";
<script src="//www.amcharts.com/lib/4/core.js"></script>
<script src="//www.amcharts.com/lib/4/charts.js"></script>
<div id="chartdiv" style="width: 90%; height: 300px";></div>

外部数据图表(不正确)

// Create chart instance
var chart = am4core.create("chartdiv", am4charts.XYChart);

// Add data
var chartdata = [{
  "Name": "Yes Please",
  "Question 1 Shows Here": 75,
  "Question 2 Shows Here": 45,
  "Question 3 Shows Here": 19
}, {
  "Name": "Maybe",
  "Branding and Logos Score": 367,
  "Question 1 Shows Here": 35,
  "Question 2 Shows Here": 43,
  "Question 3 Shows Here": 26
}, {
  "Name": "Don’t Know",
  "Question 1 Shows Here": 42,
  "Question 2 Shows Here": 31,
  "Question 3 Shows Here": 12
}, {
  "Name": "No Thanks",
  "Question 1 Shows Here": 17,
  "Question 2 Shows Here": 27,
  "Question 3 Shows Here": 15
}];

chart.data = chartdata;

// Create category axes
var categoryAxis = chart.yAxes.push(new am4charts.CategoryAxis());
categoryAxis.dataFields.category = "Name";
categoryAxis.renderer.grid.template.location = 0;
categoryAxis.renderer.minGridDistance = 20;

// Create value axes
var valueAxis = chart.xAxes.push(new am4charts.ValueAxis());
valueAxis.numberFormatter.numberFormat = "#";
valueAxis.min = 0;
valueAxis.transitionDuration = 200;
valueAxis.interpolationDuration = 200;
valueAxis.rangeChangeDuration = 200;

// Create series
var series = chart.series.push(new am4charts.ColumnSeries());
series.dataFields.valueX = "Question 1 Shows Here";
series.dataFields.categoryY = "Name";
series.name = "Question 1 Shows Here";
series.tooltipText = "{name}: [bold]{valueX}[/]";
series.stacked = true;

var series2 = chart.series.push(new am4charts.ColumnSeries());
series2.dataFields.valueX = "Question 2 Shows Here";
series2.dataFields.categoryY = "Name";
series2.name = "Question 2 Shows Here";
series2.tooltipText = "{name}: [bold]{valueX}[/]";
series2.stacked = true;

var series3 = chart.series.push(new am4charts.ColumnSeries());
series3.dataFields.valueX = "Question 3 Shows Here";
series3.dataFields.categoryY = "Name";
series3.name = "Question 3 Shows Here";
series3.tooltipText = "{name}: [bold]{valueX}[/]";
series3.stacked = true;

// Add cursor
chart.cursor = new am4charts.XYCursor();
chart.cursor.behavior = "zoomXY";

chart.legend = new am4charts.Legend();
chart.legend.position = "bottom";
<script src="//www.amcharts.com/lib/4/core.js"></script>
<script src="//www.amcharts.com/lib/4/charts.js"></script>
<div id="chartdiv" style="width: 90%; height: 300px";></div>

parseended 是在这种情况下要走的路。您需要为您的问题设置查找 table,并将它们映射到包含映射到每个响应的值的对象,例如:

chart.dataSource.events.on("parseended", function(ev) {
  var questionMap = {}; //lookup table to map questions to data elements

  ev.target.data.forEach(function(item) {
    Object.keys(item).forEach(function(key) {
        if (key.indexOf('Name') == -1) { //act on non-response keys
            if (!questionMap[key]) {
                questionMap[key] = {"Name": key}; //create an object containing the name/question pair if it doesn't exist
            }
            questionMap[key][item.Name] = item[key]; // assign response+value to the object (e.g. "Yes, Please": 75)
        }
    });
  });
  //remap lookup table as array
  ev.target.data = Object.keys(questionMap).map(function(question) {
    return questionMap[question];
  });
}); 

下面的演示:

// Create chart instance
var chart = am4core.create("chartdiv", am4charts.XYChart);

chart.dataSource.url = dataURI(); //fake URL for demonstration purposes
chart.dataSource.events.on("parseended", function(ev) {
  var questionMap = {}; //lookup table to map questions to data elements

  ev.target.data.forEach(function(item) {
    Object.keys(item).forEach(function(key) {
      if (key.indexOf('Name') == -1) { //act on non-response keys
        if (!questionMap[key]) {
          questionMap[key] = {
            "Name": key
          }; //create an object containing the name/question pair if it doesn't exist
        }
        questionMap[key][item.Name] = item[key]; // assign response+value to the object (e.g. "Yes, Please": 75)
      }
    });
  });
  //remap lookup table as array
  ev.target.data = Object.keys(questionMap).map(function(question) {
    return questionMap[question];
  });
});
// Create axes
var categoryAxis = chart.yAxes.push(new am4charts.CategoryAxis());
categoryAxis.dataFields.category = "Name";
categoryAxis.renderer.grid.template.location = 0;
categoryAxis.renderer.minGridDistance = 20;

var valueAxis = chart.xAxes.push(new am4charts.ValueAxis());
valueAxis.numberFormatter.numberFormat = "#";
valueAxis.min = 0;
valueAxis.transitionDuration = 200;
valueAxis.interpolationDuration = 200;
valueAxis.rangeChangeDuration = 200;

// Create series
var series = chart.series.push(new am4charts.ColumnSeries());
series.dataFields.valueX = "Yes Please";
series.dataFields.categoryY = "Name";
series.name = "Yes Please";
series.tooltipText = "{name}: [bold]{valueX}[/]";
series.stacked = true;

var series2 = chart.series.push(new am4charts.ColumnSeries());
series2.dataFields.valueX = "Maybe";
series2.dataFields.categoryY = "Name";
series2.name = "Maybe";
series2.tooltipText = "{name}: [bold]{valueX}[/]";
series2.stacked = true;

var series3 = chart.series.push(new am4charts.ColumnSeries());
series3.dataFields.valueX = "Don’t Know";
series3.dataFields.categoryY = "Name";
series3.name = "Don’t Know";
series3.tooltipText = "{name}: [bold]{valueX}[/]";
series3.stacked = true;

var series4 = chart.series.push(new am4charts.ColumnSeries());
series4.dataFields.valueX = "No Thanks";
series4.dataFields.categoryY = "Name";
series4.name = "No Thanks";
series4.tooltipText = "{name}: [bold]{valueX}[/]";
series4.stacked = true;

// Add cursor
chart.cursor = new am4charts.XYCursor();
chart.cursor.behavior = "zoomXY";

// Add legend
chart.legend = new am4charts.Legend();
chart.legend.position = "bottom";

function dataURI() {
  return "data:application/json;base64,W3sKICAiTmFtZSI6ICJZZXMgUGxlYXNlIiwKICAiUXVlc3Rpb24gMSBTaG93cyBIZXJlIjogNzUsCiAgIlF1ZXN0aW9uIDIgU2hvd3MgSGVyZSI6IDQ1LAogICJRdWVzdGlvbiAzIFNob3dzIEhlcmUiOiAxOQp9LCB7CiAgIk5hbWUiOiAiTWF5YmUiLAogICJCcmFuZGluZyBhbmQgTG9nb3MgU2NvcmUiOiAzNjcsCiAgIlF1ZXN0aW9uIDEgU2hvd3MgSGVyZSI6IDM1LAogICJRdWVzdGlvbiAyIFNob3dzIEhlcmUiOiA0MywKICAiUXVlc3Rpb24gMyBTaG93cyBIZXJlIjogMjYKfSwgewogICJOYW1lIjogIkRvbuKAmXQgS25vdyIsCiAgIlF1ZXN0aW9uIDEgU2hvd3MgSGVyZSI6IDQyLAogICJRdWVzdGlvbiAyIFNob3dzIEhlcmUiOiAzMSwKICAiUXVlc3Rpb24gMyBTaG93cyBIZXJlIjogMTIKfSwgewogICJOYW1lIjogIk5vIFRoYW5rcyIsCiAgIlF1ZXN0aW9uIDEgU2hvd3MgSGVyZSI6IDE3LAogICJRdWVzdGlvbiAyIFNob3dzIEhlcmUiOiAyNywKICAiUXVlc3Rpb24gMyBTaG93cyBIZXJlIjogMTUKfV0=";
}
<script src="//www.amcharts.com/lib/4/core.js"></script>
<script src="//www.amcharts.com/lib/4/charts.js"></script>
<div id="chartdiv" style="width: 90%; height: 300px" ;></div>