移动时D3画笔滞后

时间:2020-05-26 12:17:48

标签: javascript reactjs d3.js

在D3图表上进行反应。我在d3中实现了画笔。

当我滚动画笔时,它工作正常,但是比较滞后。有趣的是,如果我删除下面标记为有问题的行(在NavChart.js中),则画笔可以正常工作(没有滞后)。但是,这一行很重要,因为我需要使用react钩子更新ChartWrapper.js中的变量(称为“选择”),我需要将其与nav连接起来。 这是代码:

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'

1 个答案:

答案 0 :(得分:2)

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

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);
        }
    });
相关问题