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>
仍在尝试使用外部数据源来掌握 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>