С циклом ввода / обновления / выхода в D3 вы обычно хотите иметь массив данных, который содержит один элемент для каждого элемента, который вы хотите нарисовать. У вас есть:
- цвет имеет объект
color_hash
, это то, что вы действительно хотите использовать для рисования легенды и - некоторого массива данных
data
, хотя мы не знаем, что внутри этого.
Мы используем data
для визуализации color_hash
, это не идеально.
Для одного вы хотите построить только 2 элемента, я могу сказать, что длинаиз data
не менее 3:
Вы создаете пустой g
с помощью:
var legend = svg.append("g")
Затем выбираете дочерние элементы g
этого:
legend.selectAll('g')
Поскольку их нет, это пустой выбор. Затем вы присваиваете данные этому выбору и вводите новые элементы HTML / SVG:
legend.selectAll('g')
.data(data)
.enter()
.append('g')
Поскольку legend
является пустым выбором, выбор ввода создаст один элемент HTML / SVG для каждого элемента в массиве данных. ,После входа (и / или выхода) количество элементов HTML / SVG должно быть равно количеству элементов в массиве данных. Таким образом, в data
должно быть как минимум 3 элемента (может быть больше , если создано дополнительных элементов, но они выходят за границы SVG / контейнера. Это также объясняет, почему в третьем блоке нетцвет или текст: цветовой хэш не имеет значений с ключом 2 или более).
D3 - создает элементы из данных, как правило, в отношении один к одному между элементами и элементами. Чтобы создать нашу легенду, массив данных должен быть тем, что мы хотим построить . Как следствие, нам нужно преобразовать цветовой хэш в массив:
var legendData = [
{name: "A", color:"crimson"},
{name: "B", color:"steelblue"}
];
Теперь мы просто передаем это в selection.data()
И, поскольку мы теперь привязываем нужные данныеЧтобы нарисовать записи легенды, мы также можем упростить код, вместо:
.style("fill", color_hash[String(i)][1]);
и
.text(color_hash[String(i)][0]);
Мы можем просто использовать:
.style("fill",d.color);
и
.text(d.name);
Это дает нам:
var color_hash = { 0 : ["Male", "blue"],
1 : ["Female", "pink"]}
var width = 300;
var height = 200;
var svg = d3.select("svg")
.attr("width",width)
.attr("height",height);
var legendData = [
{name:"A",color:"crimson"},
{name:"B",color:"steelblue"}
]
var legend = svg.append("g")
legend.selectAll('g')
.data(legendData)
.enter()
.append('g')
.each(function(d, i) {
var g = d3.select(this);
g.append("rect")
.attr("x", width - 65)
.attr("y", i*25+25)
.attr("width", 10)
.attr("height", 10)
.style("fill", d.color);
g.append("text")
.attr("x", width - 50)
.attr("y", i * 25 + 33)
.attr("height", 30)
.attr("width", 100)
.style("fill", d.color)
.text(d.name);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg></svg>
Я просто сосредотачиваюсь на цикле ввода здесь: возможны дальнейшие изменения в размещении, а другой подход к вложенным добавлениям может дать преимущества по сравнениюдля добавления детей с .each