95

在(Android WebView HTML5 画布错误)中,我发布了一个关于使用 Graph.js 库绘制图形的问题。我现在遇到的问题是,如果我多次调用该函数来绘制图形,则画布每次都会调整大小。每次将图形重新绘制到同一画布上时,其大小也会发生变化。我也尝试设置画布的大小,但没有成功。

可能是什么原因?为什么画布每次都会调整大小?

4

16 回答 16

193

我有很多问题,因为毕竟我的线条图在鼠标悬停时看起来很糟糕,我找到了一种更简单的方法,希望它会有所帮助:)

使用这些 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,
于 2014-09-02T08:57:30.330 回答
64

发生的情况是 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);
于 2014-02-15T13:00:35.587 回答
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-tag 中设置画布的大小。

于 2016-08-30T11:27:02.957 回答
21

在 IOS 和 Android 中,浏览器会在您滚动时隐藏工具栏,从而改变窗口的大小,从而导致 chartjs 调整图形的大小。解决方案是保持纵横比。

var options = { 
    responsive: true,
    maintainAspectRatio: true
}

这应该可以解决您的问题。

于 2015-01-28T06:01:13.313 回答
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); 
}
于 2014-05-05T13:59:06.723 回答
5

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

首先,有必要将 canvas 元素包装在块级容器中。我对你说,不要canvas元素有兄弟姐妹;让它成为一个孤独的孩子吧,因为它固执被宠坏了。(包装器可能不需要对其施加任何尺寸限制,但为了安全起见,最好对其应用最大高度。)

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

var options = { 
    "responsive": true,
    "maintainAspectRatio": false
}

如果要调整图表的高度,请在画布元素级别进行。

<canvas height="500"></canvas>

不要试图以任何其他方式与孩子打交道。这应该会产生一个令人满意的、布局合理的图表,一个安静地呆在婴儿床里的图表。

于 2018-02-13T16:08:56.350 回答
3

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

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

希望有帮助!

于 2014-02-06T19:25:07.667 回答
2

我遇到了同样的问题。我能够通过设置选项来解决它:

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

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

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

于 2019-07-25T13:33:29.103 回答
1

这是官方文档: 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>
于 2021-03-02T12:28:40.637 回答
1

我尝试使用 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);
}

按照我的代码盘链接:

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

于 2018-02-20T05:22:10.480 回答
1

如果有人遇到问题,我找到了一个不涉及牺牲响应能力等的解决方案。

只需将画布包装在 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
于 2017-05-25T14:42:08.863 回答
0

我在使用 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

于 2017-05-08T09:06:24.817 回答
0

我在这个线程上尝试了多个答案,对我有用的是(注意我使用的是 reactjs),检查我以前传递给图表组件的道具。当我调整 DOM 的大小时,图表正在用空数据重新绘制。

componentDidUpdate(prevProps: ChartProps) { if(prevProps.data !== props.data) renderChart(); }
于 2021-05-12T14:03:45.273 回答
0

接受的 - responsive:true, maintainAspectRatio:false- 不适用于我的场景。但我发现我们可以简单地调用update图表上的方法。

所以我发现自己在 matchMedia 侦听器中调整值.. 像这样:

myRadarChart.options.scales.r.pointLabels.font.size = "1rem";
myRadarChart.update();
于 2021-07-15T14:30:34.737 回答
-3

添加div它会解决问题

<div style="position:absolute; top:50px; left:10px; width:500px; height:500px;"></div>
于 2019-05-15T05:25:19.180 回答
-6
 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);
于 2016-01-31T11:40:28.910 回答