Chart.js хранит две диаграммы рядом на одном холсте - PullRequest
1 голос
/ 16 апреля 2019

Как и в заголовке, я хотел бы использовать один холст, чтобы поделиться с помощью chart.js.Я видел рядом с DOM , но это что-то еще, мне нужно сохранить один холст и сохранить анимацию.

Я использую версию Chart.js: 2.8.0 (последняя версия)Идея ретранслировать сюжет через регистрацию плагина.Первая часть работает как шарм, в beforeLayout

chart.width = chart.canvas.width * 0.6;

масштабируется первый график, работает отлично, даже всплывающие подсказки отображаются только в пределах области первых графиков.Со вторым графиком, если я установлю:

chart.width = chart.canvas.width * 0.4;
chart.options.layout.padding.left = chart.canvas.width * 0.6;

Сюжет запутывается, стеки confused plot chart.js

ясно, что я могу установить

 chart.width = chart.canvas.width * 1;

ипотом перерисовать первый график, но, может быть, есть какой-то простой способ сохранить два (или более) графиков, разделяющих холст?

Код, взятый из sample.js samples и измененный мной для обеспечения минимальной рабочей нагрузкипример.

<!DOCTYPE html>
<html><head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
	<title>Line Chart</title>
	<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.8.0/Chart.bundle.min.js"></script>
</head>

<body>
<canvas id="canvas" width="1013" height="506" class="chartjs-render-monitor"></canvas>
	<br>
	<button id="randomizeData">Randomize Data</button>
	<script>
		var config = {
			type: 'bar',
			data: {
				labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
				datasets: [{
					label: 'My First dataset',
					backgroundColor: 'green',
					borderColor: 'blue',
					data: [
						Math.random(), Math.random(), Math.random(), Math.random(), Math.random(), Math.random(), Math.random()
					],
					fill: false,
				}, {
					label: 'My Second dataset',
					fill: false,
					backgroundColor: 'blue',
					borderColor: 'blue',
					data: [
						Math.random(), Math.random(), Math.random(), Math.random(), Math.random(), Math.random(), Math.random()
					],
				}]
			},
			plugins: [{
				beforeLayout: function (chart) {
					chart.width = chart.canvas.width * 0.6;
					chart.options.layout.padding.left = 0;
				},

			}],
			options: {
				responsive: true,
				title: {
					display: true,
					text: 'Chart.js Line Chart'
				},
				tooltips: {
					mode: 'index',
					intersect: false,
				},
				hover: {
					mode: 'nearest',
					intersect: true
				},
				scales: {
					xAxes: [{
						display: true,
						scaleLabel: {
							display: true,
							labelString: 'Month'
						}
					}],
					yAxes: [{
						display: true,
						scaleLabel: {
							display: true,
							labelString: 'Value'
						}
					}]
				}
			}
		};

		var config2 = {
			type: 'bar',
			data: {
				labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
				datasets: [{
					label: 'My First dataset',
					backgroundColor: 'green',
					borderColor: 'blue',
					data: [
						Math.random(), Math.random(), Math.random(), Math.random(), Math.random(), Math.random(), Math.random()
					],
					fill: false,
				}, {
					label: 'My Second dataset',
					fill: false,
					backgroundColor: 'blue',
					borderColor: 'blue',
					data: [
						Math.random(), Math.random(), Math.random(), Math.random(), Math.random(), Math.random(), Math.random()
					],
				}]
			},
			plugins: [{
				beforeLayout: function (chart) {
					chart.width = chart.canvas.width * 0.4;
					chart.options.layout.padding.left = chart.canvas.width * 0.6;
				},

			}],
			options: {
				responsive: true,
				title: {
					display: true,
					text: 'Chart.js Line Chart'
				},
				tooltips: {
					mode: 'index',
					intersect: false,
				},
				hover: {
					mode: 'nearest',
					intersect: true
				},
				scales: {
					xAxes: [{
						display: true,
						scaleLabel: {
							display: true,
							labelString: 'Month'
						}
					}],
					yAxes: [{
						display: true,
						scaleLabel: {
							display: true,
							labelString: 'Value'
						}
					}]
				}
			}
		};

		window.onload = function() {
			var ctx = document.getElementById('canvas').getContext('2d');
			window.myLine = new Chart(ctx, config);
			window.myLine2 = new Chart(ctx, config2);
		};

		document.getElementById('randomizeData').addEventListener('click', function() {
			config.data.datasets.forEach(function(dataset) {
				dataset.data = dataset.data.map(function() {
					return Math.random();
				});
			});

			config2.data.datasets.forEach(function(dataset) {
				dataset.data = dataset.data.map(function() {
					return Math.random();
				});
			});

			window.myLine.update();
			window.myLine2.update();
		});

	</script>
</body></html>

Вот как выглядит желаемый результат:
desired result Такие вещи, как отсутствующая ось Y, легенда и заголовок, скрываются простым display: false, а верхняя часть отступа для второго графика установлена ​​на первый график chartArea.top, проблема здесь заключается в мерцании и слишком частом перерисовке первого графика, он также получает события наведения, поэтому установка только одного отступа не нужна, поэтому для второго графика должен быть смещенустановить как-то.

Теперь я приложил усилия к тому, чтобы немного измениться и решил самостоятельно очистить, осталась глючная подсказка, всплывающая в обоих графиках и вертикальное смещение между барами обоих графиков.Также требуется перерисовка вручную при изменении размера.

<!DOCTYPE html>
<html><head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
	<title>Line Chart</title>
	<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.8.0/Chart.bundle.min.js"></script>
</head>

<body>
<div>
<canvas id="canvas" width="1013" height="506" class="chartjs-render-monitor"></canvas>
</div>
	<br>
	<button id="randomizeData">Randomize Data</button>
	<script>
		var config = {
			type: 'horizontalBar',
			data: {
				labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul'],
				datasets: [{
					label: 'My First dataset',
					backgroundColor: 'green',
					borderColor: 'blue',
					data: [
						Math.random(), Math.random(), Math.random(), Math.random(), Math.random(), Math.random(), Math.random()
					]
				}, {
					backgroundColor: 'blue',
					borderColor: 'blue',
					data: [
						Math.random(), Math.random(), Math.random(), Math.random(), Math.random(), Math.random(), Math.random()
					],
				}]
			},
			plugins: [{
				beforeLayout: function (chart) {
					chart.width = chart.canvas.width * 0.55;
					chart.options.layout.padding.left = 0;
				},

			}],
			onResize: function() {
			console.log(3)
			},
			options: {
				responsive: true,
				legend: {
					display: false
				},
				title: {
					display: true,
					text: 'Chart.js Test double plot'
				},
				tooltips: {
					mode: 'index',
					intersect: false,
				},
				hover: {
					mode: 'label',
					intersect: true
				},
				scales: {
					xAxes: [{
						display: false,
						scaleLabel: {
							display: true,
							labelString: 'Month'
						}
					}],
					yAxes: [{
						display: true,
			            gridLines: {
							display:false
						}
					}]
				}
			}
		};

		var config2 = {
			type: 'horizontalBar',
			data: {
				labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
				datasets: [{
					backgroundColor: 'green',
					borderColor: 'blue',
					data: [
						Math.random(), Math.random(), Math.random(), Math.random(), Math.random(), Math.random(), Math.random()
					],
					fill: false,
				}, {
					backgroundColor: 'blue',
					borderColor: 'blue',
					data: [
						Math.random(), Math.random(), Math.random(), Math.random(), Math.random(), Math.random(), Math.random()
					],
				}]
			},
			plugins: [{
				beforeLayout: function (chart) {
					chart.options.layout.padding.left = chart.canvas.width * 0.55;
					chart.options.layout.padding.top = myLine.chartArea.top;
				},

				afterDraw: function (chart) {
					myLine.update();
				},

			}],
			options: {
				responsive: true,
				title: {
					display: false,
				},
				legend: {
					display: false
				},
				tooltips: {
					mode: 'index',
					intersect: false,
				},
				hover: {
					mode: 'label',
					intersect: true
				},
				scales: {
					xAxes: [{
						gridLines: {
							display:false
						},   
						display: false,
						scaleLabel: {
							display: true,
						}
					}],
					yAxes: [{
						display: false,
					}]
				}
			}
		};

		window.onload = function() {
			var ctx = document.getElementById('canvas').getContext('2d');
			window.myLine = new Chart(ctx, config);
			myLine.clear = function() {
				var canvas = this.ctx;
				canvas.clearRect(0, 0, this.chartArea.right, this.height); return this.canvas;}
			window.myLine2 = new Chart(ctx, config2);
			myLine2.clear = function() {
			var canvas = this.ctx;
			canvas.clearRect(this.chartArea.left, 0, this.chartArea.right - this.chartArea.left + 15, this.height); return this.canvas;}
		};

		document.getElementById('randomizeData').addEventListener('click', function() {
			config.data.datasets.forEach(function(dataset) {
				dataset.data = dataset.data.map(function() {
					return Math.random();
				});
			});

			config2.data.datasets.forEach(function(dataset) {
				dataset.data = dataset.data.map(function() {
					return Math.random();
				});
			});

			window.myLine.update();
			window.myLine2.update();
		});

	</script>
</body></html>

Было бы даже при запуске многих обновлений, но всплывающих подсказок не было, во время анимации присутствуют два одновременно.Этот результат выглядит почти как окончательный вариант, поэтому, если кто-то задается вопросом, почему, это четыре переменные для одних и тех же данных, две связанные.Так как остались только полосы и всплывающие подсказки, я бы нарисовал несколько прямоугольников сам, если бы не анимация и тот же каркас, используемый для других графиков.Конвейер для дальнейшей обработки требует одного изображения, так что взлом холста по требованию для отрисовки их обоих невозможен.

Проблема в том, что отступы или поля игнорируются Chart.js при перерисовке.

two charts, buggy

...