与 Svg 垂直堆叠条形图反应(无第三方库)
Posted
技术标签:
【中文标题】与 Svg 垂直堆叠条形图反应(无第三方库)【英文标题】:React with Svg vertical stacked barchart (no third party library) 【发布时间】:2021-07-20 10:09:06 【问题描述】:我有以下代码。我将 React 和 svg 用于条形图。我没有使用任何第三方库来制作图表。使用下面的这段代码,我可以获得条形图。但问题是我的条形图水平显示,我想垂直显示。我无法弄清楚如何让同一段代码用于垂直条形图。
我在网上看到一个视频https://egghead.io/lessons/javascript-build-a-bar-chart-with-svg-from-scratch-with-react 这家伙能够垂直实现条形图。我不确定我在显示它时哪里出错了。我所做或尝试的任何更改,它总是显示水平条形图。
export const ReleaseScopeCharts = () =>
const data = [
"name": "Transit",
"passed": 2,
"skipped": 5,
"failed": 22,
,
"name": "Access",
"passed": 7,
"skipped": 2,
"failed": 11,
]
const fontSize=14
const width=1000
const rowHeight=40
const colors = ["#30D158", "#005EA7", "#FF453A"];
const entries = data.map((d) => (
name: d.name,
total: d.total,
bars: ["passed", "skipped", "failed"].map((key, i) => (
value: d[key],
portion: d[key] / 29,
color: colors[i]
))
.filter((bar) => bar.value)
))
const heightPerRow = rowHeight;
const canvasHeight = entries.length * heightPerRow;
const canvasWidth = width;
const labelWidth = canvasWidth / 4;
const plotWidth = canvasWidth - labelWidth;
const verticalPadding = heightPerRow / 2;
const barHeight = heightPerRow - verticalPadding;
const horizontalPadding = 0;
const rows = entries.map((entry, i) =>
const widths = entry.bars.map((bar) => plotWidth * bar.portion)
const offsets = entry.bars.map((bar, i, array) =>
const previous = array.slice(0, i);
const offset = previous.map((bar) => bar.portion)
.reduce((a, b) => a + b, 0)
return offset + bar.portion / 2
)
const bars = entry.bars.map((bar, i) =>
const barWidth = widths[i] - horizontalPadding;
return (<g key=i transform=`translate($plotWidth * offsets[i], $heightPerRow / 2)`>
<rect
rx=barHeight / 2 ry=barHeight / 2 width=barWidth height=barHeight fill=bar.color x=-barWidth / 2 y=-barHeight / 2 />
<text fill="#fff" fontSize=fontSize textAnchor="middle" alignmentBaseline="middle">bar.value</text>
</g>)
)
return (
<g key=i transform=`translate($labelWidth,$heightPerRow * i)`>
<g transform=`translate($-labelWidth, $heightPerRow / 2)`>
<text
fontSize=fontSize
textAnchor="start"
alignmentBaseline="middle">entry.name</text>
</g>
bars
</g>
)
)
return (
<div className="new-card">
<div>
</div>
<svg viewBox=`0, 0, $canvasWidth, $canvasHeight`
height=canvasHeight
width=canvasWidth
>
rows
</svg>
</div>
)
谁能帮我弄清楚我哪里出错了。
【问题讨论】:
你应该有一个固定的宽度和高度应该是你的计算。你做的完全相反。此外,您还需要基于 % 的高度并为不同的图表呈现不同的 svg。 @Yadab 可能是对的。我试图翻转这些值,但 xP 一无所获。无论如何,我玩了一点,得到了一个垂直的图表——不一样,它非常 WIP,但它是垂直的 -> codesandbox.io/s/… 。也许会有所帮助或提供一些想法,不幸的是我今天不能继续,这是一个有趣的“任务” @Yadab - 如果可以,请分享一个工作示例 【参考方案1】:我刚刚为您解决了这个问题。您可以进行其余的计算。
export 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>
);
;
【讨论】:
谢谢@Yadab。上面的代码提供了分组的垂直条形图。你能指出堆积条形图应该做的改变吗? 你想要这样的东西吗? stackblitz.com/edit/… @Yadab- No.. 实际上,在 tat 示例中,2010 年和 2011 年被并排分组,分别用于德国和美国。我希望 2010 年和 2011 年彼此重叠。所以德国是单条,美国是单条。 喜欢这个? stackblitz.com/edit/… 知道了,您想在一个栏中显示通过、跳过和失败?实现它需要一点时间。我今天休息。明天会看到这个。【参考方案2】:我将稍微断章取意地显示一个条形结果 - 可以在 SVG 中添加更多“条形”,这将留给您。
注意重要部分是<rect width="20" height="75" y="25"></rect>
,其中width
和height
显示栏的“大小”。
为了好玩,我添加了一些鼠标悬停的 CSS。
.bar
fill: lime;
/* changes the background */
height: 10rem;
transition: fill .3s ease;
cursor: pointer;
font-family: Helvetica, sans-serif;
.bar text
color: black;
font-size: 0.75rem;
.bar:hover,
.bar:focus
fill: blue;
.bar:hover text,
.bar:focus text
fill: red;
<svg class="chart" aria-labelledby="title desc" role="img">
<title id="title">A single bar chart</title>
<desc id="desc">FunBar day</desc>
<g class="bar">
<rect y="25"></rect>
<text x="0" y="115" dy=".25em">Fun</text>
</g>
<g class="bar">
<rect y="75" x="30"></rect>
<text x="30" y="115" dy=".25em">Goat</text>
</g>
</svg>
【讨论】:
这更多的是静态数据,并没有展示如何使用堆积图。你能帮我处理我上面分享的数据吗?以上是关于与 Svg 垂直堆叠条形图反应(无第三方库)的主要内容,如果未能解决你的问题,请参考以下文章
Python使用matplotlib绘制柱状图(bar plot)实战:水平条形图垂直条形图分组条形图堆叠条形图