2015-06-07 3 views
0

У меня есть график рассеяния с D3, и я пытаюсь добавить круги к выбору на основе изменения данных. Я передаю выбор данных до двух функций: render и update. Функция render представляет собой начальную визуализацию, а update имеет методы enter() и exit(). Я могу легко добавить исходный набор данных и не получить круги больше в наборе данных для выхода. Я использую d.id в качестве заполнителя d3.D3js exit() и обновление работает, не может войти()

Проблема: когда я пытаюсь добавить enter() добавленные точки данных, ничего не происходит. Я проверил длину нового выбора данных, и он больше, чем предыдущий. В DOM меньший набор данных остается (circle s, которые уже были там), но новые круги не входят, хотя набор данных изменился.

Я просмотрел множество руководств по объединению данных, и я думаю, что я соответствующим образом назвал методы enter() и exit(). Что дает?

Вот мой код:

  var container = angular.element(document.querySelector('.chart-container'))[0]; 
      var margin = { 
        top: container.clientHeight/12, 
        right: container.clientWidth/14, 
        bottom: container.clientHeight/10, 
        left: container.clientWidth/11 
       }; 
      var w = container.clientWidth - margin.left - margin.right; 
      var h = container.clientHeight - margin.top - margin.bottom; 

      // ******** **************** ******** // 
      // ******** INITIAL RENDER ******** // 
      function render(input) { 

       console.log(Object.keys(input).length); 

       var xScale = d3.scale.linear() 
        .domain([0, d3.max(input, function(d) { return d["ctc"]; })]) 
        .range([0, w]) 
        .nice(); 

       var yScale = d3.scale.linear() 
        .domain([0, d3.max(input, function(d) { return d["ttc"]; })]) 
        .range([h, 0]) 
        .nice(); 

       var rScale = d3.scale.linear() 
        .domain([0, d3.max(input, function(d) { return d["effective"]; })]) 
        .range([2, 15]); 

       // *********** // 
       // SVG ELEMENT // 
       var svg = d3.select('.chart-container') 
        .append('svg') 
        .attr('class', 'scatter') 
        .attr('viewBox', '0, 0, ' + Math.round(w + margin.left + margin.right) + ', ' + Math.round(h + margin.top + margin.bottom)) 
        .attr('preserveAspectRatio', 'xMinYMin') 
        // used to center element and make use of margins 
        .append('g') 
        .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'); 

       // add circles in group 
       var circles = svg.append('g') 
        .attr('class','circles') 
        .attr('clip-path','url(#chart-area)'); 

       // add individual circles 
       var circle = circles.selectAll('circle') 
        .data(input, function(d) {return d.id;}) 
        .enter() 
        .append('circle') 
        .attr('class', 'circle') 
        .attr('cx', function(d) { return xScale(d["ctc"]); }) 
        .attr('cy', function(d) { return yScale(d["ttc"]); }) 
        .attr('r', function(d) { return rScale(d["effective"]); }) 
        .attr('fill', function(d, i) { return d["effective"]; }) 
        .on('mouseover', function(d) { 
         tooltip.style('visibility', 'visible'); 
         return tooltip.text(d["technology"]); 
        }) 
        .on("mousemove", function(){ return tooltip.style("top", 
         (d3.event.pageY-10)+"px").style("left",(d3.event.pageX+10)+"px");}) 
        .on("mouseout", function(){return tooltip.style("visibility", "hidden");}) 


       // append clip path 
       svg.append('clipPath') 
        .attr('id','chart-area') 
        .append('rect') 
        .attr('class', 'rect') 
        .attr('x', 0) 
        .attr('y', 0) 
        .attr('width', w) 
        .attr('height', h); 

      }; 

      // ******** **************** ******** // 
      // ******** UPDATE ******** // 
      function update(updateObject) { 

       var input = updateObject; 

       var xScale = d3.scale.linear() 
        .domain([0, d3.max(input, function(d) { return d["ctc"]; })]) 
        .range([0, w]) 
        .nice(); 

       var yScale = d3.scale.linear() 
        .domain([0, d3.max(input, function(d) { return d["ttc"]; })]) 
        .range([h, 0]) 
        .nice(); 

       var rScale = d3.scale.linear() 
        .domain([0, d3.max(input, function(d) { return d["effective"]; })]) 
        .range([2, 15]); 

       var svg = d3.select('svg') 
        .data(input) 
        .attr('viewBox', '0, 0, ' + Math.round(w + margin.left + margin.right) + ', ' + Math.round(h + margin.top + margin.bottom)) 
        .attr('preserveAspectRatio', 'xMinYMin') 
        .append('g') 
        .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'); 

       // BIND TO DATA 
       var circles = d3.selectAll('circle') 
        .data(input, function(d) { return d.id; }); 

       // Circles Enter 
       circles.enter() 
        .insert('svg:circle') 
        .attr('class', 'circle') 
        .attr('cx', function(d) { return xScale(d["ctc"]); }) 
        .attr('cy', function(d) { return yScale(d["ttc"]); }) 
        .attr('r', function(d) { return rScale(d["effective"]); }); 
        /* 
        .on('mouseover', function(d) { 
         tooltip.style('visibility', 'visible'); 
         return tooltip.text(d["technology"]); 
        }) 

        .on("mousemove", function(){ return tooltip.style("top", 
         (d3.event.pageY-10)+"px").style("left",(d3.event.pageX+10)+"px");}) 
        .on("mouseout", function(){return tooltip.style("visibility", "hidden");}) 
        */ 

       // UPDATE 
       circles.transition() 
        .duration(1000) 
        .attr('cx', function(d) { return xScale(d["ctc"]); }) 
        .attr('cy', function(d) { return yScale(d["ttc"]); }) 
        .attr('r', function(d) { return rScale(d["effective"]); }); 


       // EXIT 
       circles.exit() 
        .transition() 
        .duration(500) 
        .attr('r', 0) 
        .style('opacity', 0) 
        .style('fill', 'gray') 
        .remove();  

      } 

Update здесь является codepen для тестирования: http://codepen.io/himmel/pen/JdNJMM

+0

использование 'enter()' кажется правильным, я думаю, вы могли бы создать скрипку/фрагмент или что-то для тестирования? – jhinzmann

+0

Я создаю его сейчас, скоро обновится. – Himmel

+0

Кстати, всегда полезно использовать 'd3.scale.sqrt()' для радиуса окружностей, потому что с 'd3.scale.linear()' площадь круга не пропорциональна value;) – jhinzmann

ответ

1

Проблемы с кодом, который вы пытаетесь использовать объект в качестве данных. d3.selection.data() принимает массив, а не объект. См. the d3 wiki для получения дополнительной информации о функции data().

Я создал версию вашего кодекса updated. Я изменил данные на массив и применил правильный conventional margin. Более того, я упростил код, удалив двойную инициализацию весов и элемент svg.

+0

Итак, в моей начальной публикации вероятная проблема заключалась в том, что вместо того, чтобы иметь объекты (без хэш-ключей) внутри массива, у меня были объекты с хэш-ключами внутри объекта? – Himmel

+0

точно. как объяснено в моем ответе, вы не можете использовать 'data()' с объектом. он должен быть массивом. – jhinzmann

+1

однако есть и другие проблемы с вашим кодом. например, вы создаете второй svg в функции обновления вместо использования уже созданного. Вот что я имел в виду с двойной инициализацией. – jhinzmann

Смежные вопросы