Google Charts Add Layer On Top Of Timeline

时光毁灭记忆、已成空白 提交于 2021-02-11 15:44:00

问题


I am looking to plot on a timeline a series of events with a start and end date. It seems like the google chart library offers that specific functionality through the Timeline chart type.

I also need to plot single, punctual events (not only events that happen over a begin/end timespan) and represent them with symbols like circles, triangles or other.

I was wondering if it is possible to add another layer on top of the timeline to do that? Or perhaps to add custom shapes to represent events that have matching being/end dates?

Any insight would be great!


回答1:


there are no standard options you can use to add another layer / custom shapes.

but the chart's svg can be modified manually, once the chart's 'ready' event fires.

see following working snippet,
function addMarkers will add custom shapes for a given date and row.

pass an array of "events" to be added to the chart.

addMarkers([
  {row: 0, date: new Date(currentYear, 1, 11), name: 'Event A', type: 'triangle', color: 'yellow'},
  {row: 2, date: new Date(currentYear, 10, 15), name: 'Event B', type: 'circle', color: 'lime'}
]);

google.charts.load('current', {
  packages:['timeline']
}).then(function () {
  var container = document.getElementById('timeline');
  var chart = new google.visualization.Timeline(container);
  var dataTable = new google.visualization.DataTable();
  dataTable.addColumn({type: 'string', id: 'Row'});
  dataTable.addColumn({type: 'string', id: 'Bar'});
  dataTable.addColumn({type: 'date', id: 'Start'});
  dataTable.addColumn({type: 'date', id: 'End'});
  var currentYear = (new Date()).getFullYear();
  dataTable.addRows([
    ['Row 1', 'A-1', new Date(currentYear, 0, 1), new Date(currentYear, 2, 31)],
    ['Row 1', 'A-2', new Date(currentYear, 3, 1), new Date(currentYear, 5, 30)],
    ['Row 2', 'B-1', new Date(currentYear, 6, 1), new Date(currentYear, 8, 31)],
    ['Row 2', 'B-2', new Date(currentYear, 9, 1), new Date(currentYear, 11, 31)]
  ]);
  var dataTableGroup = google.visualization.data.group(dataTable, [0]);
  var dateRangeStart = dataTable.getColumnRange(2);
  var dateRangeEnd = dataTable.getColumnRange(3);
  var rowHeight = 44;
  var options = {
    height: (dataTableGroup.getNumberOfRows() * rowHeight) + rowHeight
  };

  function drawChart() {
    chart.draw(dataTable, options);
  }

  // add custom marker
  function addMarkers(events) {
    var baseline;
    var baselineBounds;
    var chartElements;
    var labelFound;
    var labelText;
    var marker;
    var markerLabel;
    var markerSpan;
    var rowLabel;
    var svg;
    var svgNS;
    var timeline;
    var timelineUnit;
    var timelineWidth;
    var timespan;
    var xCoord;
    var yCoord;

    // initialize chart elements
    baseline = null;
    svg = null;
    svgNS = null;
    timeline = null;
    chartElements = container.getElementsByTagName('svg');
    if (chartElements.length > 0) {
      svg = chartElements[0];
      svgNS = svg.namespaceURI;
    }
    chartElements = container.getElementsByTagName('rect');
    if (chartElements.length > 0) {
      timeline = chartElements[0];
    }
    chartElements = container.getElementsByTagName('path');
    if (chartElements.length > 0) {
      baseline = chartElements[0];
    }
    if ((svg === null) || (timeline === null) || (baseline === null)) {
      return;
    }
    timelineWidth = parseFloat(timeline.getAttribute('width'));
    baselineBounds = baseline.getBBox();
    timespan = dateRangeEnd.max.getTime() - dateRangeStart.min.getTime();
    timelineUnit = (timelineWidth - baselineBounds.x) / timespan;

    // add events
    events.forEach(function (event) {
      // find row label
      rowLabel = dataTable.getValue(event.row, 0);
      chartElements = container.getElementsByTagName('text');
      if (chartElements.length > 0) {
        Array.prototype.forEach.call(chartElements, function(label) {
          if (label.textContent.indexOf('…') > -1) {
            labelText = label.textContent.replace('…', '');
          } else {
            labelText = label.textContent;
          }
          if (rowLabel.indexOf(labelText) > -1) {
            markerLabel = label.cloneNode(true);
          }
        });
      }

      // calculate placement
      markerSpan = event.date.getTime() - dateRangeStart.min.getTime();

      // add label
      markerLabel.setAttribute('text-anchor', 'start');
      markerLabel.setAttribute('fill', event.color);
      markerLabel.setAttribute('x', (baselineBounds.x + (timelineUnit * markerSpan) + 6));
      markerLabel.textContent = event.name;
      svg.appendChild(markerLabel);

      // add marker
      xCoord = (baselineBounds.x + (timelineUnit * markerSpan) - 4);
      yCoord = parseFloat(markerLabel.getAttribute('y'));
      switch (event.type) {
        case 'triangle':
          marker = document.createElementNS(svgNS, 'polygon');
          marker.setAttribute('fill', 'transparent');
          marker.setAttribute('stroke', event.color);
          marker.setAttribute('stroke-width', '3');
          marker.setAttribute('points', xCoord + ',' + (yCoord - 10) + ' ' + (xCoord - 5) + ',' + yCoord + ' ' + (xCoord + 5) + ',' + yCoord);
          svg.appendChild(marker);
          break;

        case 'circle':
          marker = document.createElementNS(svgNS, 'circle');
          marker.setAttribute('cx', xCoord);
          marker.setAttribute('cy', yCoord - 5);
          marker.setAttribute('r', '6');
          marker.setAttribute('stroke', event.color);
          marker.setAttribute('stroke-width', '3');
          marker.setAttribute('fill', 'transparent');
          svg.appendChild(marker);
          break;
      }
    });
  }

  google.visualization.events.addListener(chart, 'ready', function () {
    addMarkers([
      {row: 0, date: new Date(currentYear, 1, 11), name: 'Event A', type: 'triangle', color: 'yellow'},
      {row: 2, date: new Date(currentYear, 10, 15), name: 'Event B', type: 'circle', color: 'lime'}
    ]);
  });

  window.addEventListener('resize', drawChart, false);
  drawChart();
});
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="timeline"></div>


来源:https://stackoverflow.com/questions/54614813/google-charts-add-layer-on-top-of-timeline

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