Как изменить порядок DOM элементов SVG, основываясь на их значениях данных в динамически изменяющихся d3 vis? - PullRequest
1 голос
/ 10 апреля 2019

У меня есть набор данных json, который я динамически визуализирую аналогично в этом примере с использованием библиотеки d3.js.

Однако мне бы хотелось, чтобы столбцы меняли свое положение в пределахграфик в нижней позиции должен находиться «позади» тех, которые находятся в более высоких позициях.Для этого я хотел бы установить z-индекс на основе данных (бары с низкими значениями имеют более низкий z-индекс и, таким образом, будут располагаться за столбцами с большим значением).К сожалению, SVG использует порядок документов в качестве z-индекса, поэтому мне нужно будет переупорядочивать столбцы (переменная chartRow в примере) внутри документа каждый раз, когда меняется диаграмма.

Есть ли какие-либоспособ достижения этой цели?

1 Ответ

1 голос
/ 10 апреля 2019

Изменение порядка элементов в DOM

Чтобы изменить порядок элементов в DOM с помощью d3, вы можете использовать selection.sort и selection.order :

// Sort & then order:
selection.sort(function(a,b) {
  return a.property - b.property; 
})
.order();

Selection.sort сортирует выборку на основе связанных данных, a и b каждый представляют данные, привязанные к одному элементу.Результирующее поведение, по сути, такое же, как Array.sort, но вместо использования массива вы сортируете элементы в выделении, используя их связанные данные.Содержимое функции, предоставляемой selection.sort (функция сравнения), определяет порядок сортировки:

Функция сравнения, по умолчанию восходящая, передается для сравнения данных двух элементов a и b.Он должен возвращать либо отрицательное, положительное или нулевое значение.Если отрицательно, то a должно быть до b;если положительный, то a должно быть после b;в противном случае a и b считаются равными, а порядок произвольным.( docs )

Как только у нас будет отсортированный выбор, мы можем применить selection.order(), который повторно вставляет каждый элемент в DOM в соответствии с порядком выбора.Помните, что элементы, нарисованные первыми, могут быть покрыты элементами, нарисованными позже - первое в выделении означает потенциально под всем.


Так что, если бы у нас было что-то подобное, где перекрывающиеся столбцы рисуются последовательно на основе порядкамассив данных:

enter image description here

var bars = [
  {value: 100},
  {value: 50},
  {value: 200},
  {value: 70},
  {value: 40},
  {value: 120}
];

var height = 200;
var width = 500;

var svg = d3.select("body")
  .append("svg")
  .attr("height",height)
  .attr("width",width);

var bars = svg.selectAll("rect")
  .data(bars)
  .enter()
  .append("rect")
  .attr("width", 45)
  .attr("height", function(d) { return d.value; })
  .attr("y", function(d) { return height-d.value; })
  .attr("x", function(d,i) { return i * 30 + 50; })
  .attr("fill", function(d,i){ return d3.schemeCategory10[i]; })
  .attr("stroke","black")
  .attr("stroke-width",1);


// Order the bars:
bars.sort(function(a,b) {
  return b.value - a.value;
}).order();
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>

Мы можем подтянуть маленькие столбики, скажем, для большей наглядности с сортировкой и порядком:

enter image description here

var bars = [
  {value: 100},
  {value: 50},
  {value: 200},
  {value: 70},
  {value: 40},
  {value: 120}
];

var height = 200;
var width = 500;

var svg = d3.select("body")
  .append("svg")
  .attr("height",height)
  .attr("width",width);

var bars = svg.selectAll("rect")
  .data(bars)
  .enter()
  .append("rect")
  .attr("width", 45)
  .attr("height", function(d) { return d.value; })
  .attr("y", function(d) { return height-d.value; })
  .attr("x", function(d,i) { return i * 30 + 50; })
  .attr("fill", function(d,i){ return d3.schemeCategory10[i]; })
  .attr("stroke","black")
  .attr("stroke-width",1);

  
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>

Перестановка на основе заказа

Как вы можете видеть выше, это не сбрасывает xили y атрибут каждой полосы, чтобы отразить порядок на z (как в вашем примере).Как и в моем базовом примере выше, мы можем сбросить значения x на основе i (это можно сделать и путем изменения масштаба, но этого достаточно, чтобы быть отдельным вопросом и ответом):

var bars = [
  {value: 100},
  {value: 50},
  {value: 200},
  {value: 70},
  {value: 40},
  {value: 120}
];

var height = 200;
var width = 500;

var svg = d3.select("body")
  .append("svg")
  .attr("height",height)
  .attr("width",width);

var bars = svg.selectAll("rect")
  .data(bars)
  .enter()
  .append("rect")
  .attr("width", 45)
  .attr("height", function(d) { return d.value; })
  .attr("y", function(d) { return height-d.value; })
  .attr("x", function(d,i) { return i * 30 + 50; })
  .attr("fill", function(d,i){ return d3.schemeCategory10[i]; })
  .attr("stroke","black")
  .attr("stroke-width",1)
  
bars = bars.sort(function(a,b) {
  return a.value - b.value;
}).order();

bars.transition()
  .attr("x", function(d,i) { return i * 30 + 50; })
  .delay(500)
  .duration(2000);
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>

См. Также: вопрос и ответ, который во многом похож на ваш пример: сортировка и упорядочениеиспользуется при переходе как длины слитков, так и порядка слитков.

...