(amCharts) The chart gets its data from a HTML table. How to update the legend if a new table row is dynamically added?

旧街凉风 提交于 2019-12-12 04:36:33

问题


I have a HTML table that serves as the data provider for the chart. The table can be dynamically edited with a click of the button (I can add a new row to it).

I can update the chart each time a new row is added. However the legend remains the same, it only has three initial graphs. How can I update the legend alongside the chart?

Here is my fiddle: https://jsfiddle.net/yvzj8acd/2/

And here is the JS where I add new row to the table:

          //////////////////////////////////
          // This is where I update the chart
          //////////////////////////////////

          $(document).ready(function() {

          var newtr = "<tr class='row1a'><th>Row 4</th><td>10000</td><td>20000</td><td>5000</td><td>15000</td><td>7500</td><td>10000</td></tr>"
          var newtr2 = "<tr class='row1a'><th>Row 5</th><td>15000</td><td>30000</td><td>2000</td><td>10000</td><td>15500</td><td>7000</td></tr>"
          var newtr3 = "<tr class='row1a'><th>Row 6</th><td>1000</td><td>25000</td><td>15000</td><td>7000</td><td>10000</td><td>8000</td></tr>"

              $(".ganti").click(function(e) {
                $('#dataTable').append(newtr, newtr2, newtr3);

                generateChartData();
                chart.dataProvider = chartData;
                chart.validateData();
                chart.animateAgain();

                e.preventDefault();
              });
          });

回答1:


Quick FYI, AmCharts.ready is equivalent to $(document).ready, so you can easily combine the two.

As for your question, you need to tweak your data and chart generation approach so that it can handle the dynamically added data. Right now, your setup is pretty much hard-coded to the first three rows and the new data is never added. You also need to update the chart and add additional graphs as needed when new rows are added.

The first thing I did was update your generate data method to dynamically pull all rows that contain data, rather than the current hardcoded method that grabs the first three rows:

function generateChartData() {

  // initialize empty array
  chartData = [];

  // get the table
  var table = document.getElementById('dataTable');

  var years = table.rows[0].getElementsByTagName('th');

    //get the rows with graph values. Since data rows always 
  //have a class that begin with "row", use that as the query selector
  var rows = document.querySelectorAll("tr[class^='row']");

  var row;

  // iterate through the <td> elements of the first row
  // and construct chart data out of other rows as well
  for (var x = 0; x < years.length; x++) {
    //set up the initial object containing the year
    var dataElem = {
      "year": years[x].textContent
    };
    //iterate through the other rows based on the current year column (x + 1) and add that value to the
    //object
    for (row = 0; row < rows.length; row++) {
      dataElem[rows[row].cells[0].textContent] = rows[row].cells[x + 1].textContent
    }
    //append final object to chart data array
    chartData.push(dataElem);
  }
}

Next, I created a generateGraphsFromData method that takes the chart instance and chartData array. This method compares the valueFields found in the first element of the chartData array and the valueFields in the chart's graphs array and creates new graphs where there aren't any in the array. This works for both chart creation and update:

//update the chart's graphs array based on the the currently known valueFields
function generateGraphsFromData(chart, chartData) {
  //get the chart graph value fields
  var graphValueFields = chart.graphs.map(function(graph) {
    return graph.valueField;
  });
  //create an array of new graph value fields by filtering out the categoryField
  //and the currently known valueFields. 
  var newGraphValueFields = Object.keys(chartData[0]).filter(function(key) {
    return key != chart.categoryField;
  }).filter(function(valueField) {
    return graphValueFields.indexOf(valueField) === -1;
  });

  //for each new value field left over, create a graph object and add to the chart.
  newGraphValueFields.forEach(function(valueField) {
    var graph = new AmCharts.AmGraph();
    graph.title = valueField;
    graph.valueField = valueField;
    graph.balloonText = "Rp[[value]]";
    graph.lineAlpha = 1;
    graph.bullet = "round";
    graph.stackable = false; // disable stacking
    chart.addGraph(graph);
  });
}

From there I just updated your ready method to call this function instead of setting the graphs manually, along with forcing the first two to be hidden:

  // Create graphs
  generateGraphsFromData(chart, chartData);

  //default the other two graphs to hidden
  chart.graphs[1].hidden = true;
  chart.graphs[2].hidden = true;

Then I modified your click event to call the generateGraphs method as well:

  $(".ganti").click(function(e) {
    $('#dataTable').append(newtr, newtr2, newtr3);

    generateChartData();
    generateGraphsFromData(chart, chartData);
    // ...

Updated fiddle. I also moved the AmCharts.ready method into a separate standalone function and called it into $(document).ready, since both are identical anyway. Feel free to tweak the logic if you want to default other new graphs to hidden or whatever.



来源:https://stackoverflow.com/questions/46787202/amcharts-the-chart-gets-its-data-from-a-html-table-how-to-update-the-legend-i

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!