Выбор выхода d3 появляется пустым даже с уникальным значением id - PullRequest
0 голосов
/ 22 ноября 2018

Я пытаюсь сделать свою собственную версию вращающегося шара с маркерами, похожую на Патрика Стотца .Хотя моя цель не в городах, я использую это сейчас и имею уменьшенную версию этого файла geoJSON для данных (с той же структурой).Проблема в том, что я явно не понимаю, как правильно получить выбор выхода, потому что он всегда пуст, хотя я обновил файл geoJSON, чтобы иметь уникальный идентификатор для каждой функции.

Основное отличие I 'Я пытаюсь представить, что нужно построить 100 городов за раз, затем убрать эти маркеры и нанести следующие 100 с помощью простых эффектов перехода.Я делаю это с помощью функции d3.timer и нарезаю массив данных.

Проблема в том, что мой выбор exit всегда пуст, даже после того, как я добавил уникальный идентификатор, следуя совету thisВопрос .

Вот первая часть js, которая устанавливает глобальные переменные, глобус и страны (очень похоже на оригинал Патрика):

var width  = 820;
var height = 620;
var rScale = d3.scale.sqrt();
var amountPerPixel = 12500;
var max_population = [];
var index = 0;

// Configuration for the spinning effect
var time = Date.now();
var rotate = [0, 0];
var velocity = [0.025, -0];

// set projection type and paremetes
var projection = d3.geo.orthographic()
   .scale(300)
   .translate([(width / 2) + 100, height / 2])
   .clipAngle(90)
   .precision(0.3);

// create path variable, empty svg element and group container
var path = d3.geo.path()
   .projection(projection);

var svg = d3.select("svg");
var g = svg.append("g");

// drawing dark grey spehere as landmass
g.append("path")
   .datum({type: "Sphere"})
   .attr("class", "sphere")
   .attr("d", path)
   .attr("fill", "#0D0D0D");

var countries = svg.append("g").selectAll("path.countries");
var cities = svg.append("g").selectAll("path.cities");

// draw country lines
d3.json("countries.geojson", function(error, data) {

   countries.data(data.features)
      .enter().append("path")
      .attr("class", "countries")
      .attr("d", path)

});

Загрузка следующих трех функцийданные о городах, обрабатывают некоторые основные функции, такие как масштаб для размера и радиуса, наносят начальные данные и вращают земной шар (также похожий на оригинал Патрика с некоторыми изменениями):

d3.json("cities.geojson", function(error, data) {

         // Handle errors getting and parsing the data
         if (error) { console.log(error); return error; }

         // setting the circle size (not radius!) according to the number of inhabitants per city
         amount_array = [];
         for (i = 0; i < data.features.length; i++) {
            data.features[i].properties.id = i;
            amount_array.push(data.features[i].properties.population);
         }
         max_amount = amount_array.sort(d3.descending)[0]

         var rMin = 0;
         var rMax = Math.sqrt(max_amount / (amountPerPixel * Math.PI));
         rScale.domain([0, max_amount]);
         rScale.range([rMin, rMax]);

         path.pointRadius(function(d) {
            return d.properties ? rScale(d.properties.population) : 1;
         });

         initialData = data.features.slice(index,index+100);

         // Drawing transparent circle markers for cities
         cities.data(initialData, function(d) { return d.properties.id; })
            .enter().append("path")
            .attr("id", function(d) {return d.properties.id;})
            .attr("class", "cities")
            .attr("d", path)
            .attr("fill", "#ffba00")
            .attr("fill-opacity", 0.1);

         svg.selectAll("path.cities").transition()
            .duration(250)
            .ease("quad")
            .attr("fill-opacity", 0.75);

         // start spinning!
         spinning_globe();

         // update new data points
         update_points(data);
});

function update_points(data) {

   d3.timer(function() {

      index += 100;

      newData = data.features.slice(index,index+100)

      var newCities = cities.data(newData, function(d) { return d.properties.id; });

      newCities.enter()
         .append("path")
         .attr("id", function(d) {return d.properties.id;})
         .attr("class", "cities")
         .attr("d", path)
         .attr("fill", "#ffba00")
         .attr("fill-opacity", 0.1);


      newCities.exit().remove();

      svg.selectAll("path.cities").transition()
         .duration(250)
         .ease("quad")
         .attr("fill-opacity", 0.75);

      if(newData.length == 0) stop();

   }, 1000);

};

function spinning_globe(){
   d3.timer(function() {

      // get current time
      var dt = Date.now() - time;

      // get the new position from modified projection function
      projection.rotate([rotate[0] + velocity[0] * dt, rotate[1] + velocity[1] * dt]);

      // update cities position = redraw
      svg.selectAll("path.countries").attr("d",path);
      svg.selectAll("path.cities").attr("d", path);

   });

};

Я пробовал грубую игруПринудительный метод удаления маркеров текущего города (svg.selectAll("path.cities").remove()), но время не работает правильно.

Конечным результатом является то, что все работает правильно - шар вращается, города загораются - нони один город не удален.Что я делаю не так?

Ответы [ 2 ]

0 голосов
/ 23 ноября 2018

вы хотите работать с изменением выборок и связывать данные, поэтому не ведите запись (теперь) "старой" выборки.

// init
var cities = svg.append("g");

// init-draw
cities.selectAll(".cities")
    .data(initialData, function(d) { return d.properties.id; })
  .enter()
  .append("path")
    .attr("id", function(d) {return d.properties.id;})
    .attr("class", "cities")
    .attr("d", path)
    .attr("fill", "#ffba00")
    .attr("fill-opacity", 0.1);

// update
var newCities = cities.selectAll(".cities")
    .data(newData, function(d) { return d.properties.id; });
newCities.enter()
  .append("path")
    .attr("id", function(d) {return d.properties.id;})
    .attr("class", "cities")
    .attr("d", path)
    .attr("fill", "#ffba00")
    .attr("fill-opacity", 0.1)
  .merge(newCities);
  .transition()
  .duration(250)
  .ease("quad")
    .attr("fill-opacity", 0.75);

newCities.exit().transition().duration(250).attr("fill-opacity", 0).remove();

Инициализация и обновление почти идентичны, поэтому объедините ихв один, вызовите обновление для init-draw.

0 голосов
/ 22 ноября 2018

Возможно, проблема в том, что вы не переназначаете переменную cities после обновления.Если мое понимание верно, первый раз, когда вызывается update_points, все должно идти как положено.Но когда он будет вызван во второй раз, выбор cities все еще относится к первым 100 городам, которые были удалены.

Решение состоит в том, чтобы назначить cities = newCities.enter()....

Идиоматическийможно назначить cities = newCities.enter() .... .merge(newCities) ..., но в вашем случае это не требуется, поскольку следующие 100 городов не пересекаются с предыдущими городами, а раздел обновления пуст.

...