d3 图表中数组数据的渲染不正确

问题描述

#Problem 语句:用于在 d3 图表上显示矩形和文本的数组有 300 多条记录,但在渲染 d3 图表时仅绘制前两条记录,当我缩放时显示其余记录连同前两个记录。注意:在控制台中,我的数组显示了两个对象,但是当我展开该数组时,它显示了 300 多条记录。完全困惑这里出了什么问题。任何小的帮助将不胜感激。附上以下快照和代码供您参考。

数组的控制台输出

enter image description here

当我点击展开这个数组时,它会显示如下记录,超过 300 条记录:

enter image description here

这是我的图表使用数组的前两条记录呈现的方式:

enter image description here

但神奇的是,当我缩放图表时,我在控制台中获得了正确的数据,并且图表也绘制了 375 条记录数据以及第一次显示的前两条记录。下面是相同的快照。

enter image description here

这是图表图像,黄色标记显示之前绘制的文本。

enter image description here

当我实际缩放图表时,实际数据作为道具流入我的组件并重新绘制图表。但问题是为什么数据卡住了,api调用早就完成了。为什么在缩放时发布数据。看起来数据卡在中间,只显示两条记录。缩放时数据被释放,d3 再次重新绘制图表。

组件代码

             import React,{ useState,useEffect,useRef } from "react";
             import * as d3 from "d3";

         var colArray = [
                    "#e31a1c","#a6cee3","#b2df8a","#33a02c","#fb9a99","#fdbf6f","#ff7f00","#cab2d6","#1f78b4",];

              var MARGIN = {
                 TOP: 20,BottOM: 0,LEFT: 20,RIGHT: 20,};

           const YWIDTH = 41;
           const WIDTH = 900 - MARGIN.LEFT - MARGIN.RIGHT;
           const HEIGHT = 520 - MARGIN.TOP - MARGIN.BottOM;
           const dimensions = {
            width: 850,height: 520,};


             const ContainerCloudScheduleGanttChart = ({ chartdata }) => {
             const mySvgRef = useRef();
              const tooltip = useRef();
              const legends = useRef();
             const wrapperRef = useRef();
               var tooltipRef = tooltip.current;
             const [svgElmentState,setSvgElment] = useState();
             const [innerSvgContent,setInnerSvgContent] = useState();
             const [innersvgContentGroup,setInnerSvgElmentGroup] = useState();
             const [xAxisGroupState,setxAxisGroup] = useState();
             const [yAxisGroupState,setyAxisGroup] = useState();
                    const [legendGroup,setlegendRef] = useState();
                   const [currentZoomState,setCurrentZoomState] = useState();

const checkUnique = (arr) => {
    var hash = {},result = [];
    for (var i = 0,l = arr.length; i < l; ++i) {
        if (!hash.hasOwnProperty(arr[i])) {
            hash[arr[i]] = true;
            result.push(arr[i]);
        }
    }
    return result;
};
const calculateBarHeight = (totalSlot,barheight) => {
    let franction_x = totalSlot - 6;
    let franction_y = 6;
    let decrementRatio = franction_x / (franction_x + franction_y);
    let decresedHeight = decrementRatio * barheight;
    let rectHeight = Math.trunc(barheight - decresedHeight);
    if (rectHeight === 0) {
        rectHeight = 0.4;
    }
    return rectHeight;
};

useEffect(() => {
    if (!dimensions) return;
    let ganttSvgRef = d3
        .select(mySvgRef.current)
        .append("svg")
        .attr("width",dimensions.width)
        .attr("height",dimensions.height + MARGIN.TOP + MARGIN.BottOM)
        .append("g");
    let innerSvgMainContentGroup = d3
        .select(mySvgRef.current)
        .append("g")
        .attr("transform","translate(" + YWIDTH + "," + 0 + ")");
    let yAxisSvg = ganttSvgRef
        .append("svg")
        .attr("width",150)
        .attr("height",dimensions.height + MARGIN.TOP + MARGIN.BottOM)
        .append("g")
        .attr("transform","translate(" + 125 + "," + MARGIN.TOP + ")");

    let innerSvgContent = innerSvgMainContentGroup
        .append("svg")
        .attr("width",dimensions.width - MARGIN.LEFT - MARGIN.RIGHT - 105)
        .attr("height",dimensions.height + MARGIN.TOP + MARGIN.BottOM);
    let innersvgContentGroup = innerSvgContent
        .append("g")
        .attr("transform","translate(" + 0 + "," + MARGIN.TOP + ")");
    let xAxisGroup = innersvgContentGroup
        .append("g")
        .attr("className","x top axis")
        .attr(
            "transform","translate(" +
            0 +
            "," +
            (dimensions.height - MARGIN.TOP - MARGIN.BottOM) +
            ")"
        );
    let xAxisGroupTop = innersvgContentGroup
        .append("g")
        .attr("className","x top upper axis")
        .attr("transform"," + -20 + ")");
    let yAxisGroup = yAxisSvg
        .append("g")
        .attr("className","y axis")
        .attr("transform","translate(" + MARGIN.LEFT + "," + 0 + ")");
    let legendRef = d3
        .select(legends.current)
        .style("width",dimensions.width - MARGIN.LEFT - MARGIN.RIGHT + "px")
        .style("height",dimensions.height - 250 + "px")
        .style("overflow","hidden");
    ganttSvgRef
        .append("text")
        .attr(
            "transform","translate(" + 10 + "," + dimensions.height / 2 + ") rotate(-90)"
        )
        .style("text-anchor","middle")
        .text("VESSEL AND WEEK OF ARRIVAL AT SELECTED PORT.");

    setInnerSvgContent(innerSvgMainContentGroup);
    setSvgElment(ganttSvgRef);
    setInnerSvgElmentGroup(innersvgContentGroup);
    setxAxisGroup(xAxisGroup);
    setyAxisGroup(yAxisGroup);
    setlegendRef(legendRef);
},[dimensions]);

useEffect(() => {

    // if (!dimensions) return;
    var barHeight = 50;
    var sidePadding = 20;
    var yVesselNames = [];
    var portsName = [];
    var portColorSelector = {};
    console.log("component chartdata",chartdata);

    for (let i = 0; i < chartdata.length; i++) {
        yVesselNames.push(chartdata[i].call_data);
        portsName.push(chartdata[i].port_data);
    }

    var uniquePortsName = [...new Set(portsName)];
    for (let i = uniquePortsName.length - 1; i >= 0; i--) {
        if (uniquePortsName[i] === " ") {
            uniquePortsName.splice(i,1);
            portColorSelector[" "] = "#ffffff";
        }
    }

    for (var i = 0; i < uniquePortsName.length; i++) {
        portColorSelector[uniquePortsName[i]] = colArray[i % colArray.length];
    }

    yVesselNames = checkUnique(yVesselNames);

    var parseTime = d3.timeParse("%Y-%m-%d %H:%M:%s");
    const xtimeScale = d3
        .scaleTime()
        .domain([
            d3.min(chartdata,function (d) {
                return parseTime(d.arrivalDay_data);
            }),d3.max(chartdata,function (d) {
                return parseTime(d.departureDay_data);
            }),])
        .range([0,dimensions.width - MARGIN.LEFT - MARGIN.RIGHT - 105]);

    const yScale = d3
        .scaleBand()
        .domain(yVesselNames)
        .range([0,dimensions.height - MARGIN.TOP - MARGIN.BottOM]);

    if (currentZoomState) {
        const newXScale = currentZoomState.rescaleX(xtimeScale);
        xtimeScale.domain(newXScale.domain());
    }

    // For zooming features -enable or disable the code if zoom is needed

    const zoomBehavior = d3
        .zoom()
        .scaleExtent([0.5,50])
        .translateExtent([
            [0,0],[
                dimensions.width - MARGIN.LEFT - MARGIN.RIGHT,dimensions.height - MARGIN.TOP - MARGIN.BottOM,],])
        .on("zoom",(event) => {
            const zoomState = event.transform;
            setCurrentZoomState(zoomState);
        });
    if (innerSvgContent) {
        innerSvgContent.call(zoomBehavior);
    }

    var xAxistop = d3
        .axisBottom(xtimeScale)
        .tickSizeOuter(-(dimensions.height - MARGIN.TOP + MARGIN.BottOM))
        .tickSizeInner(-(dimensions.height - MARGIN.TOP + MARGIN.BottOM));
    if (xAxisGroupState) {
        xAxisGroupState.call(xAxistop);
    }
    var yAxis = d3.axisLeft(yScale);

    if (yAxisGroupState) {
        yAxisGroupState.call(yAxis);
    }

    if (yVesselNames.length > 6) {
        barHeight = calculateBarHeight(yVesselNames.length,barHeight);
    }
    if (innersvgContentGroup) {
        innersvgContentGroup.selectAll("rect").remove();
        var rectangles = innersvgContentGroup.selectAll("rect").data(chartdata);
        rectangles.exit().remove();

        var innerRects = rectangles.enter().append("g");
        innerRects
            .append("rect")
            .merge(rectangles)
            .attr("x",function (d) {
                //console.log("x axis",d.arrivalDay_data);
                return xtimeScale(parseTime(d.arrivalDay_data));
            })
            .attr("y",function (d,i) {
                for (var j = 0; j < yVesselNames.length; j++) {
                    if (d.call_data === yVesselNames[j]) {
                        // console.log("y axis",d.call_data);
                        return yScale(d.call_data);
                    }
                }
            })
            .attr("width",function (d) {
                return (
                    xtimeScale(parseTime(d.departureDay_data)) -
                    xtimeScale(parseTime(d.arrivalDay_data))
                );
            })
            .attr("height",barHeight)
            .attr("stroke","none")
            .attr("fill",function (d) {
                if (d.scenario_data != "1 current") {
                    for (var i = 0; i < uniquePortsName.length; i++) {
                        return portColorSelector[d.port_data];
                    }
                } else {
                    return "#e31a1c";
                }
            });

        let text = innersvgContentGroup.selectAll(".rect-text").data(chartdata);
        text.exit().remove();
        innerRects
            .append("text")
            .merge(text)
            .attr("class","rect-text")
            .text(function (d) {
                return d.duration_data;
            })
            .attr("x",function (d) {
                return xtimeScale(parseTime(d.arrivalDay_data)) + sidePadding;
            })
            .attr("y",i) {
                for (var j = 0; j < yVesselNames.length; j++) {
                    if (d.call_data === yVesselNames[j]) {
                        return yScale(d.call_data) + barHeight / 2;
                    }
                }
            })
            .attr("font-size",barHeight / 3)
            .attr("fill","#000");

        // Code for tooltip based on scenario
        legendGroup.selectAll(".legends5").remove();
        innerRects
            .on("mouSEOver",function (e) {
                var tag = "";

                switch (d3.select(this).data()[0].scenario_data) {
                    case "1 current":
                        tag =
                            "Vessel: " +
                            d3.select(this).data()[0].vesselName_data +
                            "</br>" +
                            " Service:  " +
                            d3.select(this).data()[0].serviceName_data +
                            "</br>" +
                            " Terminal:  " +
                            d3.select(this).data()[0].terminal_data +
                            "</br>" +
                            " Arrival:  " +
                            d3.select(this).data()[0].arrivalTime_data +
                            "</br>" +
                            " Duration: " +
                            d3.select(this).data()[0].duration_data;
                        break;
                    case "4 prevvoy":
                    case "5 nextvoy":
                        tag =
                            "Vessel: " +
                            d3.select(this).data()[0].vesselName_data +
                            "</br>" +
                            "Voyage duration:  " +
                            d3.select(this).data()[0].duration_data +
                            " of which stationary:  " +
                            d3.select(this).data()[0].stationary_hours_data +
                            "h" +
                            " (" +
                            d3.select(this).data()[0].distance_sailed_data +
                            ")" +
                            "</br>" +
                            "distance sailed: " +
                            d3.select(this).data()[0].distance_data +
                            " nm" +
                            "</br>" +
                            "Average speed: " +
                            d3.select(this).data()[0].average_speed_data +
                            " knots.";

                        break;

                    default:
                        tag =
                            "Vessel: " +
                            d3.select(this).data()[0].vesselName_data +
                            "</br>" +
                            " Port:  " +
                            d3.select(this).data()[0].port_data +
                            "</br>" +
                            " Arrival:  " +
                            d3.select(this).data()[0].arrivalTime_data +
                            "</br>" +
                            " Duration: " +
                            d3.select(this).data()[0].duration_data;
                        break;
                }

                tooltipRef.innerHTML = tag;
                tooltipRef.style.top = e.offsetY + "px";
                tooltipRef.style.left = e.offsetX + "px";
                tooltipRef.style.display = "block";
            })
            .on("mouSEOut",function () {
                tooltipRef.style.display = "none";
            });

        // Code for legend

        // Issue fix but need to test
        legendGroup.selectAll(".legends5").remove();
        var legend5 = legendGroup.selectAll(".legends5").data(uniquePortsName);
        legend5.exit().remove();
        var l = legend5
            .enter()
            .append("div")
            .attr("class","legends5");

        var p = l.append("p").attr("class","legend-p");
        p.append("span")
            .attr("class","legend-circle")
            .style("background",function (d) {
                var scenario = [];

                for (let j = 0; j < chartdata.length; j++) {
                    scenario = chartdata[j].scenario_data;
                }

                if (scenario !== "1 current") {
                    for (let i = 0; i < uniquePortsName.length; i++) {
                        return portColorSelector[d];
                    }
                } else {
                    return "#e31a1c";
                }
            });

        p.insert("text")
            .attr("class","text-style")
            .style("text-anchor","start")
            .text(function (d,i) {
                return d;
            });
    }
},[
    chartdata,svgElmentState,xAxisGroupState,yAxisGroupState,legendGroup,currentZoomState,dimensions,]);

return (
    <div
        ref={wrapperRef}
        style={{ width: 850,marginBottom: "130px" }}
    >
        <div className='svg' ref={mySvgRef} style={{ display: "flex" }}></div>
        <div className='tag' ref={tooltip}></div>
        <div className='legend' ref={legends}></div>
    </div>
);

};

导出认ContainerCloudScheduleGanttChart;

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)