Я новичок в D3 и пытаюсь решить непростую задачу (по крайней мере для меня!) Вот мой образец данных.
var data = [
{"x":1000, "y": {"10":100, "10.2":200, "10.3":300, "10.4":600}},
{"x":1001, "y": {"9.2":60, "9.6":400, "10.1":20, "10.8":320, "11":20, "8.8":722}},
{"x":1002, "y": {"9.8":80, "9.9":600, "9.2":40}},
{"x":1003, "y": {"10.1":60, "10.3":400, "10.8":360, "9.6":88}},
{"x":1004, "y": {"9.8":20, "10.4":450}}
];
Как связать это с помощью d3 для создания прямоугольников с атрибутами x=
значение x, y=
ключей объекта y, width=
значения объекта y и height=
любая заданная константа?
По существу, это будет иметь переменное количество прямоугольников для каждого x на основе количества элементов в y
объекте.
Это, действительно, немного сложно, главным образом потому, что ваше свойство y
содержит только один объект, а не массив объектов.
Мое решение здесь использует d3.entries
, который, согласно API:
Возвращает массив, содержащий ключи свойств и значения указанного объекта (ассоциативный массив). Каждая запись представляет собой объект с атрибутом key и value, например {key: "foo", значение: 42}. Порядок возвращаемого массива не определен. (акцент мой)
Важно иметь массив, поэтому мы можем привязать данные (так как метод data()
принимает только три вещи: массив, функцию или ничего).
Итак, в этом решении я использую внешние объекты для добавления групп...
var groups = svg.selectAll(null)
.data(data)
.enter()
.append("g");
... и объект y
каждого внешнего объекта для добавления прямоугольников...
var rects = groups.selectAll(null)
.data(function(d) {
return d3.entries(d.y)
})
.enter()
.append("rect");
... и используя d3.entries()
для преобразования объекта в массив объектов, который может использоваться с data()
.
Вот демонстрация (я изменил ваши фактические значения, поэтому мы можем лучше видеть прямоугольники):
var data = [{
"x": 100,
"y": {
"10": 100,
"20": 200,
"26": 300,
"35": 400
}
}, {
"x": 20,
"y": {
"50": 60,
"59.6": 400,
"70.1": 20,
"80.8": 320,
"88": 20,
"98.8": 722
}
}, {
"x": 30,
"y": {
"109.8": 80,
"119.9": 600,
"139.2": 40
}
}, {
"x": 10,
"y": {
"150.1": 60,
"170.3": 400,
"190.8": 360,
"209.6": 88
}
}, {
"x": 50,
"y": {
"259.8": 20,
"280.4": 450
}
}];
var colours = d3.scaleOrdinal(d3.schemeCategory10);
var constant = 5;
var svg = d3.select("svg");
var groups = svg.selectAll(null)
.data(data)
.enter()
.append("g")
.style("fill", function(d, i) {
return colours(i)
})
var rects = groups.selectAll(null)
.data(function(d) {
return d3.entries(d.y)
})
.enter()
.append("rect");
rects.attr("y", function(d) {
return +d.key
})
.attr("width", function(d) {
return d.value
})
.attr("height", constant)
.attr("x", function(d) {
return d3.select(this.parentNode).datum().x;
})
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg width="600" height="300"></svg>
Обратите внимание на то, как я получаю значения y
и width
и, особенно, значение x
(доступ к исходной системе координат).
y
являются идеальным решением с точки зрения извлечения данных, а не обязательным. Если может быть более чистое решение с некоторой реорганизацией значений y, например, для возврата массива ключей и значений, я мог бы изменить изменение данных для возврата такого результата или изменить его в самом слое JS. Еще раз спасибо!