Есть несколько способов сделать то, что вы хотите использовать только D3, без каких-либо других библиотек и без изменяя данные. Один из них использует groups
для обработки «более высоких» уровней данных (относительно вложенных данных). Давайте посмотрим его в этом коде:
Во-первых, я издевался до набора данных, как ваша:
var data = [
{name: "male",
values: [{ x: 123,y: 234},
{ x: 432,y: 221},
{ x: 199,y: 56}]
},
{name: "female",
values: [{ x: 223,y: 111},
{ x: 67,y: 288},
{ x: 19, y: 387}]
}
];
Это данные, которые мы собираемся использовать.Я собираюсь сделать график рассеяния здесь (как пример), так, давайте установим домены для весов доступа второго уровня данных (x
и y
внутри values
):
var xScale = d3.scaleLinear().range([20, 380])
.domain([0, d3.max(data, function(d){
return d3.max(d.values, function(d){
return d.x;
})
})]);
var yScale = d3.scaleLinear().range([20, 380])
.domain([0, d3.max(data, function(d){
return d3.max(d.values, function(d){
return d.y;
})
})]);
Теперь самый важная часть: мы будем привязки данных к «группам», а не к окружности элементов:
var circlesGroups = svg.selectAll(".circlesGroups")
.data(data)
.enter()
.append("g")
.attr("fill", function(d){ return (d.name == "male") ? "blue" : "red"});
После того, как в первом уровне данных у нас есть 2 объекта, D3 будут созданы 2 группы для нас.
Я также использовал группы, чтобы установить цвета окружностей: если name
является «мужским», круг синего цвета, в противном случае это красное:
.attr("fill", function(d){ return (d.name == "male") ? "blue" : "red"});
Теперь, когда созданы группы, мы создаем круги в соответствии с values
в данных каждой группы, связывание данных следующим образом:
var circles = circlesGroups.selectAll(".circles")
.data(function(d){ return d.values})
.enter()
.append("circle");
Здесь function(d){ return d.values}
будет связывать данные с кругами в соответствии с объектами внутри values
массивов.
И затем вы позиционируете свои круги. Это весь код, нажмите кнопку «запустить фрагмент кода», чтобы увидеть его:
var data = [
{name: "male",
values: [{ x: 123,y: 234},
{ x: 432,y: 221},
{ x: 199,y: 56}]
},
{name: "female",
values: [{ x: 223,y: 111},
{ x: 67,y: 288},
{ x: 19, y: 387}]
}
];
var xScale = d3.scaleLinear().range([20, 380])
\t .domain([0, d3.max(data, function(d){
\t \t \t return d3.max(d.values, function(d){
\t \t \t \t return d.x;
\t \t })
\t })]);
\t \t
var yScale = d3.scaleLinear().range([20, 380])
.domain([0, d3.max(data, function(d){
\t \t \t return d3.max(d.values, function(d){
\t \t \t \t return d.y;
\t \t })
\t })]);
var xAxis = d3.axisBottom(xScale).tickSizeInner(-360);
var yAxis = d3.axisLeft(yScale).tickSizeInner(-360);
var svg = d3.select("body")
\t .append("svg")
\t .attr("width", 400)
\t .attr("height", 400);
svg.append("g")
\t .attr("class", "x axis")
\t .attr("transform", "translate(0,380)")
\t .call(xAxis);
\t
svg.append("g")
\t .attr("class", "y axis")
\t .attr("transform", "translate(20,0)")
\t .call(yAxis);
\t
var circlesGroups = svg.selectAll(".circlesGroups")
\t .data(data)
\t .enter()
\t .append("g")
\t .attr("fill", function(d){ return (d.name == "male") ? "blue" : "red"});
\t
var circles = circlesGroups.selectAll(".circles")
\t .data(function(d){ return d.values})
\t .enter()
\t .append("circle");
\t \t
circles.attr("r", 10)
\t .attr("cx", function(d){ return xScale(d.x)})
\t .attr("cy", function(d){ return yScale(d.y)});
.axis path, line{
\t stroke: gainsboro;
}
<script src="https://d3js.org/d3.v4.min.js"></script>
спасибо, это работает, но это можно сделать только с чистым JS или d3 без изменения данных ? Я хочу улучшить свои навыки :) – Shawn
@shawn Конечно, вы можете. Underscore.js является открытым исходным кодом, вы можете проверить, как это делается. Это не так сложно понять. Код здесь: http://underscorejs.org/underscore.js Вы не можете легко сделать это с помощью d3 без изменения данных ... Существует способ, но он не оптимизирован. Вы quand делаете данные foreach, затем делаете focus.selectAll по значениям и добавляете круги таким образом. – rm4