在(Android WebView HTML5 画布错误)中,我发布了一个关于使用 Graph.js 库绘制图形的问题。我现在遇到的问题是,如果我多次调用该函数来绘制图形,则画布每次都会调整大小。每次将图形重新绘制到同一画布上时,其大小也会发生变化。我也尝试设置画布的大小,但没有成功。
可能是什么原因?为什么画布每次都会调整大小?
在(Android WebView HTML5 画布错误)中,我发布了一个关于使用 Graph.js 库绘制图形的问题。我现在遇到的问题是,如果我多次调用该函数来绘制图形,则画布每次都会调整大小。每次将图形重新绘制到同一画布上时,其大小也会发生变化。我也尝试设置画布的大小,但没有成功。
可能是什么原因?为什么画布每次都会调整大小?
我有很多问题,因为毕竟我的线条图在鼠标悬停时看起来很糟糕,我找到了一种更简单的方法,希望它会有所帮助:)
使用这些 Chart.js 选项:
// Boolean - whether or not the chart should be responsive and resize when the browser does.
responsive: true,
// Boolean - whether to maintain the starting aspect ratio or not when responsive, if set to false, will take up entire container
maintainAspectRatio: false,
发生的情况是 Chart.js 在调用时将画布的大小倍增,然后尝试使用 CSS 将其缩小,目的是为高 dpi 设备提供更高分辨率的图形。
问题是它没有意识到它已经这样做了,所以当连续调用时,它会再次乘以已经(加倍或其他)大小,直到事情开始破裂。(实际发生的是检查是否应该通过更改宽度和高度的 DOM 属性来向画布添加更多像素,如果应该,将其乘以某个因子,通常是 2,然后更改它,然后更改 css 样式属性以在页面上保持相同的大小。)
例如,当你运行一次并且你的画布宽度和高度设置为 300 时,它会将它们设置为 600,然后将样式属性更改为 300...但是如果你再次运行它,它会看到 DOM 宽度和高度是 600(查看此问题的其他答案以了解原因),然后将其设置为 1200,并将 css 宽度和高度设置为 600。
不是最优雅的解决方案,但我解决了这个问题,同时保持视网膜设备的增强分辨率,只需在每次连续调用 Chart.js 之前手动设置画布的宽度和高度
var ctx = document.getElementById("canvas").getContext("2d");
ctx.canvas.width = 300;
ctx.canvas.height = 300;
var myDoughnut = new Chart(ctx).Doughnut(doughnutData);
这对我有用:
<body>
<form>
[...]
<div style="position:absolute; top:60px; left:10px; width:500px; height:500px;">
<canvas id="cv_values"></canvas>
<script type="text/javascript">
var indicatedValueData = {
labels: ["1", "2", "3"],
datasets: [
{
[...]
};
var cv_values = document.getElementById("cv_values").getContext("2d");
var myChart = new Chart(cv_values, { type: "line", data: indicatedValueData });
</script>
</div>
</form>
</body>
基本事实是我们必须在 div-tag 中设置画布的大小。
在 IOS 和 Android 中,浏览器会在您滚动时隐藏工具栏,从而改变窗口的大小,从而导致 chartjs 调整图形的大小。解决方案是保持纵横比。
var options = {
responsive: true,
maintainAspectRatio: true
}
这应该可以解决您的问题。
正如 jcmiller11 建议的那样,设置宽度和高度会有所帮助。一个更好的解决方案是在绘制图表之前检索画布的宽度和高度。然后使用这些数字在每次重新绘制图表时设置图表。这可以确保 javascript 代码中没有常量。
ctx.canvas.originalwidth = ctx.canvas.width;
ctx.canvas.originalheight = ctx.canvas.height;
function drawchart() {
ctx.canvas.width = ctx.canvas.originalwidth;
ctx.canvas.height = ctx.canvas.originalheight;
var chartctx = new Chart(ctx);
myNewBarChart = chartctx.Bar(data, chartSettings);
}
我不得不在这里使用多个答案的组合并进行一些小的调整。
首先,有必要将 canvas 元素包装在块级容器中。我对你说,不要让canvas元素有兄弟姐妹;让它成为一个孤独的孩子吧,因为它固执又被宠坏了。(包装器可能不需要对其施加任何尺寸限制,但为了安全起见,最好对其应用最大高度。)
在确保满足上述条件后,在启动图表时,请确保使用以下选项:
var options = {
"responsive": true,
"maintainAspectRatio": false
}
如果要调整图表的高度,请在画布元素级别进行。
<canvas height="500"></canvas>
不要试图以任何其他方式与孩子打交道。这应该会产生一个令人满意的、布局合理的图表,一个安静地呆在婴儿床里的图表。
我遇到了类似的问题并找到了您的答案。我最终找到了解决方案。
看起来 Chart.js 的来源具有以下内容(大概是因为它不应该在同一画布中重新渲染和完全不同的图形):
//High pixel density displays - multiply the size of the canvas height/width by the device pixel ratio, then scale.
if (window.devicePixelRatio) {
context.canvas.style.width = width + "px";
context.canvas.style.height = height + "px";
context.canvas.height = height * window.devicePixelRatio;
context.canvas.width = width * window.devicePixelRatio;
context.scale(window.devicePixelRatio, window.devicePixelRatio);
}
如果它被调用一次,这很好,但是当你多次重绘时,你最终会多次更改画布 DOM 元素的大小,从而导致重新调整大小。
希望有帮助!
我遇到了同样的问题。我能够通过设置选项来解决它:
responsive: false,
maintainAspectRatio: true,
showScale: false,
在css中,将容器div的宽度设置为与画布相同:
#canvasContainer {
width: 300px;
}
canvas {
width: 300px;
}
这是官方文档: https ://www.chartjs.org/docs/latest/general/responsive.html
无法直接从画布元素检测画布大小何时发生变化。Chart.js 使用其父容器来更新画布渲染和显示大小。但是,此方法要求容器相对定位并仅专用于图表画布。然后可以通过设置容器大小的相对值来实现响应性(示例):
<div class="chart-container" style="position: relative; height:40vh; width:80vw">
<canvas id="chart"></canvas>
</div>
我尝试使用 jQuery 调整画布大小,但效果不佳。我认为CSS3是您可以尝试的最佳选择,如果您想在某个级别进行悬停缩放。
以下来自其他代码盘链接的悬停选项:
.style_prevu_kit:hover{
z-index: 2;
-webkit-transition: all 200ms ease-in;
-webkit-transform: scale(1.5);
-ms-transition: all 200ms ease-in;
-ms-transform: scale(1.5);
-moz-transition: all 200ms ease-in;
-moz-transform: scale(1.5);
transition: all 200ms ease-in;
transform: scale(1.5);
}
按照我的代码盘链接:
如果有人遇到问题,我找到了一个不涉及牺牲响应能力等的解决方案。
只需将画布包装在 div 容器中(无样式),然后在调用 Chart 构造函数之前将 div 的内容重置为带有 ID 的空画布。
例子:
HTML:
<div id="chartContainer">
<canvas id="myChart"></canvas>
</div>
JS:
$("#chartContainer").html('<canvas id="myChart"></canvas>');
//call new Chart() as usual
我在使用 Angular CLI 时遇到了同样的缩放问题。能够通过从 index.html 中删除这一行来使其工作:
<script src="node_modules/chart.js/dist/Chart.bundle.min.js"></script>
然后在 angular-cli.json 文件的脚本部分中,使用以下命令:
"scripts": ["../node_modules/chart.js/dist/Chart.bundle.min.js"]
资料来源:mikebarr58
我在这个线程上尝试了多个答案,对我有用的是(注意我使用的是 reactjs),检查我以前传递给图表组件的道具。当我调整 DOM 的大小时,图表正在用空数据重新绘制。
componentDidUpdate(prevProps: ChartProps) { if(prevProps.data !== props.data) renderChart(); }
接受的 - responsive:true, maintainAspectRatio:false
- 不适用于我的场景。但我发现我们可以简单地调用update
图表上的方法。
所以我发现自己在 matchMedia 侦听器中调整值.. 像这样:
myRadarChart.options.scales.r.pointLabels.font.size = "1rem";
myRadarChart.update();
添加div
它会解决问题
<div style="position:absolute; top:50px; left:10px; width:500px; height:500px;"></div>
let canvasBox = ReactDOM.findDOMNode(this.refs.canvasBox);
let width = canvasBox.clientWidth;
let height = canvasBox.clientHeight;
let charts = ReactDOM.findDOMNode(this.refs.charts);
let ctx = charts.getContext('2d');
ctx.canvas.width = width;
ctx.canvas.height = height;
this.myChart = new Chart(ctx);