我正在开发一个 React 项目,我需要在网格布局的父组件内显示 Chart.js 图表。图表应根据其父容器调整大小,同时保持固定的长宽比 3.5:1(宽度:高度)。但是,我正在努力使图表具有响应性,而不对其尺寸进行硬编码。
这是我当前的设置:
父组件
<div className="graph_container">
<h4>{title}</h4>
<div className="graph_container_graph">
<DynamicLineChart data={data} key={JSON.stringify(data)} />
</div>
</div>
父组件的样式
.graph_container {
width: 100%;
max-width: fit-content;
border-radius: 1.27rem;
background-color: #fff;
padding: 0.95rem;
display: flex;
flex-direction: column;
gap: 0.63rem;
font-size: 1.4rem;
}
.graph_container_graph {
padding: 0 0.95rem;
}
动态折线图组件
import React, { useEffect } from 'react';
import { Line } from 'react-chartjs-2';
import { Chart as ChartJS, CategoryScale, LinearScale, PointElement, LineElement, Title, Tooltip, Legend } from 'chart.js';
ChartJS.register(CategoryScale, LinearScale, PointElement, LineElement, Title, Tooltip, Legend);
const DynamicLineChart = ({ data }) => {
const chartData = {
labels: Object.keys(data),
datasets: [
{
data: Object.values(data),
fill: false,
backgroundColor: '#FFF',
borderColor: '#6497FC',
borderWidth: 3,
pointBackgroundColor: '#4D5C92',
pointBorderColor: '#4D5C92',
pointRadius: 5,
pointHoverRadius: 5,
},
],
};
const options = {
aspectRatio: 3.5,
maintainAspectRatio: true,
layout: {
padding: {},
},
plugins: {
legend: {
display: false,
},
tooltip: {
enabled: true,
},
},
scales: {
x: {
grid: {
borderDash: [15, 5],
color: '#CDD1DB',
borderColor: '#CDD1DB',
},
ticks: {
color: '#6B7280',
font: {
size: 10,
},
},
},
y: {
min: 0,
max: 100,
ticks: {
font: {
size: 10,
},
stepSize: 25,
color: '#6B7280',
},
grid: {
display: false,
},
},
},
};
return (
<div style={{ width: '100%', height: 'auto' }}>
<Line data={chartData} options={options} />
</div>
);
};
export default DynamicLineChart;
**问题**是,目前,图表没有响应,除非我对其宽度和高度进行硬编码。我希望图表根据其父容器的宽度调整大小,保持纵横比为 3.5:1。我怎样才能实现这个目标?
我尝试过的
maintainAspectRatio
设置为 true。Line
组件包装在具有基于百分比的宽度的 div 中。我需要图表根据父容器动态调整其宽度,同时保持高度与宽度成比例,纵横比为3.5:1。
任何帮助或建议将不胜感激!
通过查看您的图表选项,我想说图表应该具有响应能力, 因为选项
responsive: true
已打开(默认情况下如此);
这意味着图表将根据容器 div 调整其大小。
没有可运行的示例 无法确定,但我认为很可能正在发生的事情 是容器 div 没有按照您的预期调整大小。
考虑一下:
aspectRatio: 3.5
处完美地填充了容器 - 因为容器
有 height: auto
) 将收缩,容器的高度 (auto
) 将随之收缩,并且
减少,图表总是完美地填充容器。100%
)将跟随并增加相同的值。然而现在,
容器的高度没有理由增加,它将保持不变,并且
图表,受容器高度限制根本不会改变,创建
没有反应的样子以下代码片段使用您发布的部分代码,说明了这种动态:
const data = {
labels: Array.from({length: 12}, (_, i)=>'L'+(i+1)),
datasets: [{
data: Array.from({length: 12}, ()=>5+90*Math.random()),
fill: false,
backgroundColor: '#FFF',
borderColor: '#6497FC',
borderWidth: 3,
pointBackgroundColor: '#4D5C92',
pointBorderColor: '#4D5C92',
pointRadius: 5,
pointHoverRadius: 5,
}]
};
const options = {
aspectRatio: 3.5,
maintainAspectRatio: true,
layout: {
padding: {},
},
plugins: {
legend: {
display: false,
},
tooltip: {
enabled: true,
},
},
scales: {
x: {
grid: {
borderDash: [15, 5],
color: '#CDD1DB',
borderColor: '#CDD1DB',
},
ticks: {
color: '#6B7280',
font: {
size: 10,
},
},
},
y: {
min: 0,
max: 100,
ticks: {
font: {
size: 10,
},
stepSize: 25,
color: '#6B7280',
},
grid: {
display: false,
},
},
},
};
new Chart('myChart', {type: 'line', options, data});
const containerEl = document.querySelector('#container'),
container2El = document.querySelector('#containerOfContainer'),
chartEl = document.querySelector('#myChart'),
textarea = document.querySelector('textarea'),
shrinkBut = document.querySelector('#shrink'),
enlargeBut = document.querySelector('#enlarge');
let count = 1;
function updateTextArea(){
const idx = (count < 10 ? ' ' : '') + count++,
wCont = containerEl.offsetWidth,
hCont = containerEl.offsetHeight,
wChart = chartEl.offsetWidth,
hChart = chartEl.offsetHeight;
textarea.value = `${idx}. h = ${hCont} w = ${wCont} (div) | h = ${hChart} w = ${wChart} (chart)\n` + textarea.value;
}
let wInt = 3;
shrinkBut.onclick = function(){
disableButtons();
container2El.style.width = (container2El.offsetWidth - 30)+'px';
wInt--;
setTimeout(()=>{enableButtons(); updateTextArea();}, 1000);
}
enlargeBut.onclick = function(){
disableButtons();
container2El.style.width = (container2El.offsetWidth + 30)+'px';
wInt++;
setTimeout(()=>{enableButtons(); updateTextArea();}, 1000);
}
function disableButtons(){
shrinkBut.setAttribute('disabled', 'd');
enlargeBut.setAttribute('disabled', 'd');
}
function enableButtons(){
if(wInt > 0){
shrinkBut.removeAttribute('disabled');
}
if(wInt < 3){
enlargeBut.removeAttribute('disabled');
}
}
updateTextArea();
<div id="containerOfContainer" style="width: 90vw; border: 1px solid black">
<div id="container" style="width: 100%; height: auto; border:1px solid red">
<canvas style="border:1px solid blue" id="myChart"></canvas>
</div>
</div>
<button id="shrink">Shrink</button> <button id="enlarge" disabled>Enlarge</button>
<br/> Container sizes (<strong>most recent on top</strong>) <br/>
<textarea style="width: 70ex; height: 10ex"></textarea>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
在这种情况下,解决方案是使用容器 div 的 css - 将
height
属性替换为 aspect-ratio
。
我最初认为 aspectRatio
Chart.js 属性指的是图表区域;
然而,在多次尝试计算理想的容器纵横比之后,
我意识到实际上明确说明了什么
文档
它指的是画布。这大大简化了事情,因为什么并不重要
图表画布包含,右侧是否有图例或顶部是否有标题等。理想的
容器的css和图表的aspectRatio
一样,解决办法是
<div style={{ width: '100%', aspectRatio: 3.5 }}>
<Line data={chartData} options={options} />
</div>
这是经过修改的上述片段:
const data = {
labels: Array.from({length: 12}, (_, i)=>'L'+(i+1)),
datasets: [{
data: Array.from({length: 12}, ()=>5+90*Math.random()),
fill: false,
backgroundColor: '#FFF',
borderColor: '#6497FC',
borderWidth: 3,
pointBackgroundColor: '#4D5C92',
pointBorderColor: '#4D5C92',
pointRadius: 5,
pointHoverRadius: 5,
}]
};
const options = {
aspectRatio: 3.5,
maintainAspectRatio: true,
layout: {
padding: {},
},
plugins: {
legend: {
display: false,
},
tooltip: {
enabled: true,
},
},
scales: {
x: {
grid: {
borderDash: [15, 5],
color: '#CDD1DB',
borderColor: '#CDD1DB',
},
ticks: {
color: '#6B7280',
font: {
size: 10,
},
},
},
y: {
min: 0,
max: 100,
ticks: {
font: {
size: 10,
},
stepSize: 25,
color: '#6B7280',
},
grid: {
display: false,
},
},
},
};
new Chart('myChart', {type: 'line', options, data});
const containerEl = document.querySelector('#container'),
container2El = document.querySelector('#containerOfContainer'),
chartEl = document.querySelector('#myChart'),
textarea = document.querySelector('textarea'),
shrinkBut = document.querySelector('#shrink'),
enlargeBut = document.querySelector('#enlarge');
let count = 1;
function updateTextArea(){
const idx = (count < 10 ? ' ' : '') + count++,
wCont = containerEl.offsetWidth,
hCont = containerEl.offsetHeight,
wChart = chartEl.offsetWidth,
hChart = chartEl.offsetHeight;
textarea.value = `${idx}. h = ${hCont} w = ${wCont} (div) | h = ${hChart} w = ${wChart} (chart)\n` + textarea.value;
}
let wInt = 3;
shrinkBut.onclick = function(){
disableButtons();
container2El.style.width = (container2El.offsetWidth - 30)+'px';
wInt--;
setTimeout(()=>{enableButtons(); updateTextArea();}, 1000);
}
enlargeBut.onclick = function(){
disableButtons();
container2El.style.width = (container2El.offsetWidth + 30)+'px';
wInt++;
setTimeout(()=>{enableButtons(); updateTextArea();}, 1000);
}
function disableButtons(){
shrinkBut.setAttribute('disabled', 'd');
enlargeBut.setAttribute('disabled', 'd');
}
function enableButtons(){
if(wInt > 0){
shrinkBut.removeAttribute('disabled');
}
if(wInt < 3){
enlargeBut.removeAttribute('disabled');
}
}
updateTextArea();
<div id="containerOfContainer" style="width: 90vw; border: 1px solid black">
<div id="container" style="width: 100%; aspect-ratio: 3.5; border:1px solid red">
<canvas style="border:1px solid blue" id="myChart"></canvas>
</div>
</div>
<button id="shrink">Shrink</button> <button id="enlarge" disabled>Enlarge</button>
<br/> Container sizes (<strong>most recent on top</strong>) <br/>
<textarea style="width: 70ex; height: 10ex"></textarea>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>