D3.js v5 строит древовидную "матрицу"

Цель состоит в том, чтобы элегантно добавить несколько небольших древовидных диаграмм в форме матрицы. Я подготовил простую версию предполагаемого результата; прямоугольники и тексты показывают, как должен выглядеть шаблон. Далее необходимо добавить простой двухуровневый древовидный график под прямоугольниками.

Я работаю со структурой данных, в которой данные дерева хранятся в объекте внутри каждого элемента массива объектов:

  var data = [
    {name:"jackie chan", tree: {
      "name": "Top Level",
      "children": [
            { "name": "Fund 1" },
            { "name": "Fund 2" },
            { "name": "Fund 3"}
          ]
    }},
    {name:"jet li", tree: {
      "name": "Top Level",
      "children": [
            { "name": "Fund 1" },
            { "name": "Fund 2" },
            { "name": "Fund 3"},
            { "name": "Fund 4"},
          ]
    }},
...

Фрагмент:

var margins = {top:100, bottom:300, left:100, right:100};

var height = 600;
var width = 900;

var totalWidth = width+margins.left+margins.right;
var totalHeight = height+margins.top+margins.bottom;

var svg = d3.select('body')
.append('svg')
.attr('width', totalWidth)
.attr('height', totalHeight);

var graphGroup = svg.append('g')
.attr('transform', "translate("+margins.left+","+margins.top+")");

  var data = [
    {name:"jackie chan", tree: {
      "name": "Top Level",
      "children": [
            { "name": "Fund 1" },
            { "name": "Fund 2" },
            { "name": "Fund 3"}
          ]
    }},
    {name:"jet li", tree: {
      "name": "Top Level",
      "children": [
            { "name": "Fund 1" },
            { "name": "Fund 2" },
            { "name": "Fund 3"},
            { "name": "Fund 4"},
          ]
    }},
    {name:"donnie yen", tree: {
      "name": "Top Level",
      "children": [
            { "name": "Fund 1" },
            { "name": "Fund 2" },
          ]
    }},
    {name:"chow yun fat", tree: {
      "name": "Top Level",
      "children": [
            { "name": "Fund 1" },
            { "name": "Fund 2" },
            { "name": "Fund 3"},
            { "name": "Fund 4"},
            { "name": "Fund 5"},
          ]
    }},
  ];

  //var formatComma = d3.format(",");

  var columns = 3;
  var spacing = 150;
  var vSpacing = 180;

  var pmG = graphGroup.selectAll('.pm')
    .data(data)
    .enter()
    .append('g')
    .attr('class', 'pm')
    .attr('id', (d, i) => 'pm' + i)
    .attr('transform', (d, k) => {
      var horSpace = (k % columns) * spacing;
      var vertSpace = ~~((k / columns)) * vSpacing;
      return "translate(" + horSpace + "," + vertSpace + ")";
    });

var miniTree = d3.tree()
    .size([150, 75]);

pmG.append('rect')
    .attr('x',0)
    .attr('y',0)
    .attr('width',100)
    .attr('height',25)
    .style('fill',"#003366");

pmG.append('text')
    .attr('x',50)
    .attr('y',-10)
    .attr('text-anchor','middle')
    .text(function(d) {return d.name});

pmG.selectAll(null)
    .data( function(d) {return miniTree(d3.hierarchy(d.tree).descendants().slice(1))})
  .enter().append("path")
    .attr("class", "link")
    .attr("d", function(d) {
       return "M" + d.x + "," + d.y
         + "C" + d.x + "," + (d.y + d.parent.y) / 2
         + " " + d.parent.x + "," +  (d.y + d.parent.y) / 2
         + " " + d.parent.x + "," + d.parent.y;
       });

pmG.selectAll(null)
    .data( function(d) {return miniTree(d3.hierarchy(d.tree).descendants())})
  .enter().append("g")
    .attr("class", function(d) {
      return "node" +
        (d.children ? " node--internal" : " node--leaf"); })
    .attr("transform", function(d) {
      return "translate(" + d.x + "," + d.y + ")"; });
<script src = "https://d3js.org/d3.v5.min.js"></script>

Я думал, что смогу добиться желаемого результата, инкапсулировав все методы дерева в один вызов больших данных, а затем использовать тот же подход для добавления прямоугольников и текстов, как показано в результате фрагмента:

pmG.selectAll(null)
    .data( function(d) {return miniTree(d3.hierarchy(d.tree).descendants().slice(1))})
  .enter().append("path")
    .attr("class", "link")
    .attr("d", function(d) {
       return "M" + d.x + "," + d.y
         + "C" + d.x + "," + (d.y + d.parent.y) / 2
         + " " + d.parent.x + "," +  (d.y + d.parent.y) / 2
         + " " + d.parent.x + "," + d.parent.y;
       });

Однако я получил ошибку:

Ошибка необработанного типа: i.eachBefore не является функцией

Я никогда раньше не видел такой ошибки, и я боюсь, что назревает большая проблема.

Вопрос

Основываясь на моей матричной структуре (посмотрите, как прямоугольники и текст добавляются во фрагмент), как я могу аналогичным образом добавить небольшие «мини-деревья»?

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
2
0
146
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

У вас ошибка при создании дерева:

 .data( function(d) {return miniTree(d3.hierarchy(d.tree).descendants().slice(1)) })

Должно быть:

 .data( function(d) {return miniTree(d3.hierarchy(d.tree)).descendants().slice(1)  })

Вам нужны не потомки d3.hierarchy, а miniTree - пропустили его в первые несколько раз, когда я смотрел на него.

var margins = {top:100, bottom:300, left:100, right:100};

var height = 600;
var width = 900;

var totalWidth = width+margins.left+margins.right;
var totalHeight = height+margins.top+margins.bottom;

var svg = d3.select('body')
.append('svg')
.attr('width', totalWidth)
.attr('height', totalHeight);

var graphGroup = svg.append('g')
.attr('transform', "translate("+margins.left+","+margins.top+")");

  var data = [
    {name:"jackie chan", tree: {
      "name": "Top Level",
      "children": [
            { "name": "Fund 1" },
            { "name": "Fund 2" },
            { "name": "Fund 3"}
          ]
    }},
    {name:"jet li", tree: {
      "name": "Top Level",
      "children": [
            { "name": "Fund 1" },
            { "name": "Fund 2" },
            { "name": "Fund 3"},
            { "name": "Fund 4"},
          ]
    }},
    {name:"donnie yen", tree: {
      "name": "Top Level",
      "children": [
            { "name": "Fund 1" },
            { "name": "Fund 2" },
          ]
    }},
    {name:"chow yun fat", tree: {
      "name": "Top Level",
      "children": [
            { "name": "Fund 1" },
            { "name": "Fund 2" },
            { "name": "Fund 3"},
            { "name": "Fund 4"},
            { "name": "Fund 5"},
          ]
    }},
  ];

  //var formatComma = d3.format(",");

  var columns = 3;
  var spacing = 150;
  var vSpacing = 180;

  var pmG = graphGroup.selectAll('.pm')
    .data(data)
    .enter()
    .append('g')
    .attr('class', 'pm')
    .attr('id', (d, i) => 'pm' + i)
    .attr('transform', (d, k) => {
      var horSpace = (k % columns) * spacing;
      var vertSpace = ~~((k / columns)) * vSpacing;
      return "translate(" + horSpace + "," + vertSpace + ")";
    });

var miniTree = d3.tree()
    .size([150, 75]);

pmG.append('rect')
    .attr('x',0)
    .attr('y',0)
    .attr('width',100)
    .attr('height',25)
    .style('fill',"#003366");

pmG.append('text')
    .attr('x',50)
    .attr('y',-10)
    .attr('text-anchor','middle')
    .text(function(d) {return d.name});


pmG.selectAll(null)
    .data( function(d) { 
        return miniTree(d3.hierarchy(d.tree)).descendants().slice(1) 
        
        })
  .enter().append("path")
    .attr("transform", "translate(-25,20)") // extra positioning.
    .attr("class", "link")
    .attr("d", function(d) {
       return "M" + d.x + "," + d.y
         + "C" + d.x + "," + (d.y + d.parent.y) / 2
         + " " + d.parent.x + "," +  (d.y + d.parent.y) / 2
         + " " + d.parent.x + "," + d.parent.y;
       });

pmG.selectAll(null)
    .data( function(d) {return miniTree(d3.hierarchy(d.tree)).descendants() })
  .enter().append("g")
    .attr("class", function(d) {
      return "node" +
        (d.children ? " node--internal" : " node--leaf"); })
    .attr("transform", function(d) {
      return "translate(" + (d.x - 25) + "," + (d.y+20) + ")"; }) // with extra positioning.
      .append("circle")
path {
  stroke-width: 1px;
  fill: none;
  stroke: #003366;
}

circle {
  r: 5px;
  fill: #003366;
}
<script src = "https://d3js.org/d3.v5.min.js"></script>

Спасибо! Пути, кажется, добавлены, но кажется, что круги все еще отсутствуют. Вероятно, это еще один недосмотр моего кода, не стесняйтесь выбрасывать этот раздел, если вы знаете более простой способ добавления кругов к узлам.

Arash Howaida 17.12.2020 06:40

Я добавил строку для добавления кругов, их радиус указан в css, в противном случае вы просто добавляли элементы g в конец фрагмента.

Andrew Reid 17.12.2020 06:43

Другие вопросы по теме