问题
I am tying to set multiple attributes in d3 similar to what is done in this answer: https://stackoverflow.com/a/20822552/1112097, but I want to be able to pass a set of attributes in as an array so that the same code can create different elements. For example, the following data should create a red square and a green circle:
var data = [
{
name: "Element 1",
type: “rect”,
id: “rect01”,
attributes: [
{label: “x”, val: 0},
{label: “y”, val: 0},
{label: “width”, val: 10},
{label: “height”, val: 10},
],
styles: [
{label: “fill”, val: “none”},
{label: “stroke”, val: “#ff0000”}
]
},
{
name: "Element 2",
type: “circle”,
id: “circle01”,
attributes: [
{label: “cx”, val: 30},
{label: “cy”, val: 30},
{label: “r”, val: 10}
],
styles: [
{label: “fill”, val: “#00ff00”},
{label: “stroke”, val: “#0000ff”}
]
}
];
using something like the following:
var element = svg.selectAll(".element")
.data(data, function(d) {return d.id;});
var elementEnter = element.enter()
.append(function (d) {return d.type;})
.attr("class", "element")
.attr({
// what goes here?
})
.style({
// what goes here?
}):
What can I put in place of "what goes here?" to set both the attribute (e.g. 'x', 'cx' or 'r') and the value using the data array.
回答1:
Try this.
function setAttributesAndStyles(d){
var attrs = {};
d.attributes.forEach(function(a){
attrs[a.label] = a.val;
});
var styles = {};
d.styles.forEach(function(a){
styles[a.label] = a.val;
});
d3.select(this).attr(attrs);
d3.select(this).attr(styles);
}
var element = svg.selectAll(".element")
.data(data, function(d) {return d.id;});
var elementEnter = element.enter()
.append(function (d) {
return svg.append(d.type).node(); //Returns the dom element
})
.attr("class", "element")
.each(setAttributesAndStyles);
Note that selection.append(name) statement expects the name as a constant string or a function that returns the DOM element to append.
回答2:
It would be better if you changed your data to be in the following format:
attributes: {
"cx": 0,
"cy": 30,
"r": 10
},
styles: {
"fill: "#00ff00",
"stroke": "#0000ff"
}
This way you could simply do...
var elementEnter = element.enter()
.append(function (d) {return d.type;})
.attr("class", "element")
.attr(function(d) {return d.attributes});
.style(function(d) {return d.styles});
If you still want to keep your current format, you can do something like...
var elementEnter = element.enter()
.append(function (d) {return d.type;})
.attr("class", "element")
.attr(function(d) {return arrToObj(d.attributes)});
.style(function(d) {return arrToObj(d.styles)});
function arrToObj(arr) {
var obj = {};
arr.forEach(function(keyValue){
obj[keyValue.label] = keyValue.val;
});
return obj;
}
来源:https://stackoverflow.com/questions/27369426/set-multiple-attributes-in-d3-without-knowing-what-they-are-going-to-be-ahead-of