2-й параметр .style () /. Attr ()
При использовании чего-то вроде:
.attr("fill", someParameter);
D3 проверяет, someParameter
- функция или константа.
Если someParameter
- константа, «всем элементам присваивается одно и то же значение атрибута», в конце концов, мы используем константу. ( см. Также документацию D3 ).
Если someParameter
- функция, D3 использует function.apply()
( см. Также документацию MDN function.apply () ) для вызова этой функции для каждого элемента в выделенном фрагменте, предоставляя его с 3 параметрами:
- текущие данные (по соглашению
d
), - индекс текущего элемента (по соглашению
i
), - и группу узлов в выбранном (противоречивое соглашение, я буду использовать здесь
nodes
).
Использование apply также позволяет указать this
, который является текущим элементом (который также: nodes[i]
).
Использование of function.apply () определяет d
, i
и nodes
только внутри предоставленной функции.
Это имеет смысл, если вы предоставляете константу, нечего применять, э-э, применять и не нужно.
Что происходит, когда вы указываете d [ 'name'] в качестве второго аргумента для .style () /. attr ()
При использовании:
.attr("fill", d.color)`
d
в приведенном выше примере не имеет отношения к данные. Если вы не объявили d
и не присвоили ему свойство color
, здесь оно будет неопределенным. D3 не вызывает здесь функцию с применением для определения d
- вы не предоставляете функцию для этого.
Только если d.color
оценивается как function(d) { return d.color; }
, вы сможете сделать о чем вы спрашиваете. Это была бы очень необычная форма с D3 .
Если d
не определено, вы, скорее всего, выдадите ошибку при доступе к d.color
, как вы видели. Если d
определено, но d.color
не является функцией, оно будет рассматриваться как константа, и каждый элемент получит свойство с тем же значением.
Следовательно, поэтому мы видим формат:
.attr("fill", function(d,i,nodes) { return ... });
Stop Here
Теоретически возможно , но не рекомендуется, чтобы выполнить sh то, что, по вашему мнению, должно быть возможным.
Я делюсь только потому, что
- У меня это валялось на while
- Он показывает, сколько обходного пути требуется для достижения шаблона, о котором вы спрашиваете (без предварительного определения ваших функций как свойств некоторого объекта с именем
d
).
Опять же, не рекомендуется использовать - но вы можете, технически , динамически создать функцию доступа для данного свойства или вложенного свойства, с помощью прокси .
Здесь вы можете использовать форму:
.attr("fill", d.color)
При доступе к любому из свойств прокси (d
) (здесь color
) необходимо будет вернуть соответствующую функцию доступа. (function(d) { return d.color;}
), который затем будет передан в .attr()
, и к нему будут привязаны соответствующие данные. Вы можете использовать только свойство, вы не сможете использовать d.x + 2
.
// create a proxy `d` to return accessor functions,
var d = new Proxy({},{ get: f })
var data = [
{style:{fill:"steelblue",stroke:{color:"crimson", width:4}},width: 30, y: 50, x: 10},
{style:{fill:"yellow",stroke:{color:"orange", width:2}},width: 20, y: 50, x: 50},
{style:{fill:"crimson",stroke:{color:"steelblue", width:8}},width: 30, y: 50, x: 80}
]
var svg = d3.select("body").append("svg");
svg.selectAll(null)
.data(data)
.enter()
.append("rect")
.attr("x", d.x)
.attr("y", d.y)
.attr("width", d.width)
.attr("height",d.width)
.attr("fill",d.style.fill)
.attr("stroke-width",d.style.stroke.width)
.attr("stroke", d.style.stroke.color);
// To resolve paths (https://stackoverflow.com/a/45322101/7106086):
function resolve(path, obj) {
return path.reduce(function(prev, curr) {
return prev ? prev[curr] : null
}, obj || self)
}
// Proxy to dynamically access properties of any depth:
function f(obj, prop) {
if(prop in obj) return obj[prop];
else {
var g = function() {
var accessor = function(d) {
return resolve(accessor._path_,d);
}
// keep track of path:
if(obj._path_) accessor._path_ = [...obj._path_,prop];
else (accessor._path_) = [prop];
return accessor;
}
return obj[prop] = new Proxy(g(), {get:f});
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>