введите описание изображения здесь У меня есть следующие данные, с помощью которых я построил дерево d3, где каждый узел представляет собой прямоугольник. Теперь я хочу нарисовать n кругов на каждом прямоугольнике (где n - значение 'minor' в каждом узле (см. Данные), но я не уверен, какой самый простой способ добиться этого.

// Data
{
"minor": 1,
"critical": 0,
"children": [{
    "minor": 2,
    "critical": 0,
    "children": [{
        "minor": 3,
        "critical": 0,
        },
        {
        "minor": 2,
        "critical": 1,
        },
        {
        "minor": 1,
        "critical": 1,
        }]
    }]
}

// JS
  const nodeEnter = node.enter()
    .append('g')
    .attr('class', 'node')
    .style('font-size', '12px')
    .attr("transform", function (d) {
      return "translate(" + source.y0 + "," + source.x0 + ")";
  })
  .on('click', click);

  // Add Rectangle for the nodes
  nodeEnter.append('rect')
    .attr('class', 'node')
    .attr("width", function (d) { return d.children || d._children ? 150 : 350 })
    .attr("height", 70)
    .attr('stroke', '#ccc')
    .attr('stroke-width', '1');
0
suneet 6 Окт 2020 в 07:28

1 ответ

Лучший ответ

Вы можете использовать d3.range для создания массива определенной длины. Затем вы можете обращаться с этим массивом, как с любой другой структурой данных d3.

const nCircles = 5;
const radius = 8;
const padding = 2;

d3.select('svg')
  .selectAll('circle')
  .data(d3.range(nCircles))
  .enter()
  .append('circle')
  .attr('cx', function(_, i) {
    return radius + padding + i * 2 * (radius + padding);
  })
  .attr('cy', radius + padding)
  .attr('r', radius)
  .attr('fill', 'darkred');
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg></svg>

В качестве альтернативы вы можете использовать полностью решение ES6, но оно излишне сложное:

const array = new Array(nCircles).fill(undefined).map(function(_, i) { return i; });

Из ваших данных я понял, что каждый узел имеет атрибуты minor и critical. Теперь, чтобы обновить шары недавно вставленных узлов, вы можете использовать

nodeEnter
    .selectAll('.minor')
    // Here you take the data from the node and transform it into
    // the data for the circles. This is what makes it generic.
    .data(function(d) { d3.range(d.minor))
    .enter()
    .append('circle')
    .classed('minor', true)
    .attr('cx', function(_, i) {
      return radius + padding + i * 2 * (radius + padding);
    })
    .attr('cy', radius + padding)
    .attr('r', radius)
    .attr('fill', 'darkyellow');

// And for critical messages:
nodeEnter
    .selectAll('.critical')
    .data(function(d) { d3.range(d.critical))
    .enter()
    .append('circle')
    .classed('critical', true)
    .attr('cx', function(_, i) {
      // To position it next to the minor circles, we need to
      // know how many there are
      const nMinorCircles = d3.select(this).select('.minor').size();
      return radius + padding + 2 * (radius + padding) * (i + nMinorCircles);
    })
    .attr('cy', radius + padding)
    .attr('r', radius)
    .attr('fill', 'darkred');
1
Ruben Helsloot 6 Окт 2020 в 11:44