# 响应式图表

¥Responsive Charts

当涉及到根据窗口大小更改图表大小时,一个主要限制是画布渲染大小(canvas.width.height)无法用相对值表示,这与显示大小(canvas.style.width.height)相反。此外,这些尺寸彼此独立,因此画布渲染尺寸不会根据显示尺寸自动调整,从而导致渲染不准确。

¥When it comes to changing the chart size based on the window size, a major limitation is that the canvas render size (canvas.width and .height) can not be expressed with relative values, contrary to the display size (canvas.style.width and .height). Furthermore, these sizes are independent of each other and thus the canvas render size does not adjust automatically based on the display size, making the rendering inaccurate.

以下示例不起作用:

¥The following examples do not work:

  • <canvas height="40vh" width="80vw">:值无效,画布不会调整大小 (示例 (opens new window))

    ¥<canvas height="40vh" width="80vw">: invalid values, the canvas doesn't resize (example (opens new window))

  • <canvas style="height:40vh; width:80vw">:无效行为,画布调整大小但变得模糊(示例 (opens new window)

    ¥<canvas style="height:40vh; width:80vw">: invalid behavior, the canvas is resized but becomes blurry (example (opens new window))

  • <canvas style="margin: 0 auto;">:无效行为,画布不断缩小。Chart.js 需要为每个画布提供一个专用容器,并且应该在其中应用此样式。

    ¥<canvas style="margin: 0 auto;">: invalid behavior, the canvas continually shrinks. Chart.js needs a dedicated container for each canvas and this styling should be applied there.

Chart.js 提供了一个 几个选项 来启用响应并通过检测画布显示大小何时更改并相应地更新渲染大小来控制图表的调整大小行为。

¥Chart.js provides a few options to enable responsiveness and control the resize behavior of charts by detecting when the canvas display size changes and update the render size accordingly.

# 配置选项

¥Configuration Options

命名空间:options

¥Namespace: options

名称 类型 默认 描述
responsive boolean true 在其容器执行 (重要的提示...) 时调整图表画布的大小。
maintainAspectRatio boolean true 调整大小时保持原始画布纵横比 (width / height)
aspectRatio number 1|2 画布纵横比(即 width / height,值为 1 表示正方形画布)。请注意,如果高度明确定义为属性或通过样式,则忽略此选项。默认值因图表类型而异;径向图(圆环图、饼图、polarArea、雷达)默认为 1,其他默认为 2
onResize function null 发生调整大小时调用。获取传递的两个参数:图表实例和新尺寸。
resizeDelay number 0 将调整大小更新延迟给定的毫秒数。这可以通过消除元素更新的抖动来简化调整大小的过程。

# 重要的提示

¥Important Note

无法直接从 canvas 元素检测画布尺寸何时发生变化。Chart.js 使用其父容器来更新画布渲染和显示大小。然而,此方法要求容器相对定位并且仅专用于图表画布。然后可以通过设置容器大小 (示例 (opens new window)) 的相对值来实现响应:

¥Detecting when the canvas size changes can not be done directly from the canvas element. Chart.js uses its parent container to update the canvas render and display sizes. However, this method requires the container to be relatively positioned and dedicated to the chart canvas only. Responsiveness can then be achieved by setting relative values for the container size (example (opens new window)):

<div class="chart-container" style="position: relative; height:40vh; width:80vw">
    <canvas id="chart"></canvas>
</div>

图表也可以通过修改容器大小以编程方式调整大小:

¥The chart can also be programmatically resized by modifying the container size:

chart.canvas.parentNode.style.height = '128px';
chart.canvas.parentNode.style.width = '128px';

请注意,为了使上述代码正确调整图表高度,还必须将 maintainAspectRatio 选项设置为 false

¥Note that in order for the above code to correctly resize the chart height, the maintainAspectRatio option must also be set to false.

# 打印可调整大小的图表

¥Printing Resizable Charts

CSS 媒体查询允许在打印页面时更改样式。从这些媒体查询应用的 CSS 可能会导致图表需要调整大小。但是,调整大小不会自动发生。要支持打印时调整图表大小,你需要挂接 onbeforeprint (opens new window) 事件并手动触发调整每个图表的大小。

¥CSS media queries allow changing styles when printing a page. The CSS applied from these media queries may cause charts to need to resize. However, the resize won't happen automatically. To support resizing charts when printing, you need to hook the onbeforeprint (opens new window) event and manually trigger resizing of each chart.

function beforePrintHandler () {
    for (let id in Chart.instances) {
        Chart.instances[id].resize();
    }
}

你可能还会发现,由于浏览器布局文档以供打印以及触发调整大小事件的复杂性,Chart.js 无法针对打印布局正确调整大小。要解决此问题,你可以将显式大小传递给 .resize(),然后使用 onafterprint (opens new window) 事件在完成后恢复自动大小。

¥You may also find that, due to complexities in when the browser lays out the document for printing and when resize events are fired, Chart.js is unable to properly resize for the print layout. To work around this, you can pass an explicit size to .resize() then use an onafterprint (opens new window) event to restore the automatic size when done.

window.addEventListener('beforeprint', () => {
  myChart.resize(600, 600);
});
window.addEventListener('afterprint', () => {
  myChart.resize();
});