2016-05-18 2 views
0

Я пытаюсь создать полностью динамический график Sunburst, используя d3.js. Примеры и учебные пособия, которые я обнаружил, имеют тенденцию использовать существующие/полностью заполненные структуры данных, которые могут иметь возможность изменять значение существующих дуг, но не позволяют добавлять дочерние дуги по мере необходимости.d3.js sunburst с динамически построенной обновляемой структурой данных

Подобным образом у меня есть учебные пособия, которые позволяют новым наборам данных просто заменять существующую структуру и начинать рисовать с нуля. Это не то поведение, которое я пытаюсь реализовать.

Мне нужен динамически построенный граф, основанный на поступающих данных, поскольку он предоставляется.

Я могу добавить детей в конец набора данных, перейти и отобразить результаты без проблем. Проблема возникает всякий раз, когда я вставляю дочерний объект где-то в существующую структуру, d3 selectAll() не работает должным образом. Он включает новую дугу (которая еще не нарисована), в результате чего любые оставшиеся дуги отображаются неправильно. Затем при переходе дуг, кажется, получается дуги Dom ID, и данные, которые он предположительно представляет, смешиваются. Новая дуга не видна, и существует пустое пространство, где должна быть размещена новая дуга.

Чтобы быть ясно, мое намерение состоит в том:

  1. Добавить в существующую структуру данных, позволяя новые дети, которые будут добавлены, когда новая информация предоставляется
  2. Для перехода существующих дуг открытия пространства для новых дуг до они создаются и нарисовано

Сломался в четыре шага jsfiddle например:

  1. Инициализация графа (рисует невидимый «корень» дуги)

    {имя: "A_0", дети: []}

  2. Добавление первых данных по уходу за детьми и это дети корень

    {имя: "A_0", дети: [ {имя: "A_1", дети: [{имя: "a_2", дети: [{имя: "a_3"}]}]} ]}

  3. Добавление второго ребенка и основных детей к корню

    {name: "a_0", children: [ {name: "a_1", children: [{name: "a_2", children: [{name: "a_3" }]}]}, {имя: "A_4", дети: [{имя: "A_5", дети: [{имя: "a_6"}]}]} ]}

  4. Вставка другого ребенка в течение существующая дуга a_2

    {имя: "A_0", дети: [ {имя: "a_1", дети: [ {имя: "a_2", дети: [ {имя: "a_3"}, {Имя: "a_7"} ]} ]}, {имя: "A_4", дети: [ {имя: "A_5", дети: [ {имя: "a_6"} ]} ]} ]}

Шаг 1 работает нормально

Шаг 2 рисует дуги должным образом

Шаг 3 переходы существующих дуг и добавляет новые дуги к графу

Шаг 4 некоторые неожиданные результаты поведения.

При переходе существующих и ввода новых дуг некоторые из дуг «прыгать вокруг» потерять правильную ассоциацию с их соответствующими данными Конечный результат, как представляется:

  • A_0 - правильно
  • a_1 & a_2 - выглядеть правильно
  • a_3 - сократилась до размещения нового родственный a_7 - ожидаемое поведение
  • A_4 - исчезает
  • A_5 - прыгает вниз, где A_4 должен быть
  • a_6 - (похоже) она дублируется и существует лишь однажды, где он должен быть и где A_5 должны быть
  • a_7 - не отображается, место, где оно должно быть пустое пространство и представляется связанным с данными a_6

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

  • В попытке обновить график SelectAll() для существующих дуг включает в себя (A_0, a_1, a_2, a_3, A_4, A_5, a_7). Если существующий a_6 не включен в selectAll(), но a_7 (который не был нарисован).
  • ввода() функция, как представляется, работать на существующих a_6, который затем рассматривается как новая дуга

Похоже, я был на правильном пути, получить всю дорогу до a_6, но я не понял, из-за причины поведения при добавлении a_7.

jsFidde выполняет шаги, как описано выше, в том числе:

  • Уникальные цвета для каждой дуги
  • таблица отображения названия каждой дуги,
  • Если дуга обрабатывается с помощью d3js 'selectAll() (т. е. «существующий») или введите() (т.е. «новый»),
  • Указатель d3, который в настоящее время назначается при рисовании существующих или новых дуг.
  • Ожидаемого конечное положения, где каждая дуга должна появиться после любого перехода,
  • Arctween информации как дуга осуществляется переход от своего прежнего места на новое место и

Вопросы:

  • Что происходит, это может привести к такому поведению на шаге 4?
  • Есть ли способ обеспечить целостность между каждой дугой и данными, которые она представляет?
  • Есть ли способ вставить детей в существующую структуру или обновить график в этой динамичной усадьбе?

Рабочий пример на jsfiddle https://jsfiddle.net/mfitzgerald/j2eowwya/

var dataObj = { name:"a_0", color: "none" }; 
var height = 300; 
var width = 500; 
var radius = Math.min(width, height)/2; 
var graph = d3.select("#graph") 
    .attr('height', height) 
    .attr('width', width) 
    .append("g") 
     .attr("transform", "translate(" + width/2 + "," + height/2 + ")"); 

var partition = d3.layout.partition() 
      .sort(null) 
      .size([2 * Math.PI, radius * radius]) 
      .value(function(d, i) { return 1; }); 
var arc = d3.svg.arc() 
    .startAngle(function(d) { if (isNaN(d.x)) { d.x = 0; } d.x0 = d.x; return d.x; }) 
    .endAngle(function(d) { if (isNaN(d.dx)) { d.dx = 0; } d.dx0 = d.dx; return d.x + d.dx; }) 
    .innerRadius(function(d) { if (isNaN(d.y)) { d.y = 0; } d.y0 = d.y; return Math.sqrt(d.y); }) 
    .outerRadius(function(d) { if (isNaN(d.dy)) { d.dy = 0; } d.dy0 = d.dy; return Math.sqrt(d.y + d.dy); }); 

var arcTween = function(a) { 
    var i = d3.interpolate({x: a.x0, dx: a.dx0, y: a.y0, dy: a.dy0}, a); 
    return function(t) { 
     var b = i(t); 
     a.x0 = b.x; 
     a.dx0 = b.dx; 
     a.y0 = b.y; 
     a.dy0 = b.dy; 
     displayStats("arctween", b); 
     return arc(b); 
    }; 
} 

// Root Arc 
graph.datum(dataObj).selectAll('path.arc') 
    .data(partition.nodes) 
    .enter() 
    .append('path') 
     .attr('class', function(d) { return "arc " + d.name; }) 
     .attr("d", arc) 
     .attr("id", function(d, i) { return "path_"+i; }) 
     .attr("name", function(d) { return d.name; }) 
     .style("fill", "none"); 


function updateGraph() { 
    console.log("Update Graph"); 
    console.log(dataObj); 

    var update = graph.datum(dataObj).selectAll('path.arc') 
       .data(partition.nodes); 

    // Move existing Arcs 
    update.each(function(d, i) { 
      displayStats("target", d, i, "existing"); 
      var domId = $(this).attr("id"); 
      console.log("["+i+"] Exist Arc name:"+d.name+", dom_id:"+domId); 
     }) 
     .transition() 
      .delay(function(d, i) { return i * 250; }) 
      .duration(1500) 
      .attrTween("d", arcTween); 

    // Add New Arcs 
    update.enter().append('path') 
     .attr('class', function(d, i) { return "arc "+d.name; }) 
     .attr("d", arc) 
     .attr("id", function(d, i) { 
      var domId = "path_"+i; 
      console.log("["+i+"] NEW Arc name:"+d.name+", dom_id:"+domId); 
      displayStats("target", d, i, "new"); 
      return domId; 
     }) 
     .style("stroke", "#fff") 
     .style("fill", function(d) { return d.color; }) 
     .style("opacity", 0) 
     .transition() 
      .delay(function(d, i) { return i * 250; }) 
      .duration(1500) 
      .style("opacity", .5) 
      .attrTween("d", arcTween); 
} 
+0

Похоже, вам понадобится [использовать ключевую функцию] (https://bost.ocks.org/mike/constancy/) при присоединении данных к '.data()', чтобы старые данные привязывались к старые объекты и новые данные привязаны к новым объектам, а не просто привязываются индексом в массиве. – Gordon

+0

Это трюк! Я разработал jsfiddle с исправлением [здесь] (https://jsfiddle.net/mfitzgerald/qvwcc4cf/). Переходы должны быть изменены. Но большая проблема была решена! Спасибо за помощь –

ответ

0

@Gordon ответил на вопрос. Проблема была решена путем добавления key function при присоединении к .data() в коде updateGraph.

Forked пример на jsfiddle

var update = graph.datum(dataObj).selectAll('path.arc') 
      .data(partition.nodes, function(d) { return d.name; }); 

Я считаю, что ответы на вопросы, являются:

  • .data,() функция использует индексированный массив, который только однозначно идентифицирует каждую дугу с учетом любых новых дуг присоединяются к концу массива. После того, как он вставлен, это приведет к смещению данных, графических дуг и связанных идентификаторов DOM.
  • Использование ключевой функции, как предлагает Gordon, позволяет уникальную идентификацию определенных узлов, поддерживая синхронизацию данных и графиков, как ожидалось.

Обновление

Дополнительная модификация должна быть сделана как DOM-идентификатор был установлен с помощью индекса массива элемента данных все еще будет инвалид ассоциации с DOM и лежащим в основе график/данные.

Это приведет к 2-значным идентификаторам a_4 DOM. Вместо использования индекса массива с использованием Node Name в качестве DOM-идентификатора должна быть правильной эта ассоциация.