How to insert points on top of bar charts using Google Charts?

落花浮王杯 提交于 2020-06-28 05:25:53

问题


Given the illustration

I was able to create the chart (without the points) using the following code:

<html>
  <head>
      <script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
    <script type="text/javascript">
      google.charts.load('current', {'packages':['bar']});
      google.charts.setOnLoadCallback(drawStuff);

      var chart;

      function drawStuff() {
        var data = new google.visualization.arrayToDataTable([
          ['Y', 'Series 1','Series 2'],
          ["Element A", 44,11],
          ["Element B", 31,11],
          ["Element C", 12,11],
        ]);

        var options = {
          bars: 'horizontal', // Required for Material Bar Charts.
          axes: {
            x: {
              0: { side: 'bottom', label: 'X'} // Top x-axis.
            }
          }
        };

        var div = document.getElementById('top_x_div');
        var link = document.getElementById('url');
        chart = new google.charts.Bar(div);
        chart.draw(data, options);
        //console.log(chart.getImageURI());
      };
    </script>
  </head>
  <body>
    <div id="top_x_div" style="width: 900px; height: 500px;"></div>
  </body>
</html>

How to insert points on top of bar charts using Google Charts?


回答1:


there were a couple ways I thought of, to accomplish...

  1. Use a Combo chart
  2. Add the points manually, on the chart's 'ready' event

however, neither option can be achieved using a material chart.

google.charts.Bar

first, material charts do not support Combo charts.
and, material charts do not have the methods necessary to add the points manually.

not to mention, there are also several options that material charts do not support.
see --> Tracking Issue for Material Chart Feature Parity #2143

so we must use a classic chart...

google.visualization.BarChart

there is an option we can use to give the classic chart a similar look and feel as material charts...

theme: 'material'

now the solution...

when attempting to use a Combo chart,
the points align to the y-axis, in between the two bars.
there is not an option that will allow the points to align on the bars.
so we must add the points manually, on the chart's 'ready' event...

there are few chart methods we need...

getChartLayoutInterface() - Returns an object containing information about the onscreen placement of the chart and its elements.

getBoundingBox(id) - Returns an object containing the left, top, width, and height of chart element id.

getXLocation(position, optional_axis_index) - Returns the screen x-coordinate of position relative to the chart's container.

once the chart's 'ready' event fires, we can get the layout interface using --> getChartLayoutInterface()

the other two methods mentioned above are methods of the layout interface.

we use getBoundingBox(id) to get the coordinates of the bar, on which the point will be placed.
this will give us the Y coordinate, and the height of the point.
the id of the bar is determined by the data row and series column.

bar#C#R  // where C is the series column index, and R is the row index

we are providing the X coordinate,
getXLocation will provide the location on the chart, needed to place the point on the x-axis, at our predetermined location.

// x coordinates of points to add
var points = [
  [36, 8],
  [28, 8],
  [10, 8],
];

// loop data rows and columns
for (var r = 0; r < data.getNumberOfRows(); r++) {
  for (var c = 1; c < data.getNumberOfColumns(); c++) {
    // calculate position of the point
    var barBounds = chartLayout.getBoundingBox('bar#' + (c - 1) + '#' + r);
    var xCoord = chartLayout.getXLocation(points[r][c - 1]);
    var height = barBounds.height / 4;
    var top = barBounds.top + (height * 2);

    // create and add the point to the chart
    var point = document.createElementNS(svgNS, 'circle');
    point.setAttribute('cx', xCoord);
    point.setAttribute('cy', top);
    point.setAttribute('r', height);
    point.setAttribute('stroke', '#ffffff');
    point.setAttribute('stroke-width', height);
    point.setAttribute('fill', 'transparent');
    svg.appendChild(point);
  }
}

see following working snippet...

var chart;

google.charts.load('current', {
  packages: ['corechart']
}).then(function drawStuff() {
  var data = new google.visualization.arrayToDataTable([
    ['Y', 'Series 1', 'Series 2'],
    ['Element A', 44, 11],
    ['Element B', 31, 11],
    ['Element C', 12, 11],
  ]);

  // x coordinates of points to add
  var points = [
    [36, 8],
    [28, 8],
    [10, 8],
  ];

  var options = {
    chartArea: {
      left: 128,
      top: 24,
      right: 128,
      bottom: 72,
      height: '100%',
      width: '100%'
    },
    hAxis: {
      title: 'X'
    },
    height: '100%',
    theme: 'material',
    vAxis: {
      title: data.getColumnLabel(0)
    },
    width: '100%'
  };

  var div = document.getElementById('top_x_div');
  //var link = document.getElementById('url');

  chart = new google.visualization.BarChart(div);

  google.visualization.events.addListener(chart, 'ready', function () {
    // get chart layour interface and svg
    var chartLayout = chart.getChartLayoutInterface();
    var svg = div.getElementsByTagName('svg')[0];
    var svgNS = svg.namespaceURI;

    // loop data rows and columns
    for (var r = 0; r < data.getNumberOfRows(); r++) {
      for (var c = 1; c < data.getNumberOfColumns(); c++) {
        // calculate position of the point
        var barBounds = chartLayout.getBoundingBox('bar#' + (c - 1) + '#' + r);
        var xCoord = chartLayout.getXLocation(points[r][c - 1]);
        var height = barBounds.height / 4;
        var top = barBounds.top + (height * 2);

        // create and add the point to the chart
        var point = document.createElementNS(svgNS, 'circle');
        point.setAttribute('cx', xCoord);
        point.setAttribute('cy', top);
        point.setAttribute('r', height);
        point.setAttribute('stroke', '#ffffff');
        point.setAttribute('stroke-width', height);
        point.setAttribute('fill', 'transparent');
        svg.appendChild(point);
      }
    }
  });

  chart.draw(data, options);
  window.addEventListener('resize', function () {
    chart.draw(data, options);
  });
});
#top_x_div {
  height: 400px;
}
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="top_x_div"></div>


来源:https://stackoverflow.com/questions/61627353/how-to-insert-points-on-top-of-bar-charts-using-google-charts

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