Javascript D3总是合并节点,即使数据相同
我创建了D3Treemap组件,它应该显示两个不同的文本,并将它们放在矩形中(不是html结构,而是页面上的位置) 由于这是正确的,我注意到当新数据出现在一个文本标记中时,其中一个文本标记会被更新。 因此,我认为预期的行为是,如果从Javascript D3总是合并节点,即使数据相同,javascript,reactjs,d3.js,dom,Javascript,Reactjs,D3.js,Dom,我创建了D3Treemap组件,它应该显示两个不同的文本,并将它们放在矩形中(不是html结构,而是页面上的位置) 由于这是正确的,我注意到当新数据出现在一个文本标记中时,其中一个文本标记会被更新。 因此,我认为预期的行为是,如果从.text函数返回的数据与DOM中已经存在的文本相同,则不要更新节点,如果不同,则更新节点。 实际发生的情况是,每次输入新数据时,总会有一个文本被替换 我只想在其内部的值不同时更新,而不是在任何时候更新 以下是我的代码: import * as d3Selection
.text
函数返回的数据与DOM中已经存在的文本相同,则不要更新
节点,如果不同,则更新节点。
实际发生的情况是,每次输入新数据时,总会有一个文本被替换
我只想在其内部的值不同时更新
,而不是在任何时候更新
以下是我的代码:
import * as d3Selection from 'd3-selection';
import React, { useLayoutEffect, useRef } from 'react';
// ^^^^ imports stuff
export const Heatmap = ({
width,
height,
padding = 1,
data,
}) => {
debugger;
const ref = useRef();
useLayoutEffect(() => {
draw();
}, [width, height, padding, data, ref.current]);
const draw = () => {
const svg = d3Selection.select(ref.current);
// util to get d3-treemap, nothing out of ordinary happening here apart from adding
// opacity, value and color attributes to each node
const root = makeTreemap({
width,
height,
padding,
data,
});
const rootLeaves = root.leaves();
svg.attr('viewBox', `0 0 ${width} ${height}`).attr('preserveAspectRatio', 'xMinYMin meet');
svg.attr('height', '100%').attr('width', '100%');
const nodes = svg.selectAll('rect').data(root.leaves());
nodes.join(
(enter) =>
enter
.append('a')
.attr('href', (d) => {
if (d.link) {
return d.link;
}
return '/';
})
.attr('target', '_blank')
.append('rect')
.attr('x', function (d) {
return d.x0;
})
.attr('y', function (d) {
return d.y0;
})
.attr('width', function (d) {
return d.x1 - d.x0;
})
.attr('height', function (d) {
return d.y1 - d.y0;
})
.style('stroke', 'black')
.style('fill', function (d) {
if (d.color) {
return d.color;
}
return d.value >= 0 ? 'darkgreen' : 'darkred';
})
.style('opacity', function (d) {
if (d.opacity) {
return d.opacity;
}
return 1;
}),
(update) => update,
(exit) => exit.remove()
);
svg
.selectAll('text')
.data(root.leaves())
.join(
(enter) =>
enter
.append('text')
.attr('text-anchor', 'middle')
.attr('x', function (d) {
return (d.x0 + d.x1) / 2;
})
.attr('y', function (d) {
return (d.y0 + d.y1) / 2 + 15;
})
// just code to get string to display
.text(function (d) {
const titleSplit = d.title.split(/(?=[A-Z][a-z])|\s+/g);
const [_, ...otherParts] = titleSplit;
enter code here
return otherParts.join(' ')
})
.attr('fill-opacity', 0.7)
.attr('fill', 'white'),
(update) => update,
(exit) => exit.remove()
);
svg
.selectAll('vals')
.data(root.leaves())
.join(
(enter) =>
enter
.append('text')
.attr('x', function (d) {
return (d.x0 + d.x1) / 2;
})
.attr('y', function (d) {
return (d.y0 + d.y1) / 2;
})
.attr('text-anchor', 'middle')
.text(function (d) {
return d.title.split(/(?=[A-Z][a-z])|\s+/g)[0];
})
.attr('fill', 'white'),
(update) => update,
(exit) => exit.remove()
);
};
return (
<div style={{ width, height }}>
<svg id={styles.svg} ref={ref} />
</div>
);
};
import*作为“d3选择”中的d3选择;
从“React”导入React,{useLayoutEffect,useRef};
//^^^^导入内容
导出常数热图=({
宽度,
高度,
填充=1,
数据,
}) => {
调试器;
const ref=useRef();
useLayoutEffect(()=>{
draw();
},[宽度、高度、填充、数据、当前参考];
常量绘图=()=>{
const svg=d3Selection.select(ref.current);
//util获取d3树映射,除了添加
//每个节点的不透明度、值和颜色属性
const root=makeTreemap({
宽度,
高度,
衬垫,
数据,
});
const rootLeaves=root.leaves();
attr('viewBox','0 0${width}${height}').attr('preserveAspectRatio','xMinYMin meet');
svg.attr('height','100%').attr('width','100%');
const nodes=svg.selectAll('rect').data(root.leaves());
nodes.join(
(输入)=>
进入
.append('a')
.attr('href',(d)=>{
如果(d.link){
返回d.link;
}
返回“/”;
})
.attr('target','u blank')
.append('rect')
.attr('x',函数(d){
返回d.x0;
})
.attr('y',函数(d){
返回d.y0;
})
.attr('width',函数(d){
返回d.x1-d.x0;
})
.attr(高度),功能(d){
返回d.y1-d.y0;
})
.style('笔划','黑色')
.样式(“填充”,功能(d){
如果(d.颜色){
返回d.color;
}
返回d.value>=0?'darkgreen':'darkred';
})
.style('opacity',function(d){
如果(d.不透明度){
返回d.opacity;
}
返回1;
}),
(更新)=>更新,
(exit)=>exit.remove()
);
svg
.selectAll('text')
.data(root.leaves())
.加入(
(输入)=>
进入
.append('文本')
.attr('text-anchor','middle')
.attr('x',函数(d){
返回(d.x0+d.x1)/2;
})
.attr('y',函数(d){
收益率(d.y0+d.y1)/2+15;
})
//只需编写代码即可显示字符串
.文本(功能(d){
常量titleSplit=d.title.split(/(?=[A-Z][A-Z])|\s+/g);
常数[,…其他部分]=标题片段;
在这里输入代码
返回其他部件。联接(“”)
})
.attr('fill-opacity',0.7)
.attr(“填充”、“白色”),
(更新)=>更新,
(exit)=>exit.remove()
);
svg
.selectAll('vals')
.data(root.leaves())
.加入(
(输入)=>
进入
.append('文本')
.attr('x',函数(d){
返回(d.x0+d.x1)/2;
})
.attr('y',函数(d){
收益率(d.y0+d.y1)/2;
})
.attr('text-anchor','middle')
.文本(功能(d){
返回d.title.split(/(?=[A-Z][A-Z])|\s+/g)[0];
})
.attr(“填充”、“白色”),
(更新)=>更新,
(exit)=>exit.remove()
);
};
返回(
);
};
我注意到,如果我删除第一个文本呈现部分,节点将被添加到DOM中,而不是在新数据到达时合并
我认为这是两件事之一
join
中渲染的值完全相同,在进行DOM更新之前也没有缓存值或类似的内容,这意味着我自己必须检查值是否相等。(不知怎的)不管是哪种方式,如果你们中的任何人都清楚,我的互联网朋友,为什么在这个特定的示例中,节点总是得到更新,即使从
.text返回值也是如此(d=>…
函数是相同的,如何真正避免发生更新我将非常感激。节点总是得到更新,因为您没有指定键函数,这是数据()的第二个参数
。由于我不知道您的数据是什么样子,下面是一个简化的示例:假设您的数据如下:
data = [{text: "hi", value: 1}, {text: "world", value: 2}]
那么您的代码将如下所示:
svg
.selectAll('text')
.data(data, d => d.text) // key function
.join(
(enter) =>
enter
.append('text')
.text(d => d.text),
(update) =>
update
.text(d.text),
(exit) => exit.remove()
);
data = [{text: "hello", value: 1}, {text: "world", value: 3}]
在这里,第二个参数是d=>d.text
函数,它指定了如何对数据进行差异化。您可以将任何返回值的任意逻辑替换为该函数。在差异化时,D3将使用该函数来确定输入、更新和退出选项中的内容
如果我们的新数据如下所示:
svg
.selectAll('text')
.data(data, d => d.text) // key function
.join(
(enter) =>
enter
.append('text')
.text(d => d.text),
(update) =>
update
.text(d.text),
(exit) => exit.remove()
);
data = [{text: "hello", value: 1}, {text: "world", value: 3}]
在这里,D3使用键函数,在本例中是d=>d.text
。根据该函数,第二个元素是相同的,因此它不会进入任何选择。但是第一个元素已经更改,因此它进入了您在join()
中指定的update
选择中
见和g