Skip to content
Advertisement

React with Svg vertical stacked barchart (no third party library)

I have below piece of code. I am using React and svg for bar charts. I am not using any third party library for charts. With this below piece of code, i am able to get the bar charts. But the issue is that my bar charts show horizontally, I want to show it vertically. I am not able to figure out how to get this same piece of code working for a vertical bar chart.

I saw one video online https://egghead.io/lessons/javascript-build-a-bar-chart-with-svg-from-scratch-with-react This guy is able to achieve the bar chart vertically. I am not sure where i am going wrong in displaying it. Any changes i do or try, it always show horizontal bar chart.

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>
)}

Can someone please help me figure out where i went wrong.

Advertisement

Answer

User contributions licensed under: CC BY-SA
9 People found this is helpful
Advertisement