Chart.js 画布大小调整

106
在(Android WebView HTML5 canvas error)中,我发布了一个有关使用Graph.js库绘制图形的问题。 我现在遇到的问题是,如果我多次调用绘制图形的函数,画布会每次重新调整大小。每次将图形重新绘制到同一画布上时,它的大小也会发生变化。 我还尝试设置画布的大小,但没有成功。
可能的原因是什么?为什么画布每次都重新调整大小呢?
19个回答

215

这个问题困扰了我很久,因为即使在鼠标悬停时我的折线图看起来很糟糕,但我找到了一种更简单的方法,希望能有所帮助 :)

请使用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,

感谢@NoFlag的回答。 对我来说,无论如何都无法将高度和宽度属性应用于画布。如果有人在这里寻找调整画布大小的解决方案,请尝试将响应设置为true。
  • Chart.defaults.global.responsive = false *
- sghosh968
19
别忘了,为了让这种方法正常工作,你需要将画布放置在一个 <div> 中,并在该 <div> 上设置高度和/或宽度,而不是在画布上设置。 - totymedli
2
这些标志现在默认设置为“true”,因此您无需更改它们:http://www.chartjs.org/docs/latest/general/responsive.html - João Pimentel Ferreira
除此之外,还要设置画布的宽度和高度。这样就可以正常工作了。谢谢。 - Mazhar MIK
在我的情况下,调用图表的更新方法效果更好;由于其他原因必须关闭响应式,因此无法使用这个本来不错的解决方案。+1 +alt:答案 :-) - flowtron
现在它运行良好。谢谢。 - Jomal Johny

67

现在发生的情况是Chart.js在调用时会将画布的大小加倍,然后尝试使用CSS将其缩小,目的是为了为高分辨率设备提供更高分辨率的图表。

问题是它没有意识到自己已经这样做过了,因此当连续调用时,它会再次将已经(加倍或其他)大小乘以某个因子,直到出现问题。(实际上正在发生的是它正在检查是否应该通过更改宽度和高度的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);

1
我遇到了这个错误:未捕获的引用错误:doughnutData未定义。 - Du-Lacoste
15
嗯,是的,那只是一个占位符变量,因为我不知道你试图绘制什么数据。 - jcmiller11

29

这对我有用:

<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标签中设置画布的大小。


同意!只需将画布放置在 div 中,然后确保“响应式”选项不为 false(默认为 true)。然后将尺寸规则应用于 div 即可。 - NoelB

23
在IOS和Android中,当你滚动网页时,浏览器会隐藏工具栏,从而改变窗口大小,进而导致chartjs调整图形的大小。解决方法是保持纵横比例。
var options = { 
    responsive: true,
    maintainAspectRatio: true
}

这应该能解决你的问题。


13

在这里,我不得不使用多个答案的组合,并进行一些微调。

首先,必须将画布元素包裹在块级容器中。我告诉你,不要让画布元素有任何兄弟姐妹;让它成为孤独的孩子,因为它是 固执己见被宠坏了。(包装器可能不需要放置任何尺寸限制,但出于安全考虑,最好对其应用最大高度。)

确认满足上述条件后,在启动图表时,请确保使用以下选项:

var options = { 
    "responsive": true,
    "maintainAspectRatio": false
}
如果你想要调整图表的高度,请在画布元素层级进行操作。
<canvas height="500"></canvas>

不要试图以任何其他方式处理孩子。这应该会产生一个令人满意且正确布置的图表,使其在婴儿床上保持安静。


6
如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); 
}

抱歉,你能解释一下这是如何工作的吗?例如我打开一个页面然后画布有一个大小,但是如果我调整窗口的大小,画布将会有不同的大小(并且我假定我不需要原始大小,因为那是针对先前窗口大小的)? - kiradotee

4

我遇到了类似的问题并找到了你的答案...最终我找到了解决方法。

看起来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元素的大小,引起重新调整大小。

希望这能有所帮助!


2
我也曾遇到过同样的问题。我通过设置选项来解决它:

将选项设置为:

responsive: false,
maintainAspectRatio: true,
showScale: false,

在CSS中,将容器div的宽度设置为与画布相同:

并在HTML中使用canvas标签来创建画布。

    #canvasContainer { 
      width: 300px;
    }
    
    canvas {
      width: 300px;
    }


2

Chart.js -- 版本 4.3.0

在调整大小时,设置具有响应性的图表的最简单方法是:

const ctx = document.getElementById('chart');
    
const handleResize = (chart) => {
chart.resize();
}

new Chart(ctx, {
   type: 'bar',
   data: {
       labels: ['Red', 'Blue', 'Yellow', 'Green', 'Purple', 'Orange'],
       datasets: [{
         label: '# of Votes',
         data: [12, 19, 3, 5, 2, 3],
         borderWidth: 1
       }]
   },
   options: {
      responsive: true,
      onResize: handleResize,
      maintainAspectRatio: false
   }
});
.chart-parent{
   position: relative;
   width: 90vw;
   height: 90vh;
}
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.3.0/dist/chart.umd.min.js"></script>

<div class="chart-parent">
   <canvas id="chart"></canvas>
</div>

请注意:我只是以width: 90vw和height 90vh作为示例。您可以根据需要进行调整。 Boilerplate Template是从Chart.js文档中使用的。

当我尝试使用Chart.js v4.3.0时,我遇到了堆栈溢出的问题。这是有道理的,因为你的代码在onResize()函数中调用了chart.resize(),导致进入了循环。 - infografnet
@infografnet 分享你的代码。我提到的代码完全正常工作。你可以测试一下。你之所以出现堆栈溢出是因为其他原因。请分享你的代码。 - Developer
没有意义... - undefined

1
我尝试使用jQuery调整画布大小,但效果不佳。如果您想要在悬停时缩放到特定级别,我认为CSS3是最好的选择。
以下是其他codepan链接中的悬停选项:
.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);
}

请访问我的CodePen链接:

https://codepen.io/hitman0775/pen/XZZzqN


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接