带有 svg 的堆叠条形图(无第 3 方库)
stacked barchart with svg (no 3rd party library)
我正在尝试使用 svg 和 html 创建堆叠条形图,但不使用任何第 3 方库。不幸的是,没有一个在线文档显示如何使用普通 svg 创建堆叠条形图。
我已经创建了一个 codepen,并且我正在实现那个堆叠条形图。谁能告诉我还需要什么才能使它成为堆叠条形图。
https://codepen.io/a166617/pen/qBXvzQd
这是我目前拥有的代码
const ReleaseScopeCharts = () => {
const data = [
{
name: 'Transit',
passed: 2,
skipped: 5,
failed: 22,
},
{
name: 'Access',
passed: 7,
skipped: 2,
failed: 11,
},
];
const width = 500;
const colors = ['#30D158', '#005EA7', '#FF453A'];
const entries = data.map((d) => ({
name: d.name,
total: ['passed', 'skipped', 'failed'].reduce((acc, key) => acc + d[key], 0),
bars: ['passed', 'skipped', 'failed'].map((key, i) => ({
value: d[key],
color: colors[i],
}))
.filter((bar) => bar.value),
}));
const rows = (entry) => entry.bars.map((bar, index) => {
const height = (bar.value / entry.total) * 100;
return (
<g key={index}>
<rect
width={50}
height={`${height}%`}
fill={bar.color}
x={index * 60} // multiply with the width (50) + 10 for space
/>
</g>
);
});
return (
<div className="new-card">
<div />
{entries.map((entry) => (
<>
{entry.name}
<svg viewBox={`0, 0, ${width}, ${500}`}
height={500}
width={width}
style={{ transform: `rotateX(180deg)` }}
>
{rows(entry)}
</svg>
</>
))}
</div>
);
};
对于堆叠条形图,我的意思是显示一个在另一个之上。
要堆叠条形图,您需要计算当前列和 space 宽度。将 svg 包装成 div,同时将 text 偏移到 div 并以 display:flex
.
为中心
将 y 键添加到 bars,其中:
- 起点=通过=0
- 中点=跳过=通过值
- 终点=失败=传递值+跳过值
y: key === 'passed' ? 0 : key === 'skipped' ? d['passed'] : d['skipped'] + d['passed'],
// Basic style
const newCardStyle = {
display: 'flex',
};
const contentStyle = {
display: 'flex',
flexFlow: 'column',
alignItems: 'center',
};
// multiply 50 (width) * 3 (columns) + 10 (space width) * 2 ( space between columns)
const width = 50 * 3 + 10 * 3;
function App() {
const data = [
{
name: 'Transit',
passed: 2,
skipped: 5,
failed: 22,
},
{
name: 'Access',
passed: 7,
skipped: 2,
failed: 11,
},
];
// Basic style
const newCardStyle = {
display: 'flex',
};
const contentStyle = {
display: 'flex',
flexFlow: 'column',
alignItems: 'center',
};
// multiply 50 (width) * 3 (columns) + 10 (space width) * 2 ( space between columns)
const width = 50 * 3 + 10 * 3;
const colors = ['#30D158', '#005EA7', '#FF453A'];
const entries = data.map(d => ({
name: d.name,
total: ['passed', 'skipped', 'failed'].reduce(
(acc, key) => acc + d[key],
0
),
bars: ['passed', 'skipped', 'failed']
.map((key, i) => ({
value: d[key],
color: colors[i],
y:
key === 'passed'
? 0
: key === 'skipped'
? d['passed']
: d['skipped'] + d['passed'],
}))
.filter(bar => bar.value),
}));
const rows = entry => {
return entry.bars.map((bar, index) => {
const height = (bar.value / entry.total) * 100;
const y = (bar.y / entry.total) * 100;
return (
<g key={Math.random()}>
<rect
width={50}
height={`${height}%`}
fill={bar.color}
x={60} // multiply with the width (50) + 10 for space
y={`${y}%`}
/>
</g>
);
});
};
return (
<div className="new-card" style={newCardStyle}>
{entries.map(entry => (
<div style={contentStyle} key={Math.random()}>
<svg
viewBox={`0, 0, ${width}, ${500}`}
height={500}
width={width}
style={{ transform: `rotateX(180deg)` }}
>
{rows(entry)}
</svg>
{entry.name}
</div>
))}
</div>
);
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
<script src="https://unpkg.com/react@17/umd/react.production.min.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@17/umd/react-dom.production.min.js" crossorigin></script>
<div id="root"></div>
我正在尝试使用 svg 和 html 创建堆叠条形图,但不使用任何第 3 方库。不幸的是,没有一个在线文档显示如何使用普通 svg 创建堆叠条形图。
我已经创建了一个 codepen,并且我正在实现那个堆叠条形图。谁能告诉我还需要什么才能使它成为堆叠条形图。
https://codepen.io/a166617/pen/qBXvzQd
这是我目前拥有的代码
const ReleaseScopeCharts = () => {
const data = [
{
name: 'Transit',
passed: 2,
skipped: 5,
failed: 22,
},
{
name: 'Access',
passed: 7,
skipped: 2,
failed: 11,
},
];
const width = 500;
const colors = ['#30D158', '#005EA7', '#FF453A'];
const entries = data.map((d) => ({
name: d.name,
total: ['passed', 'skipped', 'failed'].reduce((acc, key) => acc + d[key], 0),
bars: ['passed', 'skipped', 'failed'].map((key, i) => ({
value: d[key],
color: colors[i],
}))
.filter((bar) => bar.value),
}));
const rows = (entry) => entry.bars.map((bar, index) => {
const height = (bar.value / entry.total) * 100;
return (
<g key={index}>
<rect
width={50}
height={`${height}%`}
fill={bar.color}
x={index * 60} // multiply with the width (50) + 10 for space
/>
</g>
);
});
return (
<div className="new-card">
<div />
{entries.map((entry) => (
<>
{entry.name}
<svg viewBox={`0, 0, ${width}, ${500}`}
height={500}
width={width}
style={{ transform: `rotateX(180deg)` }}
>
{rows(entry)}
</svg>
</>
))}
</div>
);
};
对于堆叠条形图,我的意思是显示一个在另一个之上。
要堆叠条形图,您需要计算当前列和 space 宽度。将 svg 包装成 div,同时将 text 偏移到 div 并以 display:flex
.
将 y 键添加到 bars,其中:
- 起点=通过=0
- 中点=跳过=通过值
- 终点=失败=传递值+跳过值
y: key === 'passed' ? 0 : key === 'skipped' ? d['passed'] : d['skipped'] + d['passed'],
// Basic style
const newCardStyle = {
display: 'flex',
};
const contentStyle = {
display: 'flex',
flexFlow: 'column',
alignItems: 'center',
};
// multiply 50 (width) * 3 (columns) + 10 (space width) * 2 ( space between columns)
const width = 50 * 3 + 10 * 3;
function App() {
const data = [
{
name: 'Transit',
passed: 2,
skipped: 5,
failed: 22,
},
{
name: 'Access',
passed: 7,
skipped: 2,
failed: 11,
},
];
// Basic style
const newCardStyle = {
display: 'flex',
};
const contentStyle = {
display: 'flex',
flexFlow: 'column',
alignItems: 'center',
};
// multiply 50 (width) * 3 (columns) + 10 (space width) * 2 ( space between columns)
const width = 50 * 3 + 10 * 3;
const colors = ['#30D158', '#005EA7', '#FF453A'];
const entries = data.map(d => ({
name: d.name,
total: ['passed', 'skipped', 'failed'].reduce(
(acc, key) => acc + d[key],
0
),
bars: ['passed', 'skipped', 'failed']
.map((key, i) => ({
value: d[key],
color: colors[i],
y:
key === 'passed'
? 0
: key === 'skipped'
? d['passed']
: d['skipped'] + d['passed'],
}))
.filter(bar => bar.value),
}));
const rows = entry => {
return entry.bars.map((bar, index) => {
const height = (bar.value / entry.total) * 100;
const y = (bar.y / entry.total) * 100;
return (
<g key={Math.random()}>
<rect
width={50}
height={`${height}%`}
fill={bar.color}
x={60} // multiply with the width (50) + 10 for space
y={`${y}%`}
/>
</g>
);
});
};
return (
<div className="new-card" style={newCardStyle}>
{entries.map(entry => (
<div style={contentStyle} key={Math.random()}>
<svg
viewBox={`0, 0, ${width}, ${500}`}
height={500}
width={width}
style={{ transform: `rotateX(180deg)` }}
>
{rows(entry)}
</svg>
{entry.name}
</div>
))}
</div>
);
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
<script src="https://unpkg.com/react@17/umd/react.production.min.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@17/umd/react-dom.production.min.js" crossorigin></script>
<div id="root"></div>