问题描述
#Problem 语句:用于在 d3 图表上显示矩形和文本的数组有 300 多条记录,但在渲染 d3 图表时仅绘制前两条记录,当我缩放时显示其余记录连同前两个记录。注意:在控制台中,我的数组显示了两个对象,但是当我展开该数组时,它显示了 300 多条记录。完全困惑这里出了什么问题。任何小的帮助将不胜感激。附上以下快照和代码供您参考。
数组的控制台输出:
当我点击展开这个数组时,它会显示如下记录,超过 300 条记录:
这是我的图表使用数组的前两条记录呈现的方式:
但神奇的是,当我缩放图表时,我在控制台中获得了正确的数据,并且图表也绘制了 375 条记录数据以及第一次显示的前两条记录。下面是相同的快照。
当我实际缩放图表时,实际数据作为道具流入我的组件并重新绘制图表。但问题是为什么数据卡住了,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 (将#修改为@)