Обновление данных макета пачки из вызова JSON и перерисовки

Я экспериментировал с примером упаковки. Однако у меня много проблем с попыткой обновить вещь из нового набора данных JSON и впоследствии обновить ее.

Мой код — это просто модифицированная версия примера пакета кругов:

var diameter = 960,
    format = d3.format(",d");

var pack = d3.layout.pack()
    .size([diameter - 4, diameter - 4])
    .value(function(d) { return d.size; });

var svg = d3.select("body").append("svg")
    .attr("width", diameter)
    .attr("height", diameter)
    .append("g")
    .attr("transform", "translate(2,2)");

var node;

d3.json("data1.json", function(error, root) {

    node = svg.datum(root).selectAll(".node")
      .data(pack.nodes);

    node.enter().append("g")
      .classed("node", true)
      .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });

    node.append("title")
      .text(function(d) { return d.name; });

    node.append("circle")
            .attr("r", 0)
        .on("click", refresh)
            .transition()
            .duration(2000)
        .attr("r", function(d) { return d.r; });

    node.append("text")
      .attr("dy", ".3em")
      .style("text-anchor", "middle")
      .text(function(d) { return d.name });

    node.exit()
        .remove();
});

d3.select(self.frameElement).style("height", diameter + "px");

Это работает, как и ожидалось. Однако я хочу выполнить функцию обновления, которая обновляет диаграмму из новых данных JSON и обновляет ее. Я пробовал приведенный ниже код, но он просто добавляет новый элемент вместо изменения старых, а также не удаляет старые (по-видимому, node.exit.remove() никогда не запускается). Мне интересно, связано ли это с использованием «датума» вместо «данных» и действительно ли в этом отношении выполняется соединение данных:

var refresh = function() {

    d3.json("data2.json", function(error, root2) {

        node = svg.datum(root2).selectAll(".node")
            .data(pack.nodes);

        node.append("title")
            .text(function(d) { return d.name; });

        node.append("circle")
            .attr("r", 0)
            .transition()
            .duration(2000)
            .attr("r", function(d) { return d.r; });

        node.append("text")
            .attr("dy", ".3em")
            .style("text-anchor", "middle")
            .text(function(d) { return d.name });
    });
}

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

Для справки, данные, которые я использую, таковы:

{
    "name": "Names",
    "children": [
        { "name": "John", "size": 100 },
        { "name": "Peter", "size": 200 },
        { "name": "Arnold", "size": 300 },
        { "name": "Rasmus", "size": 400 }
    ]
}

и

{
    "name": "Names",
    "children": [
        { "name": "John", "size": 1000 },
        { "name": "Rasmus", "size": 200 },
        { "name": "Benjamin", "size": 300 },
        { "name": "James", "size": 400 }
    ]
}

person Alex Langberg    schedule 13.09.2013    source источник
comment
Вы правы, что .datum() не вычисляет соединение. Однако .data(), следующее за ним, делает. Однако в вашем коде обновления вы, похоже, обрабатываете только выбор обновления - нет .enter() или .exit().   -  person Lars Kotthoff    schedule 13.09.2013
comment
Спасибо, я совершенно неправильно понял, как вы также должны перерисовывать, например, при вводе (), когда вы обновляете данные.   -  person Alex Langberg    schedule 14.09.2013
comment
У меня это действительно работает очень хорошо! Обязательно сделаю туториал для таких чайников, как я. Если кто-то заглянет сюда и ищет ответ, не стесняйтесь обращаться ко мне.   -  person Alex Langberg    schedule 14.09.2013
comment
Опубликуйте свое решение в качестве ответа!   -  person Adam Pearce    schedule 14.09.2013


Ответы (1)


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

var diameter = 960,
    format = d3.format(",d");

var pack = d3.layout.pack()
    .size([diameter - 4, diameter - 4])
    .value(function(d) { return d.size; });

var svg = d3.select("body").append("svg")
    .attr("width", diameter)
    .attr("height", diameter)
  .append("g")
    .attr("transform", "translate(2,2)");

var node;
var currentJson;
var currentUrl = "data1.json";

var getNewData = function() {

    if(currentUrl == "data1.json") {
        currentUrl = "data2.json";
    }
    else {
        currentUrl = "data1.json";
    }

    d3.json(currentUrl, function(error, data) {
        currentJson = data;
        refresh();
    });
}

var refresh = function() {

    node = svg.selectAll(".node")
                    .data(pack.nodes(currentJson));

    node.enter().append("g")
            .classed("node", true)
            .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; })
        .append("circle")
            .attr("r", 0)
            .on("click", getNewData)
            .transition()
            .duration(2000)
            .attr("r", function(d) { return d.r; });

    node.transition()
        .duration(2000)
        .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });

    node.select("circle")
        .transition()
        .duration(2000)
        .attr("r", function(d) { return d.r; });
}

d3.select(self.frameElement).style("height", diameter + "px");

getNewData();
person Alex Langberg    schedule 14.09.2013
comment
+1 за ответ на свой вопрос. Пожалуйста, примите ваш ответ, когда сможете. - person Christopher Chiche; 16.09.2013
comment
Без проблем. И здорово видеть, насколько вы активны, ребята. :) - person Alex Langberg; 16.09.2013