【问题标题】:D3 brush lag when movingD3 移动时刷机滞后
【发布时间】:2020-05-26 12:17:48
【问题描述】:

使用 React 处理 D3 图表。我在 d3 中实现了一个画笔。

当我滚动画笔时,它工作正常,但它很迟钝。有趣的是,如果我删除下面标记为有问题的行(在 NavChart.js 中),画笔将开始正常工作(没有滞后)。然而,这条线很重要,因为我使用反应钩子更新 ChartWrapper.js 中的变量(称为“选择”),我需要将图表与导航连接起来。 代码如下:

ChartWrapper.js ->

import React, {useRef, useEffect, useState, useImperativeHandle} from 'react';
import  {select, selectAll, extent, axisBottom, axisLeft, scaleLinear, scaleTime, curve, line, curveCardinal, set} from 'd3';
import Chart from './Chart';
import NavChart from './NavChart';
import UsePrevious from './UsePrevious';

const MARGIN = {TOP: 50, BOTTOM: 50, LEFT: 50, RIGHT: 50};
const maxData = 10;
export default function ChartWrapper(props) {

    let [selection, setSelection] = useState([props.data[0].time, props.data[1].time]);
    const previousSelection = UsePrevious(selection);
    let [first, setFirst] = useState(true);
    const svgRef = useRef();
    let chart = null;
    let nav = null;
    const navRef = useRef();    

    useEffect(
        () => {
                console.log(`selection is : ${selection}`);
                //Chart component
                chart = new Chart(MARGIN, svgRef, props.data, props.xAxisText, props.yAxisText);
                // navigation component (Both aren't connected right now)
                nav = new NavChart(MARGIN, navRef, props.data, previousSelection.current, selection, setSelection, first);
                setFirst(false);


        }, [props.data, previousSelection, selection, first]        
    );

    return (
        <div>
            <svg ref = {svgRef} width = {700} height = {400}></svg>
            <br /><br/>
            <svg ref = {navRef} width = {700} height = {75}></svg>
        </div>
    );
}

NavChart.js ->

import {select,
    selectAll,
    extent,
    axisBottom,
    axisLeft,
    scaleLinear,
    scaleTime,
    line,
    brushX,
    event
} from 'd3';

const PADDING = {TOP: 10, BOTTOM: 30};

export default class NavChart {
    constructor(MARGIN, svgRef, data, previousSelection, selection, setSelection, firstTime) {

        this.svg = select(svgRef.current);
        this.MARGIN = MARGIN;
        this.data = data;

        this.chartWidth = this.svg.attr('width') - MARGIN.LEFT - MARGIN.RIGHT;
        this.chartHeight = this.svg.attr('height') - PADDING.TOP - PADDING.BOTTOM;

        this.xScale = scaleTime()
                        .domain(extent(
                            this.data.map((d) => d.time)
                        ))
                        .range([0, this.chartWidth]);

        this.yScale = scaleLinear()
                        .domain(extent(
                            this.data.map((d) => d.value)
                        ))
                        .range([this.chartHeight, 0]);

        this.myLine = line()
                        .x((d) => this.xScale(d.time))
                        .y((d) => this.yScale(d.value));

        this.chartArea = this.svg.append('g')
                        .attr('transform', `translate(${MARGIN.LEFT}, ${PADDING.TOP})`);

        this.chartArea.append('rect')
                        .attr('x', 0)
                        .attr('y', 0)
                        .attr('width', this.chartWidth)
                        .attr('height', this.chartHeight)
                        .attr('fill', '#f2f2f2');

        this.pathsG = this.chartArea.append('g')
                        .attr('class', 'pathsG')
                        .attr('transform', `translate(0,0)`);

        this.xAxis = axisBottom(this.xScale);

        this.xAxisG = this.chartArea.append('g')
                                       .attr('transform', `translate(0, ${this.chartHeight})`);

        this.xAxisG.call(this.xAxis);

        this.pathsG.selectAll('path')
            .data([this.data])
            .join('path')
            .attr('d', (value) => this.myLine(value))
            .attr('fill', 'none')
            .attr('stroke', '#D073BA')
            .attr('stroke-width', '1.5');

        this.circlesVar = this.pathsG.selectAll('.circle')
            .data(data);

        this.circlesVar.enter().append('circle')
            .attr('class', 'circle')
            .attr('r', '3')/*(value) => 
                    value.time > selection[0] && value.time <= selection[1] ? 4 : 2)*/
            .style('fill', '#D073BA')
            .attr('cx', (d) => this.xScale(d.time))
            .attr('cy', (d) => this.yScale(d.value));

        this.brushG = this.chartArea.append('g')
                        .attr('class', 'brush');

        this.brush = brushX().extent([
            [0, 0],
            [this.chartWidth, this.chartHeight]
        ]).on('start brush end', () => {
            if (event.selection  && (event.sourceEvent != null)) {
                const timeSelection = event.selection.map(this.xScale.invert);
                setSelection(timeSelection);    // This line is problematic
            }
        });
         this.brushG.call(this.brush)
                        .call(this.brush.move, selection.map(this.xScale));
    }
}

我了解更改选择变量(通过 NavChart.js 中的 setSelection 方法)将触发 ChartWrapper.js 中的 useEffect() 挂钩,但我不知道为什么会导致延迟。我需要添加过渡到画笔吗?

编辑:在线链接代码 -> 'https://stackblitz.com/edit/react-jxgqe8'

【问题讨论】:

    标签: javascript reactjs d3.js


    【解决方案1】:

    当前代码监听重叠事件,因此并行响应多次。

    end 事件就足够了,而不是一起听startbrushend

        this.brush = brushX().extent([
            [0, 0],
            [this.chartWidth, this.chartHeight]
        ]).on('end', () => {
            if (event.selection  && (event.sourceEvent != null)) {
                const timeSelection = event.selection.map(this.xScale.invert);
                setSelection(timeSelection);
            }
        });
    

    【讨论】:

    • 感谢您的解决方案!!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-11-11
    • 2021-10-02
    • 1970-01-01
    • 2017-07-18
    • 1970-01-01
    • 2018-05-31
    • 1970-01-01
    相关资源
    最近更新 更多