如何将自定义标记添加到 Google 时间线图表?
How to add custom markers to Google Timeline Chart?
我想在 Google 时间轴图表上添加标记,如此处所示 Timeline Chart with Markers
我目前正在遵循此处给出的解决方案:。但是,这里需要有一个时间轴元素,然后标记才能出现在它上面。但是,我想要一种可以添加标记的方法,而无需在行中的那个位置有任何时间线数据。是否有用于在 Google 时间轴中添加标记的内置功能,或者不需要添加虚拟时间轴的自定义方法。
没有 built-in 添加标记的功能。
由于您引用的答案是自定义解决方案,
我们可以修改解决方案以满足我们的需要。
我们不一定需要时间线元素来放置标记。
但我们确实需要数据,以便绘制时间线,
在其上放置标记。
开箱即用,时间轴会将 x-axis 限制在数据中找到的日期范围内。
但我们可以设置自定义 x-axis 范围,使其更大,
并为没有时间线元素的标记留出更多空间。
hAxis: {
minValue: dateRangeStart,
maxValue: dateRangeEnd,
}
请参阅以下工作片段...
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 = new Date(currentYear - 1, 0, 1);
var dateRangeEnd = new Date(currentYear + 1, 11, 31);
var rowHeight = 44;
var options = {
height: (dataTableGroup.getNumberOfRows() * rowHeight) + rowHeight,
hAxis: {
minValue: dateRangeStart,
maxValue: dateRangeEnd,
}
};
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.getTime() - dateRangeStart.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.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, 1, 11), name: 'Event 1', type: 'triangle', color: 'red'},
{row: 1, date: new Date(currentYear + 1, 5, 23), name: 'Event 2', type: 'circle', color: 'purple'},
{row: 3, date: new Date(currentYear + 1, 8, 2), name: 'Event 3', type: 'triangle', color: 'magenta'}
]);
});
window.addEventListener('resize', drawChart, false);
drawChart();
});
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="timeline"></div>
我想在 Google 时间轴图表上添加标记,如此处所示 Timeline Chart with Markers
我目前正在遵循此处给出的解决方案:
没有 built-in 添加标记的功能。
由于您引用的答案是自定义解决方案,
我们可以修改解决方案以满足我们的需要。
我们不一定需要时间线元素来放置标记。
但我们确实需要数据,以便绘制时间线,
在其上放置标记。
开箱即用,时间轴会将 x-axis 限制在数据中找到的日期范围内。
但我们可以设置自定义 x-axis 范围,使其更大,
并为没有时间线元素的标记留出更多空间。
hAxis: {
minValue: dateRangeStart,
maxValue: dateRangeEnd,
}
请参阅以下工作片段...
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 = new Date(currentYear - 1, 0, 1);
var dateRangeEnd = new Date(currentYear + 1, 11, 31);
var rowHeight = 44;
var options = {
height: (dataTableGroup.getNumberOfRows() * rowHeight) + rowHeight,
hAxis: {
minValue: dateRangeStart,
maxValue: dateRangeEnd,
}
};
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.getTime() - dateRangeStart.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.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, 1, 11), name: 'Event 1', type: 'triangle', color: 'red'},
{row: 1, date: new Date(currentYear + 1, 5, 23), name: 'Event 2', type: 'circle', color: 'purple'},
{row: 3, date: new Date(currentYear + 1, 8, 2), name: 'Event 3', type: 'triangle', color: 'magenta'}
]);
});
window.addEventListener('resize', drawChart, false);
drawChart();
});
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="timeline"></div>