【问题标题】:Aligning tick marks on an Area Chart with String X-Values将面积图上的刻度线与字符串 X 值对齐
【发布时间】:2019-03-05 19:27:53
【问题描述】:

我正在使用 D3 库构建面积图,并使用他们的 area chart 示例来帮助我构建它。但是,我没有沿 x 轴使用日期,而是使用字符串,因此我尝试使用他们的 bar chart 示例来帮助我处理 xAxis 及其值。

不过,由于这个原因,我的 x 轴刻度线在两个值点之间“居中”,而不是左对齐(见下图)。

当我尝试使用面积图示例构建 xAxis 时,我没有看到任何被填充的区域或沿 xAxis 的任何数据点。

如何移动刻度线以直接在数据点上对齐,而不是在两个不同的数据点之间居中?

这是我的代码在构建图表时的样子:

    sampleAreaData = [
        {"month": "Jun. 2018", "value": "2"},
        {"month": "Jul. 2018", "value": "12"},
        {"month": "Aug. 2018", "value": "33"},
        {"month": "Sept. 2018", "value": "100"},
        {"month": "Oct. 2018", "value": "150"},
        {"month": "Nov. 2018", "value": "368"},
        {"month": "Dec. 2018", "value": "404"},
        {"month": "Jan. 2019", "value": "482"},
        {"month": "Feb. 2019", "value": "559"},
    ]

    initializeSampleAreaGraph() {
        // Variables
        const svg = d3.select(this.template.querySelector('svg.sampleAreaGraph'));
        const width = this.svgSampleAreaWidth;
        const height = this.svgSampleAreaHeight;
        const margin = ({top: 20, right: 20, bottom: 30, left: 30});
        const x = d3.scaleBand()
            .domain(this.sampleAreaData.map(d => d.month))
            .range([margin.left, width - margin.right])
        const y = d3.scaleLinear()
            .domain([0, d3.max(this.sampleAreaData, d => d.value)]).nice()
            .range([height - margin.bottom, margin.top]);
        const xAxis = g => g
            .attr("transform", `translate(0,${height - margin.bottom})`)
            .call(d3.axisBottom(x).ticks(width / 80).tickSizeOuter(0));
        const yAxis = g => g
            .attr("transform", `translate(${margin.left},0)`)
            .call(d3.axisLeft(y))
            .call(g => g.select(".domain").remove())
            .call(g => g.select(".tick:last-of-type text").clone()
                .attr("x", 3)
                .attr("text-anchor", "start")
                .attr("font-weight", "bold")
                .text(this.sampleAreaData.month));
        const area = d3.area()
            .x(d => x(d.month))
            .y0(y(0))
            .y1(d => y(d.value));

        // SVG Construction
        svg.append("path")
            .attr("fill", "steelblue")
            .datum(this.sampleAreaData)
            .attr("d", area)
        svg.append("g")
            .call(xAxis);
        svg.append("g")
            .call(yAxis);
        return svg.node();
    }

【问题讨论】:

    标签: javascript d3.js salesforce-lightning


    【解决方案1】:

    嗯,有几件事你可以改进。 TL;博士;下面的代码。

    d3.scaleBand 将返回带中间的刻度,正如其名称所述。 下图是从d3 docs无耻复制过来的:

    如您所见,scaleBand 的目的是将轴分成偶数带。

    由于您已经有了某种时间信息,您可以尝试使用Date.parse(d.month) 解析它并传递此信息来构建您的域。

    我修改了您的 sn-p,使其可以在预览中使用,并评论了您的代码以进行其他一些改进。

    var sampleAreaData = [
            {"month": "Jun. 2018", "value": "2"},
            {"month": "Jul. 2018", "value": "12"},
            {"month": "Aug. 2018", "value": "33"},
            {"month": "Sept. 2018", "value": "100"},
            {"month": "Oct. 2018", "value": "150"},
            {"month": "Nov. 2018", "value": "368"},
            {"month": "Dec. 2018", "value": "404"},
            {"month": "Jan. 2019", "value": "482"},
            {"month": "Feb. 2019", "value": "559"},
        ];
    
        function initializeSampleAreaGraph() {
            // Variables
            // const svg = d3.select(this.template.querySelector('svg.sampleAreaGraph')); // no need to select a selection. d3.select is the same as a querySelector.
            const svg = d3.select('svg.sampleAreaGraph');
            const width = 500;
            const height = 500;
            const margin = ({top: 20, right: 20, bottom: 30, left: 30});
            const xScale = d3.scaleTime() // changed this to scaleBand
                .domain(d3.extent(sampleAreaData, function(d) { return Date.parse(d.month) })) // d3.extent return an array with min and max values
                .range([margin.left, width - margin.right]);
            const yScale = d3.scaleLinear()
                .domain([0, d3.max(sampleAreaData, d => d.value)])
                .nice()
                .range([height - margin.bottom, margin.top]);
            const xAxis = g => g
                .attr("transform", `translate(0, ${height - margin.bottom})`)
                .call(d3.axisBottom(xScale).ticks(width / 80).tickSizeOuter(0));
            const yAxis = g => g
                .attr("transform", `translate(${margin.left},0)`)
                .call(d3.axisLeft(yScale))
                .call(g => g.select(".domain").remove())
                .call(g => g.select(".tick:last-of-type text").clone()
                    .attr("x", 3)
                    .attr("text-anchor", "start")
                    .attr("font-weight", "bold")
                    .text(sampleAreaData.month));
            
          const area = d3.area(sampleAreaData)
                .x(d => xScale(Date.parse(d.month))) // pass a valid date number
                .y0(yScale(0))
                .y1(d => yScale(d.value));
    
            // SVG Construction
            svg.append("path")
                .attr("fill", "steelblue")
                .datum(this.sampleAreaData)
                .attr("d", area)
            svg.append("g")
                .call(xAxis);
            svg.append("g")
                .call(yAxis);
            return svg.node();
        }
    
    initializeSampleAreaGraph();
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
    <svg width="900" height="500" class="sampleAreaGraph"></svg>

    我希望这会有所帮助。

    【讨论】:

    • 正如我的问题所述,我不会使用日期,我将使用字符串。虽然我看到您将我的字符串转换为 scaleTime() 中的日期,但不能保证我的字符串可以转换为字符串。至于 SVG 的选择,我在 Salesforce Web 组件中使用它,这就是您必须选择 SVG 的方式。
    • 您必须为您的月份属性定义一个模式。即使您使用像 scaleLinear() 这样的通用方法,您也应该有某种模式,以便您可以解决问题。应该在您的问题中指定此模式。
    • 好的,所以我决定只使用与日期相关的这些图表,所以我将Month 更改为2018-12-012019-01-01 等。但现在我的 x 轴将它们列出为:..., November, December, 2019, February, ... 你如何让它显示整个日期?
    • 哦,还有,您的代码 sn-p 不起作用。没有图表出现
    • 我现在正在查看图表。在我这边工作:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-15
    • 2022-01-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多