Adding annotations to Google candlestick chart (Posted solution triggers TypeError)

别来无恙 提交于 2020-06-27 16:29:49

问题


I am trying to add some annotations to a Google Candlestick chart. I noticed someone had already asked this same question (Adding annotations to Google Candlestick chart). The user Aperçu replied with a detailed solution to extend the chart and add annotations since the chart doesn't have any such feature built in. However, when I try this solution I get an error "TypeError: document.querySelectorAll(...)[0] is undefined"

Here is my code:

        chartPoints = [
            ['Budget', 0, 0, 9999, 9999, 'foo1'],
            ['Sales', 0, 0, 123, 123, 'foo2'],
            ['Backlog', 123, 123, 456, 456, 'foo3'],
            ['Hard Forecast', 456, 456, 789, 789, 'foo4'],
            ['Sales to Budget', 789, 789, 1000, 1000, 'foo5']
        ];
        var data = google.visualization.arrayToDataTable(chartPoints, true);
        data.setColumnProperty(5, 'role', 'annotation');
        var options = {
            legend: 'none',
            bar: { groupWidth: '40%', width: '100%' },
            candlestick: {
                fallingColor: { strokeWidth: 0, fill: '#a52714' },
                risingColor: { strokeWidth: 0, fill: '#0f9d58' }
            }
        };    

        var chart = new google.visualization.CandlestickChart(document.getElementById('chart_div'));
        chart.draw(data, options);

        // attempt to use Aperçu's solution
        const bars = document.querySelectorAll('#chart_div svg > g:nth-child(5) > g')[0].lastChild.children // this triggers a TypeError
        for (var i = 0 ; i < bars.length ; i++) {
          const bar = bars[i]
          const { top, left, width } = bar.getBoundingClientRect()
          const hint = document.createElement('div')
          hint.style.top = top + 'px'
          hint.style.left = left + width + 5 + 'px'
          hint.classList.add('hint')
          hint.innerText = rawData.filter(t => t[1])[i][0]
          document.getElementById('chart_div').append(hint)
        }

I want the chart to show the last piece of data next to the bars (i.e. "foo1", "foo2", etc)


回答1:


each candle or bar will be represented by a <rect> element

we can use the rise and fall colors to separate the bars from other <rect> elements in the chart

there will be the same number of bars as rows in the data table

once we find the first bar, we can use rowIndex of zero to pull values from the data

we need to find the value of the rise / fall, to know where to place the annotation

then use chart methods to find the location for the annotation

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

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

see following working snippet
two annotations are added
one for the difference in rise and fall
and the other for the value in the column with annotation role

google.charts.load('current', {
  callback: drawChart,
  packages: ['corechart']
});

function drawChart() {
  var chartPoints = [
    ['Budget', 0, 0, 9999, 9999, 'foo1'],
    ['Sales', 0, 0, 123, 123, 'foo2'],
    ['Backlog', 123, 123, 456, 456, 'foo3'],
    ['Hard Forecast', 456, 456, 789, 789, 'foo4'],
    ['Sales to Budget', 789, 789, 1000, 1000, 'foo5']
  ];
  var data = google.visualization.arrayToDataTable(chartPoints, true);
  data.setColumnProperty(5, 'role', 'annotation');
  var options = {
    legend: 'none',
    bar: { groupWidth: '40%', width: '100%' },
    candlestick: {
      fallingColor: { strokeWidth: 0, fill: '#a52714' },
      risingColor: { strokeWidth: 0, fill: '#0f9d58' }
    }
  };

  var container = document.getElementById('chart_div');
  var chart = new google.visualization.CandlestickChart(container);

  google.visualization.events.addListener(chart, 'ready', function () {
    var annotation;
    var bars;
    var chartLayout;
    var formatNumber;
    var positionY;
    var positionX;
    var rowBalance;
    var rowBottom;
    var rowIndex;
    var rowTop;
    var rowValue;
    var rowWidth;

    chartLayout = chart.getChartLayoutInterface();
    rowIndex = 0;
    formatNumber = new google.visualization.NumberFormat({
      pattern: '#,##0'
    });

    bars = container.getElementsByTagName('rect');
    for (var i = 0; i < bars.length; i++) {
      switch (bars[i].getAttribute('fill')) {
        case '#a52714':
        case '#0f9d58':
          rowWidth = parseFloat(bars[i].getAttribute('width'));
          if (rowWidth > 2) {
            rowBottom = data.getValue(rowIndex, 1);
            rowTop = data.getValue(rowIndex, 3);
            rowValue = rowTop - rowBottom;
            rowBalance = Math.max(rowBottom, rowTop);
            positionY = chartLayout.getYLocation(rowBalance) - 6;
            positionX = parseFloat(bars[i].getAttribute('x'));

            // row value
            annotation = container.getElementsByTagName('svg')[0].appendChild(container.getElementsByTagName('text')[0].cloneNode(true));
            annotation.textContent = formatNumber.formatValue(rowValue);
            annotation.setAttribute('x', (positionX + (rowWidth / 2)));
            annotation.setAttribute('y', positionY);
            annotation.setAttribute('font-weight', 'bold');

            // annotation column
            annotation = container.getElementsByTagName('svg')[0].appendChild(container.getElementsByTagName('text')[0].cloneNode(true));
            annotation.textContent = data.getValue(rowIndex, 5);
            annotation.setAttribute('x', (positionX + (rowWidth / 2)));
            annotation.setAttribute('y', positionY - 18);
            annotation.setAttribute('font-weight', 'bold');

            rowIndex++;
          }
          break;
      }
    }
  });

  chart.draw(data, options);
}
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="chart_div"></div>


来源:https://stackoverflow.com/questions/46064803/adding-annotations-to-google-candlestick-chart-posted-solution-triggers-typeerr

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