运行下面的代码段。
按“ update1”-出现圆圈。
按“ update2”-没有明显变化。
在update2上,我希望将(左上)黑色圆圈删除,并在另一端(右下方)替换为圆圈-因为函数dataKey返回的键值对于修改后的数据为“ 140:140”原始数据为“ 20:20”。也就是说,不再有与“ 20:20”相对应的数据项,并且有一个键为“ 140:140”的新项。
编辑
自从第一次发布以来,我注意到,如果我替换对象而不是修改对象的属性,那么事情将按预期工作。(使用按钮update1B和update2B)..尽管这仍然需要dataKey函数。
let svg = null ;
let space = 20 ;
let dataIndex = 1 ;
let data = [
{x:space*dataIndex,y:space*dataIndex++,c:"black"},
{x:space*dataIndex,y:space*dataIndex++,c:"green"},
{x:space*dataIndex,y:space*dataIndex++,c:"blue"},
{x:space*dataIndex,y:space*dataIndex++,c:"red"},
{x:space*dataIndex,y:space*dataIndex++,c:"yellow"},
{x:space*dataIndex,y:space*dataIndex++,c:"purple"}
];
function init(){
svg = document.getElementById("svg") ;
svg.setAttribute("height",`${space*dataIndex+10}px`);
svg.setAttribute("width",`${space*dataIndex+10}px`);
}
function dataKey(d){
// console.log(`${d.x}:${d.y}`);
return `${d.x}:${d.y}`;
}
function updateData(data){
let d3svg = d3.select(svg);
let nodes = d3svg.selectAll(".node").data(data,dataKey) ;
nodes
.enter()
.append("circle")
.attr("cx",function(d){ return d.x; })
.attr("cy",function(d){ return d.y; })
.attr("r","10px")
.attr("class","node")
.attr("fill",function(d){ return d.c; });
nodes.exit().remove();
}
function update1(){
data[0].x = space;
data[0].y = space;
updateData(data) ;
}
function update2(){
data[0].x = space*dataIndex;
data[0].y = space*dataIndex;
updateData(data) ;
}
function update1B(){
data[0] = {x:space,y:space};
updateData(data) ;
}
function update2B(){
data[0] = {x:space*dataIndex,y:space*dataIndex};
updateData(data) ;
}
onload = init ;
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg id="svg"></svg>
<button onclick="update1();">update1</button>
<button onclick="update2();">update2</button>
<button onclick="update1B();">update1B</button>
<button onclick="update2B();">update2B</button>
答案 0 :(得分:0)
关于update1 / update2-数据由索引绑定(如果未指定键),并且由于数据数组的长度没有减少,因此出口选择为空(事实上,enter更新时的选择也应为空,因为数据长度也未增加)。取而代之的是,您现有的元素更改了数据,但是您根本不对它做出反应(即您对nodes.enter()
进行了某些操作,对nodes.exit()
进行了某些操作,而仅对nodes
进行了更改)
通常,您只希望对append
选择使用style
和enter
(并且可选地,如果使用过渡,则是其他属性的起始值),然后合并在更新新数据的属性之前,将其与update选择一起使用。
这是您的代码,固定了updateData
函数
let svg = null ;
let space = 20 ;
let dataIndex = 1 ;
let data = [
{x:space*dataIndex,y:space*dataIndex++,c:"black"},
{x:space*dataIndex,y:space*dataIndex++,c:"green"},
{x:space*dataIndex,y:space*dataIndex++,c:"blue"},
{x:space*dataIndex,y:space*dataIndex++,c:"red"},
{x:space*dataIndex,y:space*dataIndex++,c:"yellow"},
{x:space*dataIndex,y:space*dataIndex++,c:"purple"}
];
function init(){
svg = document.getElementById("svg") ;
svg.setAttribute("height",`${space*dataIndex+10}px`);
svg.setAttribute("width",`${space*dataIndex+10}px`);
}
function dataKey(d){
// console.log(`${d.x}:${d.y}`);
return `${d.x}:${d.y}`;
}
function updateData(data){
let d3svg = d3.select(svg);
let nodes = d3svg.selectAll(".node").data(data,dataKey) ;
nodes
.enter()
.append("circle")
.attr("class","node")
.merge(nodes)
.attr("cx",function(d){ return d.x; })
.attr("cy",function(d){ return d.y; })
.attr("r","10px")
.attr("fill",function(d){ return d.c; });
nodes.exit().remove();
}
function update1(){
data[0].x = space;
data[0].y = space;
updateData(data) ;
}
function update2(){
data[0].x = space*dataIndex;
data[0].y = space*dataIndex;
updateData(data) ;
}
function update1B(){
data[0] = {x:space,y:space};
updateData(data) ;
}
function update2B(){
data[0] = {x:space*dataIndex,y:space*dataIndex};
updateData(data) ;
}
onload = init ;
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg id="svg"></svg>
<button onclick="update1();">update1</button>
<button onclick="update2();">update2</button>
<button onclick="update1B();">update1B</button>
<button onclick="update2B();">update2B</button>
答案 1 :(得分:0)
我的困惑在于我期望按键如何工作;
我曾想过,自上次连接以来其键已更改的对象将被标识为新数据。
至关重要的是,在连接时计算出的键值不会存储在以后的连接中以进行比较;
在连接时计算得出的键值不存储/不可用于后续连接中的比较,因此不会将同一对象标识为新数据或已删除数据。