防止 amcharts 系列重叠
Keep amcharts series from overlapping
我有一个包含三个系列的图表设置,每个系列都有自己的 y 轴。目前它们显示在图表的两侧,如下所示:
这比我希望的图表要忙一些,因为有时系列可以混合在一起。我怎样才能使 y 轴不重叠,如下所示:
编辑:这是 working example
/**
* ---------------------------------------
* This demo was created using amCharts 4.
*
* For more information visit:
* https://www.amcharts.com/
*
* Documentation is available at:
* https://www.amcharts.com/docs/v4/
* ---------------------------------------
*/
// Apply chart themes
am4core.useTheme(am4themes_animated);
// Create chart instance
var chart = am4core.create("chartdiv", am4charts.XYChart);
chart.paddingRight = 20;
var dateAxis = chart.xAxes.push(new am4charts.DateAxis());
dateAxis.baseInterval = {
'timeUnit': 'second',
'count': 1
};
dateAxis.dateFormats.setKey('minute', 'h:mm a');
dateAxis.tooltipDateFormat = '[bold]MM-dd-yy, h:mm:ss a[/]';
dateAxis.renderer.grid.template.location = 0;
chart.yAxes.push(new am4charts.ValueAxis());
chart.yAxes.push(new am4charts.ValueAxis());
chart.yAxes.push(new am4charts.ValueAxis());
chart.cursor = new am4charts.XYCursor();
chart.legend = new am4charts.Legend();
var data = [
{name:'value1', value: 2, timestamp: '2018-01-01T15:00:00.00Z'},
{name:'value2', value: 5, timestamp: '2018-01-01T15:00:00.00Z'},
{name:'value3', value: 8, timestamp: '2018-01-01T15:00:00.00Z'},
{name:'value1', value: 4, timestamp: '2018-01-01T15:00:15.00Z'},
{name:'value2', value: 2, timestamp: '2018-01-01T15:00:15.00Z'},
{name:'value3', value: 5, timestamp: '2018-01-01T15:00:15.00Z'},
{name:'value1', value: 9, timestamp: '2018-01-01T15:00:30.00Z'},
{name:'value2', value: 11, timestamp: '2018-01-01T15:00:30.00Z'},
{name:'value3', value: 6, timestamp: '2018-01-01T15:00:30.00Z'},
{name:'value1', value: 4, timestamp: '2018-01-01T15:00:45.00Z'},
{name:'value2', value: 5, timestamp: '2018-01-01T15:00:45.00Z'},
{name:'value3', value: 13, timestamp: '2018-01-01T15:00:45.00Z'},
{name:'value1', value: 1, timestamp: '2018-01-01T15:01:00.00Z'},
{name:'value2', value: 7, timestamp: '2018-01-01T15:01:00.00Z'},
{name:'value3', value: 11, timestamp: '2018-01-01T15:01:00.00Z'},
];
var names = ['value1','value2', 'value3'];
names.forEach((name, index) => {
var opposite = index % 2 == 0;
var series = this.chart.series.push(new am4charts.LineSeries());
var yAxis = this.chart.yAxes.getIndex(index);
series.yAxis = yAxis;
series.name = name;
series.dataFields.dateX = 'date';
series.dataFields.valueY = 'value';
series.data = data.filter(d => d.name === name).map( d => {
return {date: new Date(d.timestamp), value: d.value};
});
switch (name) {
case 'value1':
series.stroke = am4core.color('#9E842F');
yAxis.minY = 0;
yAxis.maxY = 31;
break;
case 'value2':
series.stroke = am4core.color('#196D6F');
yAxis.minY = -20;
yAxis.maxY = 80;
break;
case 'value3':
series.stroke = am4core.color('#553786');
yAxis.minY = 0;
yAxis.maxY = 100;
break;
}
series.tooltip.getFillFromObject = false;
series.tooltip.background.fill = series.stroke;
series.tooltipText = '{name}: [bold]{valueY}[/]';
yAxis.cursorTooltipEnabled = false;
yAxis.renderer.line.strokeOpacity = 1;
yAxis.renderer.line.strokeWidth = 2;
yAxis.renderer.line.stroke = series.stroke;
yAxis.renderer.labels.template.fill = series.stroke;
yAxis.renderer.opposite = opposite;
yAxis.renderer.grid.template.disabled = true;
var bullet = series.bullets.push(new am4charts.CircleBullet());
bullet.width = 5;
bullet.height = 5;
bullet.fill = series.stroke;
});
var scrollbarX = new am4charts.XYChartScrollbar();
chart.series.values.forEach(s => {
scrollbarX.series.push(s);
});
chart.scrollbarX = scrollbarX;
chart.scrollbarX.parent = this.chart.bottomAxesContainer;
chart.validateData();
如果不创建单独的图表就无法执行此操作,但是如果您在同一 div 中创建单独的图表作为子容器对象,则可以同步光标并缩放每个实例。 github repo 中有一个此权限的示例,它创建了三个单独的实例并使用事件将游标同步在一起。
下面使用您的数据转载的演示:
am4core.useTheme(am4themes_animated);
var container = am4core.create("chartdiv", am4core.Container);
container.width = am4core.percent(100);
container.height = am4core.percent(100);
container.layout = "vertical";
var chartCount = 3;
var data = [
{name:'value1', value: 2, timestamp: '2018-01-01T15:00:00.00Z'},
{name:'value2', value: 5, timestamp: '2018-01-01T15:00:00.00Z'},
{name:'value3', value: 8, timestamp: '2018-01-01T15:00:00.00Z'},
{name:'value1', value: 4, timestamp: '2018-01-01T15:00:15.00Z'},
{name:'value2', value: 2, timestamp: '2018-01-01T15:00:15.00Z'},
{name:'value3', value: 5, timestamp: '2018-01-01T15:00:15.00Z'},
{name:'value1', value: 9, timestamp: '2018-01-01T15:00:30.00Z'},
{name:'value2', value: 11, timestamp: '2018-01-01T15:00:30.00Z'},
{name:'value3', value: 6, timestamp: '2018-01-01T15:00:30.00Z'},
{name:'value1', value: 4, timestamp: '2018-01-01T15:00:45.00Z'},
{name:'value2', value: 5, timestamp: '2018-01-01T15:00:45.00Z'},
{name:'value3', value: 13, timestamp: '2018-01-01T15:00:45.00Z'},
{name:'value1', value: 1, timestamp: '2018-01-01T15:01:00.00Z'},
{name:'value2', value: 7, timestamp: '2018-01-01T15:01:00.00Z'},
{name:'value3', value: 11, timestamp: '2018-01-01T15:01:00.00Z'},
];
var charts = [];
var cursorShowDisposers = [];
// create chart instances
for (var i = 0; i < chartCount; i++) {
makeChart(data.filter((x) => x.name == 'value' + (i + 1)), 'value' + (i + 1));
}
let legend = new am4charts.Legend();
legend.parent = container;
legend.interactionsEnabled = false;
legend.data = [{
"name": "value1",
"fill":"#9E842F"
}, {
"name": "value2",
"fill": "#196D6F"
}, {
"name": "value3",
"fill": "#553786"
}];
initCursorListeners();
// after the charts are made, add scrollbar to the first one
var firstChart = charts[0];
firstChart.scrollbarX = new am4core.Scrollbar();
firstChart.zoomOutButton.disabled = false;
// enable date axis labels for the last one
var lastChart = charts[charts.length - 1];
var lastDateAxis = lastChart.xAxes.getIndex(0);
lastDateAxis.renderer.labels.template.disabled = false;
lastDateAxis.cursorTooltipEnabled = true;
// create chart
function makeChart(data, name) {
var chart = container.createChild(am4charts.XYChart);
charts.push(chart);
chart.data = data;
chart.zoomOutButton.disabled = true;
chart.padding(10, 15, 10, 15);
var dateAxis = chart.xAxes.push(new am4charts.DateAxis());
dateAxis.renderer.grid.template.location = 0;
dateAxis.renderer.labels.template.disabled = true;
dateAxis.tooltip.animationDuration = 0;
dateAxis.cursorTooltipEnabled = false;
dateAxis.dateFormatter.inputDateFormat = 'i';
dateAxis.baseInterval = {
'timeUnit': 'second',
'count': 1
};
var valueAxis = chart.yAxes.push(new am4charts.ValueAxis());
valueAxis.tooltip.disabled = true;
valueAxis.tooltip.disabled = true;
valueAxis.renderer.minWidth = 60;
var series = chart.series.push(new am4charts.LineSeries());
series.dataFields.dateX = "timestamp";
series.dataFields.valueY = "value";
series.name = name;
series.interpolationDuration = 0;
switch (name) {
case 'value1':
series.stroke = am4core.color('#9E842F');
valueAxis.minY = 0;
valueAxis.maxY = 31;
break;
case 'value2':
series.stroke = am4core.color('#196D6F');
valueAxis.minY = -20;
valueAxis.maxY = 80;
break;
case 'value3':
series.stroke = am4core.color('#553786');
valueAxis.minY = 0;
valueAxis.maxY = 100;
break;
}
series.tooltip.getFillFromObject = false;
series.tooltip.background.fill = series.stroke;
series.tooltipText = '{name}: [bold]{valueY}[/]';
var bullet = series.bullets.push(new am4charts.CircleBullet());
bullet.width = 5;
bullet.height = 5;
bullet.fill = series.stroke;
var cursor = new am4charts.XYCursor();
cursor.lineY.disabled = true;
cursor.xAxis = dateAxis;
chart.cursor = cursor;
// whenever any of the charts is zoomed, we should zoom all other charts
dateAxis.events.on("selectionextremeschanged", function (event) {
syncDateAxes(event.target);
})
}
function initCursorListeners() {
cursorShowDisposers = [];
for (var i = 0; i < charts.length; i++) {
var chart = charts[i];
var cursor = chart.cursor;
cursor.interactionsEnabled = true;
cursorShowDisposers.push(cursor.events.on("shown", function (event) {
handleShowCursor(event.target);
}));
}
}
var shownCursorChangeDisposer;
var shownCursorZoomStartedDisposer;
var shownCursorZoomEndedDisposer;
function handleShowCursor(shownCursor) {
// disable mouse for all other cursors
for (var i = 0; i < charts.length; i++) {
var chart = charts[i];
var cursor = chart.cursor;
if (cursor != shownCursor) {
cursor.interactionsEnabled = false;
}
// remove show listener
cursorShowDisposers[i].dispose();
}
// add change disposer to the hovered chart cursor
shownCursorChangeDisposer = shownCursor.lineX.events.on("positionchanged", function (event) {
syncCursors(shownCursor);
});
shownCursorZoomStartedDisposer = shownCursor.events.on("zoomstarted", function (event) {
for (var i = 0; i < charts.length; i++) {
var chart = charts[i];
var cursor = chart.cursor;
if (cursor != event.target) {
var point = { x: event.target.point.x, y: 0 };
cursor.triggerDown(point);
}
}
});
shownCursorZoomEndedDisposer = shownCursor.events.on("zoomended", function (event) {
for (var i = 0; i < charts.length; i++) {
var chart = charts[i];
var cursor = chart.cursor;
if (cursor != event.target) {
var point = { x: event.target.point.x, y: 0 };
cursor.triggerUp(point);
}
}
});
shownCursor.events.once("hidden", function (event) {
shownCursorChangeDisposer.dispose();
shownCursorZoomStartedDisposer.dispose();
shownCursorZoomEndedDisposer.dispose();
for (var i = 0; i < charts.length; i++) {
var chart = charts[i];
var cursor = chart.cursor;
cursor.hide(0);
cursorShowDisposers[i].dispose();
}
initCursorListeners();
});
}
function syncCursors(syncWithCursor) {
for (var i = 0; i < charts.length; i++) {
var chart = charts[i];
var cursor = chart.cursor;
var point = { x: syncWithCursor.point.x, y: 0 };
if (cursor != syncWithCursor) {
cursor.triggerMove(point);
}
}
}
function syncDateAxes(syncWithAxis) {
for (var i = 0; i < charts.length; i++) {
var chart = charts[i];
var dateAxis = chart.xAxes.getIndex(0);
if (dateAxis != syncWithAxis) {
dateAxis.events.disableType("selectionextremeschanged");
dateAxis.start = syncWithAxis.start;
dateAxis.end = syncWithAxis.end;
dateAxis.events.enableType("selectionextremeschanged");
}
}
}
;
#chartdiv {
width: 100%;
height: 700px;
}
<script src="//www.amcharts.com/lib/4/core.js"></script>
<script src="//www.amcharts.com/lib/4/charts.js"></script>
<script src="//www.amcharts.com/lib/4/themes/animated.js"></script>
<div id="chartdiv"></div>
通过一些小的调整,可以将所有三个轴堆叠在一个图表中,光标、滚动条和缩放会影响所有三个轴:
主要技巧是设置chart.leftAxesContainer.layout = 'vertical'
让所有三个轴在容器中垂直堆叠
为了让它工作,不要在任何轴上设置opposite
(我们希望它们都位于左侧)
删除 yAxis 上的行设置 minY
和 maxY
值以避免难看的重叠
像这样在每个轴上设置合适的高度和边距:yAxis.height = 150; yAxis.marginBottom = 20;
更改 CSS 中图表的整体高度,使其更高并防止所有内容挤在一起(例如 #chartdiv { height: 700px; }
)
这是一个 modified version of your example 并且(如果 Codepen 停止存在)这是代码:
/**
* ---------------------------------------
* This demo was created using amCharts 4.
*
* For more information visit:
* https://www.amcharts.com/
*
* Documentation is available at:
* https://www.amcharts.com/docs/v4/
* ---------------------------------------
*/
// Apply chart themes
am4core.useTheme(am4themes_animated);
// Create chart instance
var chart = am4core.create("chartdiv", am4charts.XYChart);
chart.paddingRight = 20;
chart.leftAxesContainer.layout = 'vertical'
var dateAxis = chart.xAxes.push(new am4charts.DateAxis());
dateAxis.baseInterval = {
'timeUnit': 'second',
'count': 1
};
dateAxis.dateFormats.setKey('minute', 'h:mm a');
dateAxis.tooltipDateFormat = '[bold]MM-dd-yy, h:mm:ss a[/]';
dateAxis.renderer.grid.template.location = 0;
chart.yAxes.push(new am4charts.ValueAxis());
chart.yAxes.push(new am4charts.ValueAxis());
chart.yAxes.push(new am4charts.ValueAxis());
chart.cursor = new am4charts.XYCursor();
chart.legend = new am4charts.Legend();
var data = [
{name:'value1', value: 2, timestamp: '2018-01-01T15:00:00.00Z'},
{name:'value2', value: 5, timestamp: '2018-01-01T15:00:00.00Z'},
{name:'value3', value: 8, timestamp: '2018-01-01T15:00:00.00Z'},
{name:'value1', value: 4, timestamp: '2018-01-01T15:00:15.00Z'},
{name:'value2', value: 2, timestamp: '2018-01-01T15:00:15.00Z'},
{name:'value3', value: 5, timestamp: '2018-01-01T15:00:15.00Z'},
{name:'value1', value: 9, timestamp: '2018-01-01T15:00:30.00Z'},
{name:'value2', value: 11, timestamp: '2018-01-01T15:00:30.00Z'},
{name:'value3', value: 6, timestamp: '2018-01-01T15:00:30.00Z'},
{name:'value1', value: 4, timestamp: '2018-01-01T15:00:45.00Z'},
{name:'value2', value: 5, timestamp: '2018-01-01T15:00:45.00Z'},
{name:'value3', value: 13, timestamp: '2018-01-01T15:00:45.00Z'},
{name:'value1', value: 1, timestamp: '2018-01-01T15:01:00.00Z'},
{name:'value2', value: 7, timestamp: '2018-01-01T15:01:00.00Z'},
{name:'value3', value: 11, timestamp: '2018-01-01T15:01:00.00Z'},
];
var names = ['value1','value2', 'value3'];
names.forEach((name, index) => {
var series = this.chart.series.push(new am4charts.LineSeries());
var yAxis = this.chart.yAxes.getIndex(index);
yAxis.height = 150;
yAxis.marginBottom = 20;
series.yAxis = yAxis;
series.name = name;
series.dataFields.dateX = 'date';
series.dataFields.valueY = 'value';
series.data = data.filter(d => d.name === name).map( d => {
return {date: new Date(d.timestamp), value: d.value};
});
switch (name) {
case 'value1':
series.stroke = am4core.color('#9E842F');
break;
case 'value2':
series.stroke = am4core.color('#196D6F');
break;
case 'value3':
series.stroke = am4core.color('#553786');
break;
}
series.tooltip.getFillFromObject = false;
series.tooltip.background.fill = series.stroke;
series.tooltipText = '{name}: [bold]{valueY}[/]';
yAxis.cursorTooltipEnabled = false;
yAxis.renderer.line.strokeOpacity = 1;
yAxis.renderer.line.strokeWidth = 2;
yAxis.renderer.line.stroke = series.stroke;
yAxis.renderer.labels.template.fill = series.stroke;
yAxis.renderer.grid.template.disabled = true;
var bullet = series.bullets.push(new am4charts.CircleBullet());
bullet.width = 5;
bullet.height = 5;
bullet.fill = series.stroke;
});
var scrollbarX = new am4charts.XYChartScrollbar();
chart.series.values.forEach(s => {
scrollbarX.series.push(s);
});
chart.scrollbarX = scrollbarX;
chart.scrollbarX.parent = this.chart.bottomAxesContainer;
chart.validateData();
我有一个包含三个系列的图表设置,每个系列都有自己的 y 轴。目前它们显示在图表的两侧,如下所示:
这比我希望的图表要忙一些,因为有时系列可以混合在一起。我怎样才能使 y 轴不重叠,如下所示:
编辑:这是 working example
/**
* ---------------------------------------
* This demo was created using amCharts 4.
*
* For more information visit:
* https://www.amcharts.com/
*
* Documentation is available at:
* https://www.amcharts.com/docs/v4/
* ---------------------------------------
*/
// Apply chart themes
am4core.useTheme(am4themes_animated);
// Create chart instance
var chart = am4core.create("chartdiv", am4charts.XYChart);
chart.paddingRight = 20;
var dateAxis = chart.xAxes.push(new am4charts.DateAxis());
dateAxis.baseInterval = {
'timeUnit': 'second',
'count': 1
};
dateAxis.dateFormats.setKey('minute', 'h:mm a');
dateAxis.tooltipDateFormat = '[bold]MM-dd-yy, h:mm:ss a[/]';
dateAxis.renderer.grid.template.location = 0;
chart.yAxes.push(new am4charts.ValueAxis());
chart.yAxes.push(new am4charts.ValueAxis());
chart.yAxes.push(new am4charts.ValueAxis());
chart.cursor = new am4charts.XYCursor();
chart.legend = new am4charts.Legend();
var data = [
{name:'value1', value: 2, timestamp: '2018-01-01T15:00:00.00Z'},
{name:'value2', value: 5, timestamp: '2018-01-01T15:00:00.00Z'},
{name:'value3', value: 8, timestamp: '2018-01-01T15:00:00.00Z'},
{name:'value1', value: 4, timestamp: '2018-01-01T15:00:15.00Z'},
{name:'value2', value: 2, timestamp: '2018-01-01T15:00:15.00Z'},
{name:'value3', value: 5, timestamp: '2018-01-01T15:00:15.00Z'},
{name:'value1', value: 9, timestamp: '2018-01-01T15:00:30.00Z'},
{name:'value2', value: 11, timestamp: '2018-01-01T15:00:30.00Z'},
{name:'value3', value: 6, timestamp: '2018-01-01T15:00:30.00Z'},
{name:'value1', value: 4, timestamp: '2018-01-01T15:00:45.00Z'},
{name:'value2', value: 5, timestamp: '2018-01-01T15:00:45.00Z'},
{name:'value3', value: 13, timestamp: '2018-01-01T15:00:45.00Z'},
{name:'value1', value: 1, timestamp: '2018-01-01T15:01:00.00Z'},
{name:'value2', value: 7, timestamp: '2018-01-01T15:01:00.00Z'},
{name:'value3', value: 11, timestamp: '2018-01-01T15:01:00.00Z'},
];
var names = ['value1','value2', 'value3'];
names.forEach((name, index) => {
var opposite = index % 2 == 0;
var series = this.chart.series.push(new am4charts.LineSeries());
var yAxis = this.chart.yAxes.getIndex(index);
series.yAxis = yAxis;
series.name = name;
series.dataFields.dateX = 'date';
series.dataFields.valueY = 'value';
series.data = data.filter(d => d.name === name).map( d => {
return {date: new Date(d.timestamp), value: d.value};
});
switch (name) {
case 'value1':
series.stroke = am4core.color('#9E842F');
yAxis.minY = 0;
yAxis.maxY = 31;
break;
case 'value2':
series.stroke = am4core.color('#196D6F');
yAxis.minY = -20;
yAxis.maxY = 80;
break;
case 'value3':
series.stroke = am4core.color('#553786');
yAxis.minY = 0;
yAxis.maxY = 100;
break;
}
series.tooltip.getFillFromObject = false;
series.tooltip.background.fill = series.stroke;
series.tooltipText = '{name}: [bold]{valueY}[/]';
yAxis.cursorTooltipEnabled = false;
yAxis.renderer.line.strokeOpacity = 1;
yAxis.renderer.line.strokeWidth = 2;
yAxis.renderer.line.stroke = series.stroke;
yAxis.renderer.labels.template.fill = series.stroke;
yAxis.renderer.opposite = opposite;
yAxis.renderer.grid.template.disabled = true;
var bullet = series.bullets.push(new am4charts.CircleBullet());
bullet.width = 5;
bullet.height = 5;
bullet.fill = series.stroke;
});
var scrollbarX = new am4charts.XYChartScrollbar();
chart.series.values.forEach(s => {
scrollbarX.series.push(s);
});
chart.scrollbarX = scrollbarX;
chart.scrollbarX.parent = this.chart.bottomAxesContainer;
chart.validateData();
如果不创建单独的图表就无法执行此操作,但是如果您在同一 div 中创建单独的图表作为子容器对象,则可以同步光标并缩放每个实例。 github repo 中有一个此权限的示例,它创建了三个单独的实例并使用事件将游标同步在一起。
下面使用您的数据转载的演示:
am4core.useTheme(am4themes_animated);
var container = am4core.create("chartdiv", am4core.Container);
container.width = am4core.percent(100);
container.height = am4core.percent(100);
container.layout = "vertical";
var chartCount = 3;
var data = [
{name:'value1', value: 2, timestamp: '2018-01-01T15:00:00.00Z'},
{name:'value2', value: 5, timestamp: '2018-01-01T15:00:00.00Z'},
{name:'value3', value: 8, timestamp: '2018-01-01T15:00:00.00Z'},
{name:'value1', value: 4, timestamp: '2018-01-01T15:00:15.00Z'},
{name:'value2', value: 2, timestamp: '2018-01-01T15:00:15.00Z'},
{name:'value3', value: 5, timestamp: '2018-01-01T15:00:15.00Z'},
{name:'value1', value: 9, timestamp: '2018-01-01T15:00:30.00Z'},
{name:'value2', value: 11, timestamp: '2018-01-01T15:00:30.00Z'},
{name:'value3', value: 6, timestamp: '2018-01-01T15:00:30.00Z'},
{name:'value1', value: 4, timestamp: '2018-01-01T15:00:45.00Z'},
{name:'value2', value: 5, timestamp: '2018-01-01T15:00:45.00Z'},
{name:'value3', value: 13, timestamp: '2018-01-01T15:00:45.00Z'},
{name:'value1', value: 1, timestamp: '2018-01-01T15:01:00.00Z'},
{name:'value2', value: 7, timestamp: '2018-01-01T15:01:00.00Z'},
{name:'value3', value: 11, timestamp: '2018-01-01T15:01:00.00Z'},
];
var charts = [];
var cursorShowDisposers = [];
// create chart instances
for (var i = 0; i < chartCount; i++) {
makeChart(data.filter((x) => x.name == 'value' + (i + 1)), 'value' + (i + 1));
}
let legend = new am4charts.Legend();
legend.parent = container;
legend.interactionsEnabled = false;
legend.data = [{
"name": "value1",
"fill":"#9E842F"
}, {
"name": "value2",
"fill": "#196D6F"
}, {
"name": "value3",
"fill": "#553786"
}];
initCursorListeners();
// after the charts are made, add scrollbar to the first one
var firstChart = charts[0];
firstChart.scrollbarX = new am4core.Scrollbar();
firstChart.zoomOutButton.disabled = false;
// enable date axis labels for the last one
var lastChart = charts[charts.length - 1];
var lastDateAxis = lastChart.xAxes.getIndex(0);
lastDateAxis.renderer.labels.template.disabled = false;
lastDateAxis.cursorTooltipEnabled = true;
// create chart
function makeChart(data, name) {
var chart = container.createChild(am4charts.XYChart);
charts.push(chart);
chart.data = data;
chart.zoomOutButton.disabled = true;
chart.padding(10, 15, 10, 15);
var dateAxis = chart.xAxes.push(new am4charts.DateAxis());
dateAxis.renderer.grid.template.location = 0;
dateAxis.renderer.labels.template.disabled = true;
dateAxis.tooltip.animationDuration = 0;
dateAxis.cursorTooltipEnabled = false;
dateAxis.dateFormatter.inputDateFormat = 'i';
dateAxis.baseInterval = {
'timeUnit': 'second',
'count': 1
};
var valueAxis = chart.yAxes.push(new am4charts.ValueAxis());
valueAxis.tooltip.disabled = true;
valueAxis.tooltip.disabled = true;
valueAxis.renderer.minWidth = 60;
var series = chart.series.push(new am4charts.LineSeries());
series.dataFields.dateX = "timestamp";
series.dataFields.valueY = "value";
series.name = name;
series.interpolationDuration = 0;
switch (name) {
case 'value1':
series.stroke = am4core.color('#9E842F');
valueAxis.minY = 0;
valueAxis.maxY = 31;
break;
case 'value2':
series.stroke = am4core.color('#196D6F');
valueAxis.minY = -20;
valueAxis.maxY = 80;
break;
case 'value3':
series.stroke = am4core.color('#553786');
valueAxis.minY = 0;
valueAxis.maxY = 100;
break;
}
series.tooltip.getFillFromObject = false;
series.tooltip.background.fill = series.stroke;
series.tooltipText = '{name}: [bold]{valueY}[/]';
var bullet = series.bullets.push(new am4charts.CircleBullet());
bullet.width = 5;
bullet.height = 5;
bullet.fill = series.stroke;
var cursor = new am4charts.XYCursor();
cursor.lineY.disabled = true;
cursor.xAxis = dateAxis;
chart.cursor = cursor;
// whenever any of the charts is zoomed, we should zoom all other charts
dateAxis.events.on("selectionextremeschanged", function (event) {
syncDateAxes(event.target);
})
}
function initCursorListeners() {
cursorShowDisposers = [];
for (var i = 0; i < charts.length; i++) {
var chart = charts[i];
var cursor = chart.cursor;
cursor.interactionsEnabled = true;
cursorShowDisposers.push(cursor.events.on("shown", function (event) {
handleShowCursor(event.target);
}));
}
}
var shownCursorChangeDisposer;
var shownCursorZoomStartedDisposer;
var shownCursorZoomEndedDisposer;
function handleShowCursor(shownCursor) {
// disable mouse for all other cursors
for (var i = 0; i < charts.length; i++) {
var chart = charts[i];
var cursor = chart.cursor;
if (cursor != shownCursor) {
cursor.interactionsEnabled = false;
}
// remove show listener
cursorShowDisposers[i].dispose();
}
// add change disposer to the hovered chart cursor
shownCursorChangeDisposer = shownCursor.lineX.events.on("positionchanged", function (event) {
syncCursors(shownCursor);
});
shownCursorZoomStartedDisposer = shownCursor.events.on("zoomstarted", function (event) {
for (var i = 0; i < charts.length; i++) {
var chart = charts[i];
var cursor = chart.cursor;
if (cursor != event.target) {
var point = { x: event.target.point.x, y: 0 };
cursor.triggerDown(point);
}
}
});
shownCursorZoomEndedDisposer = shownCursor.events.on("zoomended", function (event) {
for (var i = 0; i < charts.length; i++) {
var chart = charts[i];
var cursor = chart.cursor;
if (cursor != event.target) {
var point = { x: event.target.point.x, y: 0 };
cursor.triggerUp(point);
}
}
});
shownCursor.events.once("hidden", function (event) {
shownCursorChangeDisposer.dispose();
shownCursorZoomStartedDisposer.dispose();
shownCursorZoomEndedDisposer.dispose();
for (var i = 0; i < charts.length; i++) {
var chart = charts[i];
var cursor = chart.cursor;
cursor.hide(0);
cursorShowDisposers[i].dispose();
}
initCursorListeners();
});
}
function syncCursors(syncWithCursor) {
for (var i = 0; i < charts.length; i++) {
var chart = charts[i];
var cursor = chart.cursor;
var point = { x: syncWithCursor.point.x, y: 0 };
if (cursor != syncWithCursor) {
cursor.triggerMove(point);
}
}
}
function syncDateAxes(syncWithAxis) {
for (var i = 0; i < charts.length; i++) {
var chart = charts[i];
var dateAxis = chart.xAxes.getIndex(0);
if (dateAxis != syncWithAxis) {
dateAxis.events.disableType("selectionextremeschanged");
dateAxis.start = syncWithAxis.start;
dateAxis.end = syncWithAxis.end;
dateAxis.events.enableType("selectionextremeschanged");
}
}
}
;
#chartdiv {
width: 100%;
height: 700px;
}
<script src="//www.amcharts.com/lib/4/core.js"></script>
<script src="//www.amcharts.com/lib/4/charts.js"></script>
<script src="//www.amcharts.com/lib/4/themes/animated.js"></script>
<div id="chartdiv"></div>
通过一些小的调整,可以将所有三个轴堆叠在一个图表中,光标、滚动条和缩放会影响所有三个轴:
主要技巧是设置
chart.leftAxesContainer.layout = 'vertical'
让所有三个轴在容器中垂直堆叠为了让它工作,不要在任何轴上设置
opposite
(我们希望它们都位于左侧)删除 yAxis 上的行设置
minY
和maxY
值以避免难看的重叠像这样在每个轴上设置合适的高度和边距:
yAxis.height = 150; yAxis.marginBottom = 20;
更改 CSS 中图表的整体高度,使其更高并防止所有内容挤在一起(例如
#chartdiv { height: 700px; }
)
这是一个 modified version of your example 并且(如果 Codepen 停止存在)这是代码:
/**
* ---------------------------------------
* This demo was created using amCharts 4.
*
* For more information visit:
* https://www.amcharts.com/
*
* Documentation is available at:
* https://www.amcharts.com/docs/v4/
* ---------------------------------------
*/
// Apply chart themes
am4core.useTheme(am4themes_animated);
// Create chart instance
var chart = am4core.create("chartdiv", am4charts.XYChart);
chart.paddingRight = 20;
chart.leftAxesContainer.layout = 'vertical'
var dateAxis = chart.xAxes.push(new am4charts.DateAxis());
dateAxis.baseInterval = {
'timeUnit': 'second',
'count': 1
};
dateAxis.dateFormats.setKey('minute', 'h:mm a');
dateAxis.tooltipDateFormat = '[bold]MM-dd-yy, h:mm:ss a[/]';
dateAxis.renderer.grid.template.location = 0;
chart.yAxes.push(new am4charts.ValueAxis());
chart.yAxes.push(new am4charts.ValueAxis());
chart.yAxes.push(new am4charts.ValueAxis());
chart.cursor = new am4charts.XYCursor();
chart.legend = new am4charts.Legend();
var data = [
{name:'value1', value: 2, timestamp: '2018-01-01T15:00:00.00Z'},
{name:'value2', value: 5, timestamp: '2018-01-01T15:00:00.00Z'},
{name:'value3', value: 8, timestamp: '2018-01-01T15:00:00.00Z'},
{name:'value1', value: 4, timestamp: '2018-01-01T15:00:15.00Z'},
{name:'value2', value: 2, timestamp: '2018-01-01T15:00:15.00Z'},
{name:'value3', value: 5, timestamp: '2018-01-01T15:00:15.00Z'},
{name:'value1', value: 9, timestamp: '2018-01-01T15:00:30.00Z'},
{name:'value2', value: 11, timestamp: '2018-01-01T15:00:30.00Z'},
{name:'value3', value: 6, timestamp: '2018-01-01T15:00:30.00Z'},
{name:'value1', value: 4, timestamp: '2018-01-01T15:00:45.00Z'},
{name:'value2', value: 5, timestamp: '2018-01-01T15:00:45.00Z'},
{name:'value3', value: 13, timestamp: '2018-01-01T15:00:45.00Z'},
{name:'value1', value: 1, timestamp: '2018-01-01T15:01:00.00Z'},
{name:'value2', value: 7, timestamp: '2018-01-01T15:01:00.00Z'},
{name:'value3', value: 11, timestamp: '2018-01-01T15:01:00.00Z'},
];
var names = ['value1','value2', 'value3'];
names.forEach((name, index) => {
var series = this.chart.series.push(new am4charts.LineSeries());
var yAxis = this.chart.yAxes.getIndex(index);
yAxis.height = 150;
yAxis.marginBottom = 20;
series.yAxis = yAxis;
series.name = name;
series.dataFields.dateX = 'date';
series.dataFields.valueY = 'value';
series.data = data.filter(d => d.name === name).map( d => {
return {date: new Date(d.timestamp), value: d.value};
});
switch (name) {
case 'value1':
series.stroke = am4core.color('#9E842F');
break;
case 'value2':
series.stroke = am4core.color('#196D6F');
break;
case 'value3':
series.stroke = am4core.color('#553786');
break;
}
series.tooltip.getFillFromObject = false;
series.tooltip.background.fill = series.stroke;
series.tooltipText = '{name}: [bold]{valueY}[/]';
yAxis.cursorTooltipEnabled = false;
yAxis.renderer.line.strokeOpacity = 1;
yAxis.renderer.line.strokeWidth = 2;
yAxis.renderer.line.stroke = series.stroke;
yAxis.renderer.labels.template.fill = series.stroke;
yAxis.renderer.grid.template.disabled = true;
var bullet = series.bullets.push(new am4charts.CircleBullet());
bullet.width = 5;
bullet.height = 5;
bullet.fill = series.stroke;
});
var scrollbarX = new am4charts.XYChartScrollbar();
chart.series.values.forEach(s => {
scrollbarX.series.push(s);
});
chart.scrollbarX = scrollbarX;
chart.scrollbarX.parent = this.chart.bottomAxesContainer;
chart.validateData();