为 D3 React 中的每个栏设置栏颜色

Setting bar color for each bar in D3 React

我正在尝试制作一个条形图,每个条形都有不同的颜色。我已经根据答案尝试了几种方法来实现这一点,但出于某种原因,我似乎无法更改单个栏的颜色。我正在使用的代码会更改每个条形的颜色。如何设置多种颜色?

这是我试过的代码:

import React, { useEffect, useRef, useState } from 'react';
import * as d3 from 'd3';
import './BarChart.css';

const dataSet = [
    { category: 'Validation Pricing', quantity: 85 },
    { category: 'KC Validation', quantity: 15 }
];

const BarChart = () => {
    const d3Chart = useRef();
    const [dimensions, setDimensions] = useState({
        width: window.innerWidth,
        height: window.innerHeight
    });
    const update = useRef(false);

    useEffect(() => {
        // Listen for any resize event update
        window.addEventListener('resize', () => {
            setDimensions({
                width: window.innerWidth,
                height: window.innerHeight
            });

            // if resize, remove the previous chart
            if (update.current) {
                d3.selectAll('g').remove();
            } else {
                update.current = true;
            }
        });

        DrawChart(dataSet, dimensions);
    }, [dimensions]);

    const margin = { top: 50, right: 30, bottom: 30, left: 60 };

    const DrawChart = (data, dimensions) => {
        console.log(dimensions);

        const chartWidth = parseInt(d3.select('#d3RenewalChart').style('width')) - margin.left - margin.right;
        const chartHeight = parseInt(d3.select('#d3RenewalChart').style('height')) - margin.top - margin.bottom;

        const colors = ['#7fc97f', '#beaed4', '#fdc086', '#ffff99', '#386cb0', '#f0027f', '#bf5b17', '#666666'];

        const svg = d3
            .select(d3Chart.current)
            .attr('width', chartWidth + margin.left + margin.right)
            .attr('height', chartHeight + margin.top + margin.bottom);
        const x = d3
            .scaleBand()
            .domain(d3.range(data.length))
            .range([margin.left, chartWidth + margin.right])
            .padding(0.1);

        svg.append('g')
            .attr('transform', 'translate(0,' + chartHeight + ')')
            .call(
                d3
                    .axisBottom(x)
                    .tickFormat((i) => data[i].category)
                    .tickSizeOuter(0)
            );

        const max = d3.max(data, function (d) {
            return d.quantity;
        });

        const y = d3.scaleLinear().domain([0, 100]).range([chartHeight, margin.top]);

        svg.append('g')
            .attr('transform', 'translate(' + margin.left + ',0)')
            .call(d3.axisLeft(y));

        svg.append('g')
            .attr('fill', function (d, i, j) {
                console.log(d, j, i);
                return colors[i];
            })
            .selectAll('rect')
            .data(data)
            .join('rect')
            .attr('x', (d, i) => x(i))
            .attr('y', (d) => y(d.quantity))
            .attr('height', (d) => y(0) - y(d.quantity))
            .attr('width', x.bandwidth());
    };

    return (
        <div id="d3RenewalChart">
            <svg ref={d3Chart}></svg>
        </div>
    );
};

export default BarChart;

首先你设置父g的填充颜色:

svg.append('g')
   .attr('fill', function (d, i, j) {
      console.log(d, j, i);
       return colors[i];
    })

你只附加一个 g 所以上面的代码运行一次。更重要的是,父元素g的填充被子元素继承:

Transformations applied to the <g> element are performed on its child elements, and its attributes are inherited by its children. (docs).

然后,在设置 g 的样式后,向其附加一些矩形:

     [g].selectAll('rect')
        .data(data)
        .join('rect')
        .attr('x', (d, i) => x(i))
        .attr('y', (d) => y(d.quantity))
        .attr('height', (d) => y(0) - y(d.quantity))
        .attr('width', x.bandwidth());

但是,您没有对这些矩形应用填充:所以它们继承了父 g 填充,应该始终是 colors[0],这就是它们完全相同的原因。

而是在追加新的矩形后应用填充逻辑:

      svg.append('g')        
        .selectAll('rect')
        .data(data)
        .join('rect')
        .attr('x', (d, i) => x(i))
        .attr('y', (d) => y(d.quantity))
        .attr('height', (d) => y(0) - y(d.quantity))
        .attr('width', x.bandwidth())
        .attr('fill', function (d, i) {
            return colors[i];
         })