我想创建一个包含Chart.Js
的折线图,但滚动时Y-Axis
不会移动。
我假设我可以使用固定宽度,并将其放在带有overflow:auto
的容器div中,但随后将Y-axis
信息附加到画布并向上滚动。
我在文档中没有看到此参数或选项。有什么想法吗?
谢谢
答案 0 :(得分:27)
你几乎走在正确的轨道上。如果添加另一个包装器和y轴,则完成。
预览强>
<强> CSS 强>
.chartWrapper {
position: relative;
}
.chartWrapper > canvas {
position: absolute;
left: 0;
top: 0;
pointer-events:none;
}
.chartAreaWrapper {
width: 600px;
overflow-x: scroll;
}
<强> HTML 强>
<div class="chartWrapper">
<div class="chartAreaWrapper">
<canvas id="myChart" height="300" width="1200"></canvas>
</div>
<canvas id="myChartAxis" height="300" width="0"></canvas>
</div>
<强>脚本强>
...
new Chart(ctx).Line(data, {
onAnimationComplete: function () {
var sourceCanvas = this.chart.ctx.canvas;
// the -5 is so that we don't copy the edges of the line
var copyWidth = this.scale.xScalePaddingLeft - 5;
// the +5 is so that the bottommost y axis label is not clipped off
// we could factor this in using measureText if we wanted to be generic
var copyHeight = this.scale.endPoint + 5;
var targetCtx = document.getElementById("myChartAxis").getContext("2d");
targetCtx.canvas.width = copyWidth;
targetCtx.drawImage(sourceCanvas, 0, 0, copyWidth, copyHeight, 0, 0, copyWidth, copyHeight);
}
});
答案 1 :(得分:6)
Chart.js 2.7.2:https://jsfiddle.net/EmmaLouise/eb1aqpx8/3/
此方法处理不同的DPR设置,并将缩放轴以匹配Chart.js应用于其图表的缩放比例。它还会在Chart.js绘制的原始Y轴上调用.clearRect(),清除已定义区域中的像素,这意味着没有轴重复或重叠。
CSS:
.chartWrapper {
position: relative;
}
.chartWrapper > canvas {
position: absolute;
left: 0;
top: 0;
pointer-events: none;
}
.chartAreaWrapper {
width: 600px;
overflow-x: scroll;
}
HTML
<div class="chartWrapper">
<div class="chartAreaWrapper">
<div class="chartAreaWrapper2">
<canvas id="chart-Test" height="300" width="1200"></canvas>
</div>
</div>
<canvas id="axis-Test" height="300" width="0"></canvas>
</div>
JS:
$(function () {
var rectangleSet = false;
var canvasTest = $('#chart-Test');
var chartTest = new Chart(canvasTest, {
type: 'bar',
data: chartData,
maintainAspectRatio: false,
responsive: true,
options: {
tooltips: {
titleFontSize: 0,
titleMarginBottom: 0,
bodyFontSize: 12
},
legend: {
display: false
},
scales: {
xAxes: [{
ticks: {
fontSize: 12,
display: false
}
}],
yAxes: [{
ticks: {
fontSize: 12,
beginAtZero: true
}
}]
},
animation: {
onComplete: function () {
if (!rectangleSet) {
var scale = window.devicePixelRatio;
var sourceCanvas = chartTest.chart.canvas;
var copyWidth = chartTest.scales['y-axis-0'].width - 10;
var copyHeight = chartTest.scales['y-axis-0'].height + chartTest.scales['y-axis-0'].top + 10;
var targetCtx = document.getElementById("axis-Test").getContext("2d");
targetCtx.scale(scale, scale);
targetCtx.canvas.width = copyWidth * scale;
targetCtx.canvas.height = copyHeight * scale;
targetCtx.canvas.style.width = `${copyWidth}px`;
targetCtx.canvas.style.height = `${copyHeight}px`;
targetCtx.drawImage(sourceCanvas, 0, 0, copyWidth * scale, copyHeight * scale, 0, 0, copyWidth * scale, copyHeight * scale);
var sourceCtx = sourceCanvas.getContext('2d');
// Normalize coordinate system to use css pixels.
sourceCtx.clearRect(0, 0, copyWidth * scale, copyHeight * scale);
rectangleSet = true;
}
},
onProgress: function () {
if (rectangleSet === true) {
var copyWidth = chartTest.scales['y-axis-0'].width;
var copyHeight = chartTest.scales['y-axis-0'].height + chartTest.scales['y-axis-0'].top + 10;
var sourceCtx = chartTest.chart.canvas.getContext('2d');
sourceCtx.clearRect(0, 0, copyWidth, copyHeight);
}
}
}
}
});
答案 2 :(得分:2)
这是完整的工作示例,包含 5000 个数据点,并根据需要添加尽可能多的数据。 滚动条代码取自互联网,因此您可以根据需要对其进行修改。 此示例还包含一个带有多个系列的滚动条。 (代码有注释)
<!DOCTYPE html>
<html lang="en">
<head> </head>
<body>
<div style="width: 500pt;">
<canvas id="myChart" style="display: block;width: 1333px;height: 369px;"></canvas>
<section class="range-slider">
<span class="rangeValues"></span>
<input value="1" min="1" max="" type="range" />
<input value="10" min="1" max="" type="range" />
</section>
</div>
</body>
<style>
section.range-slider {
position: relative;
width: 700px;
height: 300px;
float: left;
text-align: center;
}
section.range-slider input[type="range"] {
pointer-events: none;
position: absolute;
-webkit-appearance: none;
-webkit-tap-highlight-color: rgba(255, 255, 255, 0);
border: none;
border-radius: 14px;
background: #f1efef;
box-shadow: inset 0 1px 0 0 #cdc6c6, inset 0 -1px 0 0 #d9d4d4;
-webkit-box-shadow: inset 0 1px 0 0 #cdc6c6, inset 0 -1px 0 0 #d9d4d4;
overflow: hidden;
left: 0;
top: 50px;
width: 700px;
outline: none;
height: 20px;
margin: 0;
padding: 0;
}
section.range-slider input[type="range"]::-webkit-slider-thumb {
pointer-events: all;
position: relative;
z-index: 1;
outline: 0;
-webkit-appearance: none;
width: 20px;
height: 20px;
border: none;
border-radius: 14px;
background-image: -webkit-gradient(
linear,
left top,
left bottom,
color-stop(0%, #dad8da),
color-stop(100%, #413f41)
);
/* android <= 2.2 */
background-image: -webkit-linear-gradient(top, #dad8da 0, #413f41 100%);
/* older mobile safari and android > 2.2 */
background-image: linear-gradient(to bottom, #dad8da 0, #413f41 100%);
/* W3C */
}
section.range-slider input[type="range"]::-moz-range-thumb {
pointer-events: all;
position: relative;
z-index: 10;
-moz-appearance: none;
width: 20px;
height: 20px;
border: none;
border-radius: 14px;
background-image: linear-gradient(to bottom, #dad8da 0, #413f41 100%);
/* W3C */
}
section.range-slider input[type="range"]::-ms-thumb {
pointer-events: all;
position: relative;
z-index: 10;
-ms-appearance: none;
width: 20px;
height: 20px;
border-radius: 14px;
border: 0;
background-image: linear-gradient(to bottom, #dad8da 0, #413f41 100%);
/* W3C */
}
section.range-slider input[type="range"]::-moz-range-track {
position: relative;
z-index: -1;
background-color: black;
border: 0;
}
section.range-slider input[type="range"]:last-of-type::-moz-range-track {
-moz-appearance: none;
background: none transparent;
border: 0;
}
section.range-slider input[type="range"]::-moz-focus-outer {
border: 0;
}
</style>
</html>
<script src="https://cdn.jsdelivr.net/npm/chart.js@2.8.0"></script>
<script>
var ctx = document.getElementById("myChart").getContext("2d");
// create dummt data
var labels = [];
var values = [];
for(var i=0;i<5000;i++){
labels.push("Label"+i)
values.push(Math.random()*30)
}
var chart = new Chart(ctx, {
// The type of chart we want to create
type: "bar",
// The data for our dataset
data: {
labels: labels,
datasets: [
{
label: "My First dataset",
backgroundColor: "rgb(255, 99, 132)",
borderColor: "rgb(255, 99, 132)",
data: values,
},
],
},
// Configuration options go here
options: {},
});
function getVals() {
// Get slider values
var parent = this.parentNode;
var slides = parent.getElementsByTagName("input");
var min = parseFloat(slides[0].value);
var max = parseFloat(slides[1].value);
// Neither slider will clip the other, so make sure we determine which is larger
if (min > max) {
var tmp = max;
max = min;
min = tmp;}
var label = [];
var value = [];
label = JSON.parse(JSON.stringify(labels)).slice(min, max);
//var datasets = Data.datasets;
// IF YOU HAVE MULTIPLE SERIESES
// ChartObj.data.labels = label;
// for (var i = 0; i < datasets.length; i++) {
// values = datasets[i].data.slice(min, max);
// ChartObj.data.datasets[i].data = values;
// }
// ChartObj.update();
value = JSON.parse(JSON.stringify(values)).slice(min, max);
chart.data.labels = label;
chart.data.datasets[0].data = value;
chart.update();
var displayElement = parent.getElementsByClassName("rangeValues")[0];
displayElement.innerHTML = "Min : " + min + " Max : " + max;
}
// Initialize Sliders
var sliderSections = document.getElementsByClassName("range-slider");
for (var x = 0; x < sliderSections.length; x++) {
var sliders = sliderSections[x].getElementsByTagName("input");
for (var y = 0; y < sliders.length; y++) {
if (sliders[y].type === "range") {
sliders[y].oninput = getVals;
sliders[y].max=JSON.parse(JSON.stringify(labels)).length;
// Manually trigger event first time to display values
sliders[y].oninput();
}
}
}
</script>
答案 3 :(得分:1)
所有这些答案都相当混乱和复杂。这就是我为项目所做的工作。每当数据集更改或容器大小更改时,我都只是调用fitChart()。
HTML:
<div class="chartWrapper">
<div class="chartContainer">
<canvas id="chart"></canvas>
</div>
</div>
CSS :(将宽度和高度设置为任意值)
div.chartWrapper {
position: relative;
overflow: auto;
width: 100%;
}
div.chartContainer {
position: relative;
height: 300px;
}
JS:
var xAxisLabelMinWidth = 15; // Replace this with whatever value you like
var myChart = new Chart(document.getElementById('chart').getContext('2d'), {
type: 'line',
data: {},
options: {
responsive: true,
maintainAspectRatio: false
}
});
function fitChart(){
var chartCanvas = document.getElementById('chart');
var maxWidth = chartCanvas.parentElement.parentElement.clientWidth;
var width = Math.max(mayChart.data.labels.length * xAxisLabelMinWidth, maxWidth);
chartCanvas.parentElement.style.width = width +'px';
}
答案 4 :(得分:0)
使用最新版本(2.4.0)对我有用:
HTML
<div style="width: 100%; overflow-x: auto;">
<div style="width: 3000px, height: 300px">
<canvas id="chart1" height="300" width="0"></canvas>
</div>
</div>
您还可以根据数据长度动态计算width
。例如,在VueJS中,您可以按照以下步骤进行操作(对于每个条目,请考虑30px
):
VueJS
<div style="width: 100%; overflow-x: auto;">
<div :style="{width: (this.data.length * 30) + 'px', height: '300px'}">
<canvas id="chart1" height="300" width="0"></canvas>
</div>
</div>
答案 5 :(得分:0)
<ion-content >
<div scrollX="true" scrollY="true" style="overflow:scroll; position:fixed; display:inline; top:0; right:0; bottom:0; left:0; white-space: nowrap;">
<canvas baseChart
[data]="barChartData"
[labels]="barChartLabels"
[options]="barChartOptions"
[colors]="lineChartColors"
[legend]="barChartLegend"
[chartType]="barChartType"
(chartHover)="chartHovered($event)"
(chartClick)="chartClicked($event)">
</canvas>
</div>
<button (click)="randomize()">Update</button>
</ion-content>
当我将画布宽度设置为700 px且滚动工作顺利时,它对我有用。
答案 6 :(得分:0)
要添加到以上Emma Louise的解决方案中(我不敢发表评论),我发现如果在绘制图像之前用某种颜色填充矩形,则覆盖画布是不透明的。这样,您就不必担心清除onProgress或onComplete矩形了。
targetCtx.fillStyle = 'white'
targetCtx.fillRect(0, 0, copyWidth * scale, copyHeight * scale);
另外,也许是因为我的devicePixelRatio是1,但是这两行使我图表中的文本变得模糊。删除它们时看起来还不错。
targetCtx.canvas.style.width = `${copyWidth}px`;
targetCtx.canvas.style.height = `${copyHeight}px`;