Добавить движущиеся круги для перехода вложенных путей в d3.js

#d3.js

#d3.js

Вопрос:

Я хочу добавить круги в svg для каждого пути, созданного гнездом, чтобы круги вели к рисованию путей. Аналогично этой скрипке, но с вложенными данными.

Вот некоторый воспроизводимый пример кода в версии d3.v4 и доступный для выполнения фрагмент путей, к которым я хотел бы добавить круги:

 var data=[{group:1,x:6,y:8},
  {group:1,x:4,y:4},
  {group:1,x:1,y:2},
  {group:2,x:8,y:3},
  {group:2,x:1,y:6},
  {group:2,x:7,y:5},
  {group:3,x:7,y:1},
  {group:3,x:6,y:6},
  {group:3,x:3,y:2}];

var height = 600
var width = 800

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

var colours = ["#0000FF",
  "#FF0000",
  "#00FF00"
];

var line = d3.line()
  .x(function(d, i) {
    return d.x * 20;
  })
  .y(function(d, i) {
    return d.y * 20;
  })
  .curve(d3.curveNatural);

function tweenDash() {
  var l = this.getTotalLength(),
    i = d3.interpolateString("0,"   l, l   ","   l);
  return function(t) {
    return i(t);
  };
}

function transition(selection) {
  selection.each(function() {
    d3.select(this).transition()
      .duration(5000)
      .attrTween("stroke-dasharray", tweenDash)
      .ease(d3.easeLinear);
  })
}

var dataGroup = d3.nest()
  .key(function(d) {
    return d.group;
  })
  .entries(data);

dataGroup.forEach(function(d, i) {

  var path = svg.append("path")
    .attr("d", line(d.values))
    .attr("stroke", colours[i])
    .attr("stroke-width", 1)
    .attr("fill", "none");

  transition(d3.selectAll("path"))

});  
 <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.13.0/d3.min.js"></script>  

Ответ №1:

Используя этот пример, я добавил круги к вашим путям. Обратите внимание, что они не идеально повторяют путь, но это покрывается увеличением их радиуса.

Пару раз вы используете .forEach() или .each() для перебора данных или выделения, но вам это не нужно. d3 предназначен для одновременной работы с массивами данных, поэтому вы можете легко применить одно преобразование к нескольким элементам, каждый из которых использует свои собственные данные. Привыкание к этому может значительно улучшить ваш опыт работы с разработчиками.

 var data = [{
    group: 1,
    x: 6,
    y: 8
  },
  {
    group: 1,
    x: 4,
    y: 4
  },
  {
    group: 1,
    x: 1,
    y: 2
  },
  {
    group: 2,
    x: 8,
    y: 3
  },
  {
    group: 2,
    x: 1,
    y: 6
  },
  {
    group: 2,
    x: 7,
    y: 5
  },
  {
    group: 3,
    x: 7,
    y: 1
  },
  {
    group: 3,
    x: 6,
    y: 6
  },
  {
    group: 3,
    x: 3,
    y: 2
  }
];

var height = 600
var width = 800

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

var colours = ["#0000FF",
  "#FF0000",
  "#00FF00"
];

var line = d3.line()
  .x(function(d, i) {
    return d.x * 20;
  })
  .y(function(d, i) {
    return d.y * 20;
  })
  .curve(d3.curveNatural);

function tweenDash() {
  var l = this.getTotalLength(),
    i = d3.interpolateString("0,"   l, l   ","   l);
  return function(t) {
    return i(t);
  };
}

function tweenCircle(i, paths) {
  var path = paths
    .filter(function(_, j) { return i === j; })
    .node();
  var l = path.getTotalLength();

  return function(t) {
    var p = path.getPointAtLength(t * l);
    return "translate("   [p.x, p.y]   ")";
  };
}

function transition(path, circle) {
  path.transition()
    .duration(2000)
    .attrTween("stroke-dasharray", tweenDash)
    .ease(d3.easeLinear);

  circle.transition()
    .duration(2000)
    .attrTween("transform", function(d, i) { return tweenCircle(i, path); })
    .ease(d3.easeLinear);
}

var dataGroup = d3.nest()
  .key(function(d) {
    return d.group;
  })
  .entries(data);

var path = svg.selectAll('path')
  .data(dataGroup)
  .enter()
  .append("path")
  .attr("d", function(d) { return line(d.values); })
  .attr("stroke", function(d, i) { return colours[i]; })
  .attr("stroke-width", 1)
  .attr("fill", "none");

var circle = svg.selectAll('circle')
  .data(dataGroup)
  .enter()
  .append("circle")
  .attr("fill", function(d, i) { return colours[i]; })
  .attr("transform", function(d) {
    const start = d.values[0];
    return "translate("   [start.x, start.y]   ")"; })
  .attr("r", 8);

transition(path, circle);  
 <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.13.0/d3.min.js"></script>