数据使用自定义键加入无法正常工作 [英] Data Join with Custom Key does not work as expected
问题描述
我使用d3绘制一些点。我想根据一些条件改变所有点的形状。连接看起来有点像这样:
var data = [{x:10,y:10},{x:20 ,y:30}];
var shape =rect;
...
var point = svg.selectAll(。point)
.data(data,function(d,idx){returnrow_+ idx +_shape_+ shape;})
;
d3 enter()和exit()选择似乎不反映由shape 改变。
小提琴在这里: http:// jsfiddle.net/schmoo2k/jcpctbty/
您需要注意的是,键功能是在选择 this
作为SVG元素,然后选择数据数组为 this
。
我想也许这是你想要做的事情。
var data = [{x:10,y:10},{x:20,y:30}]; var svg = d3.select(body)append(svg).attr(width 500).attr(height,500); function update(data,shape){var point = svg.selectAll(。point).data(data,function(d,idx){var key =row_ + idx +_shape_+(Array.isArray(this)?Data:+ shape:d3.select(this).attr(shape)); alert(key); return key;}); alert(enter selection size:+ point.enter()。size()); point.enter()。append(shape).attr(class,point).style(fill,red).attr(shape,shape)开关(形状){caserect:point.attr(x,function(d){return dx;}).attr(y,function(d){return dy;}).attr ,5).attr(height,5);打破; casecircle:point.attr(cx,function(d){return d.x;}).attr(cy,function(d){return d.y;}).attr(r,5)打破; } point.exit()。remove();} update(data,rect); setTimeout(function(){update(data,circle);},5000);
pre>text {font:bold 48px monospace;}输入{fill:green;}。 :#333;}
< script src = ://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.js>< / script>
div>
抽象版本
只是为了整理这里是一个更可读和惯用的版本(包括修复的文本元素的问题)...
var data = [{x:10 ,y:10,},{x:20,y:30,}]; var svg = d3.select(body)。append(svg).attr(width,500).attr高度,500),marker = Marker(); function update(data,shape){var point = svg.selectAll(。point).data(data,key(shape,shape)),enter = point .enter()。append(g).attr(class,point).attr(transform,function(d){returntranslate(+ dx +,+ dy +) }).attr(shape,shape); enter.append(shape).style(fill,red).attr(marker.width [shape],5).attr(marker.height [shape],5); enter.append(text).attr({class:title,dx:10,text-anchor:start})。 point.exit()。remove();} update(data,rect); setTimeout(function(){update(data,circle);},2000); function Marker rect:width,circle:r},height:{rect:height,circle:r},shape:function(d){return d.shape},};} value){//连接数据和元素,其中attr的值是value function _phase(that){return Array.isArray(that)? data:element; } function _Type(that){return {data:value,get element(){return d3.select(that).attr(attr)}}} return function(d,i,j){var _value = return i +_+ _value [_phase(this)]; };}
< script src =https: /cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js\"></script>
广义的数据驱动方法
div class =snippetdata-lang =jsdata-hide =false>
var data = [{x:10,y:10,},{x:20,y:30,}]; var svg = d3.select(body)append(svg) .attr(width,500).attr(height,500),marker = Marker(); function update(data,shape){//数据驱动的方法data.forEach d.shape = shape [i]}); var log = [],point = svg.selectAll(。point).data(data,key({shape:marker.shape,transform:marker.transform},log)),// UPDATE update = point.classed (update,true),updateSize = update.size(); update.selectAll(text)。transition()。duration(1000).style(fill,#ccc); update.selectAll(。shape)。transition()。duration(1000).style(fill,#ccc)// ENTER var enter = point.enter()。append(g).classed (point enter,true).attr(transform,marker.dock).attr(shape,marker.shape),// UPDATE + ENTER // ...此时不需要updateAndEnter = classed(update-enter,true); // EXIT var exit = point.exit()。classed(exit,true); exit.selectAll(text)。transition()。duration(1000).style(fill,red); exit.selectAll(。shape)。transition()。duration(1000).style(fill,red); exit.transition()。delay(1000。)。duration(1000).attr(transform,marker.dock).remove(); // ADJUSTMENTS enter.each(function(d){//为每个数据元素添加指定的形状//在每个数据元素中添加,以便attr可以是数据的函数d3.select(this).append(marker.shape d)).style(fill,green).classed(shape,true).attr(marker.width [marker.shape(d)],5).attr(marker.height [marker.shape (d)],5)}); enter.append(text).attr({class:title,dx:10,text-anchor:start}).text(marker.shape).style(fill绿色).style(opacity,1); enter.transition()。delay(1000).duration(2000).attr(transform,marker.transform);} data = generateData(40,10)update(data,data.map {return [rect,circle] [Math.round(Math.random())]})); setInterval(function rect,circle] [Math.round(Math.random())]}));},5000); function generateData(n,p){var values = []; for(var i = 0; i
text {font:bold 12px monospace; fill:black;}
< script src =https ://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js>
I am plotting some points using d3. I want to change the shape off all the points based on some condition. The join looks a bit like this:
var data=[{x:10,y:10}, {x:20, y:30}];
var shape = "rect";
...
var point = svg.selectAll(".point")
.data(data, function(d, idx) { return "row_" + idx + "_shape_" + shape;})
;
The d3 enter() and exit() selections do not seem to reflect any changes caused by "shape" changing.
Fiddle is here: http://jsfiddle.net/schmoo2k/jcpctbty/
You need to be aware that the key function is calculated on the selection with this
as the SVG element and then on the data with the data array as this
.
I think maybe this is what you are trying to do...
var data = [{
x: 10,
y: 10
}, {
x: 20,
y: 30
}];
var svg = d3.select("body").append("svg")
.attr("width", 500)
.attr("height", 500);
function update(data, shape) {
var point = svg.selectAll(".point")
.data(data, function(d, idx) {
var key = "row_" + idx + "_shape_" + (Array.isArray(this) ? "Data: " + shape :
d3.select(this).attr("shape"));
alert(key);
return key;
});
alert("enter selection size: " + point.enter().size());
point.enter().append(shape)
.attr("class", "point")
.style("fill", "red")
.attr("shape", shape);
switch (shape) {
case "rect":
point.attr("x", function(d) {
return d.x;
})
.attr("y", function(d) {
return d.y;
})
.attr("width", 5)
.attr("height", 5);
break;
case "circle":
point.attr("cx", function(d) {
return d.x;
})
.attr("cy", function(d) {
return d.y;
})
.attr("r", 5);
break;
}
point.exit().remove();
}
update(data, "rect");
setTimeout(function() {
update(data, "circle");
}, 5000);
text {
font: bold 48px monospace;
}
.enter {
fill: green;
}
.update {
fill: #333;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.js"></script>
Abstracted version
Just to tidy things up here is a more readable and idiomatic version (including fixing a problem with the text element)...
var data = [{
x: 10,
y: 10,
}, {
x: 20,
y: 30,
}];
var svg = d3.select("body").append("svg")
.attr("width", 500)
.attr("height", 500),
marker = Marker();
function update(data, shape) {
var point = svg.selectAll(".point")
.data(data, key("shape", shape)),
enter = point.enter().append("g")
.attr("class", "point")
.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")"
})
.attr("shape", shape);
enter.append(shape)
.style("fill", "red")
.attr(marker.width[shape], 5)
.attr(marker.height[shape], 5);
enter.append("text")
.attr({
"class": "title",
dx: 10,
"text-anchor": "start"
})
.text(shape);
point.exit().remove();
}
update(data, "rect");
setTimeout(function() {
update(data, "circle");
}, 2000);
function Marker() {
return {
width: {
rect: "width",
circle: "r"
},
height: {
rect: "height",
circle: "r"
},
shape: function(d) {
return d.shape
},
};
}
function key(attr, value) {
//join data and elements where value of attr is value
function _phase(that) {
return Array.isArray(that) ? "data" : "element";
}
function _Type(that) {
return {
data: value,
get element() {
return d3.select(that).attr(attr)
}
}
}
return function(d, i, j) {
var _value = _Type(this)
return i + "_" + _value[_phase(this)];
};
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
Generalised, data-driven approach
var data = [{
x: 10,
y: 10,
}, {
x: 20,
y: 30,
}];
var svg = d3.select("body").append("svg")
.attr("width", 500)
.attr("height", 500),
marker = Marker();
function update(data, shape) {
//data-driven approach
data.forEach(function(d, i) {
d.shape = shape[i]
});
var log = [],
point = svg.selectAll(".point")
.data(data, key({
shape: marker.shape,
transform: marker.transform
}, log)),
//UPDATE
update = point.classed("update", true),
updateSize = update.size();
update.selectAll("text").transition().duration(1000).style("fill", "#ccc");
update.selectAll(".shape").transition().duration(1000).style("fill", "#ccc")
//ENTER
var enter = point.enter().append("g")
.classed("point enter", true)
.attr("transform", marker.dock)
.attr("shape", marker.shape),
//UPDATE+ENTER
// ... not required on this occasion
updateAndEnter = point.classed("update-enter", true);
//EXIT
var exit = point.exit().classed("exit", true);
exit.selectAll("text").transition().duration(1000).style("fill", "red");
exit.selectAll(".shape").transition().duration(1000).style("fill", "red");
exit.transition().delay(1000.).duration(1000)
.attr("transform", marker.dock)
.remove();
//ADJUSTMENTS
enter.each(function(d) {
//append the specified shape for each data element
//wrap in each so that attr can be a function of the data
d3.select(this).append(marker.shape(d))
.style("fill", "green")
.classed("shape", true)
.attr(marker.width[marker.shape(d)], 5)
.attr(marker.height[marker.shape(d)], 5)
});
enter.append("text")
.attr({
"class": "title",
dx: 10,
"text-anchor": "start"
})
.text(marker.shape)
.style("fill", "green")
.style("opacity", 1);
enter.transition().delay(1000).duration(2000)
.attr("transform", marker.transform);
}
data = generateData(40, 10)
update(data, data.map(function(d, i) {
return ["rect", "circle"][Math.round(Math.random())]
}));
setInterval(function() {
update(data, data.map(function(d, i) {
return ["rect", "circle"][Math.round(Math.random())]
}));
}, 5000);
function generateData(n, p) {
var values = [];
for (var i = 0; i < n; i++) {
values.push({
x: (i + 1) * p,
y: (i + 1) * p
})
}
return values;
};
function Marker() {
return {
x: {
rect: "x",
circle: "cx"
},
y: {
rect: "y",
circle: "cy"
},
width: {
rect: "width",
circle: "r"
},
height: {
rect: "height",
circle: "r"
},
shape: function(d) {
return d.shape
},
transform: function(d) {
return "translate(" + f(d.x) + "," + f(d.y) + ")"
},
dock: function(d) {
return "translate(" + (d.x + 800) + "," + (d.y + 100) + ")"
}
};
function f(x) {
return d3.format(".0f")(x)
}
}
function key(attr, value, log) {
//join data and elements where value of attr is value
function _phase(that) {
return Array.isArray(that) ? "data" : "element";
}
function _Key(that) {
if (plural) {
return {
data: function(d, i, j) {
var a, key = "";
for (a in attr) {
key += (typeof attr[a] === "function" ? attr[a](d, i, j) : attr[a]);
}
return key;
},
element: function() {
var a, key = "";
for (a in attr) {
key += d3.select(that).attr(a);
}
return key;
}
}
} else {
return {
data: function(d, i, j) {
return typeof value === "function" ? value(d, i, j) : value;
},
element: function() {
return d3.select(that).attr(attr)
}
}
}
}
var plural = typeof attr === "object";
if (plural && arguments.length === 2) log = value;
return function(d, i, j) {
var key = _Key(this)[_phase(this)](d, i, j);
if (log) log.push(i + "_" + _phase(this) + "_" + key);
return key;
};
}
text {
font: bold 12px monospace;
fill: black;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
这篇关于数据使用自定义键加入无法正常工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!