2017-01-15 4 views
0

Я пытаюсь обновить сложенную гистограмму с переходами при изменении базовых данных. Он каждый раз вызывает одну и ту же функцию «рендеринга» и хорошо работает, когда не задействованы никакие переходы. Однако я хотел бы оживить изменения в значениях, переходя от своего текущего состояния к другому.D3.js анимационное обновление сложенной гистограммы

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

Мой подход был сделать следующее: (. REQ для переходов)

  1. загрузить данные
  2. нагрузки начальных условий
  3. нагрузку конечных условий (в пределах перехода)
  4. Скопируйте текущие данные в другой массив: prevData
  5. Обновить данные после интервала

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

if (prevData.length > 0) { 
          //get the parent key so we know who's data we are now updating 
          var devKey = d3.select(this.parentNode).datum().key; 

          //find the data associated with its PREVIOUS value 
          var seriesData = seriesPrevData.find(function (s) { return (s.key == devKey); }) 
          if (seriesData != null) { 
           //now find the date we are currently looking at 
           var day = seriesData.find(function (element) { return (element.data.Date.getTime() == d.data.Date.getTime()); }); 

           if (day != null) { 
            //now set the value appropriately 
            //console.debug("prev height:" + devKey + ":" + day[1]); 
            return (y(day[0]) - y(day[1])); 
           } 
          } 

         } 

Все, что я делаю, это найти правильный ключ массив (созданный d3.stack()), а затем пытается найти соответствующий предыдущий ввод данных (если он существует). Однако поиск исходных узлов и поиск по массивам для поиска требуемого ключа и соответствующего элемента данных очень затянуты.

Итак, мой вопрос в том, есть ли лучший способ сделать это? или части этого?

  1. Найти ранее связанных значений данных, связанных с этим элементом или текущих значений до того, как изменяется в пределах функции.
  2. Лучше всего найти текущий ключ, а не использовать: d3.select (this.parentNode) ...? Я пробовал передавать ключевые значения, но, похоже, не понимаю. Лучшее, что я достиг, - это передать ключевую функцию родителям и найти его так, как описано выше.

Извините за длинный пост, я просто потратил целый день на разработку своего решения, разочаровавшись в том, что все, что мне действительно нужно, это предыдущие значения элемента. Имея, чтобы сделать все эти «гимнастику», чтобы получить то, что мне нужно было, кажется, очень «ип» D3.js как :-)

Благодарности

+0

Я не уверен, что я понял вашу проблему. Тем более, почему вы делаете некоторые явные текущие/предыдущие подготовки данных, для меня непонятно.В принципе, нужно обрабатывать данные в d3 и затем использовать методы «enter» и «exit» для обработки дополнительных или удаленных данных. Я не вижу необходимости вручную составлять данные здесь. – pintxo

+0

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

ответ

0

Ниже приведен простой пример для анимированной гистограммы. Он будет перебирать две разные версии набора данных, чтобы показать, как очень легко обрабатывать изменения в базовых данных с помощью d3. Нет необходимости (в этом примере) для любой ручной подготовки данных для перехода/анимации.

var data = [ 
 
    [1, 2, 3, 4, 5], 
 
    [1, 6, 5, 3] 
 
]; 
 

 
var c = d3.select('#canvas'); 
 

 
var currentDataIndex = -1; 
 
function updateData() { 
 

 
    // change the current data 
 
    currentDataIndex = ++currentDataIndex % data.length; 
 
    console.info('updating data, index:', currentDataIndex); 
 
    var currentData = data[currentDataIndex]; 
 
    
 
    // get our elements and bind the current data to it 
 
    var rects = c.selectAll('div.rect').data(currentData); 
 

 
    // remove old items 
 
    rects.exit() 
 
     .transition() 
 
     .style('opacity', 0) 
 
     .remove(); 
 

 
    // add new items and define their appearance 
 
    rects.enter() 
 
     .append('div') 
 
     .attr('class', 'rect') 
 
     .style('width', '0px'); 
 

 
    // change new and existing items 
 
    rects 
 
     // will transition from the previous width to the current one 
 
     // for new items, they will transition from 0px to the current value 
 
     .transition() 
 
     .duration('1000') 
 
     .ease('circle') 
 
     .style('width', function (d) { return d * 50 + 'px'; }); 
 
    
 
} 
 

 
// initially set the data 
 
updateData(); 
 

 
// keep changing the data every 2 seconds 
 
window.setInterval(updateData, 2000);
div.rect { 
 
    height: 40px; 
 
    background-color: red; 
 
} 
 

 
div#canvas { 
 
    padding: 20px; 
 
    border: 1px solid #ccc; 
 
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script> 
 
<div id="canvas"> 
 
</div>

+0

Привет, Я понимаю, что ваш ответ передает, и это подчеркивает отсутствие надлежащего понимания с моей стороны в плане того, как работает D3 (насколько я должен был уже знать!). Тем не менее, я не могу применить вашу логику к ** STACKED **. Кажется, что когда я пытаюсь следовать вашему шаблону, никакие данные не загружаются :-(может ли тот факт, что сложная гистограмма привязана к набору данных дважды (я полагаю, что она использует форму вложенных привязок)? –

+0

Часть проблемы, похоже, возникает, когда Я пытаюсь включить выход и ввести функции отдельно. В качестве вашего примера я делаю следующее (псевдокод): 1. var m = d3.selectAll(). Data(); m.enter(); По какой-то причине это похоже, что-то ломает вещи, если я вместо этого просто делаю: var m = d3.selectAll(). data(). enter(); это работает нормально. Я не уверен, какие отличия в коде выше. это связано с отсутствием моего понимания. –

+0

Вы посмотрели: https://medium.com/fattura-con-billy/animated-stacked-bar-charts-with-d3-js-2ef928163e59#.xausgxgvn – pintxo

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