как повторно использовать две (или более) последовательности цепных переходов в D3 - PullRequest
0 голосов
/ 23 сентября 2018

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

В качестве игрушечного примера рассмотрим случай, когда порядки последовательности должны быть a, b, c, d, e, f, g, h и e, f, g, h, a, b, c, d.Я попытался с кодом ниже, но это не работает.Обратите внимание, что переходы могут иметь разные свойства (delay, duration, ease и т. Д.) И могут применяться к различным атрибутам (x, y, width, height или cx, cy, r и т. Д.) И стили.Например, переход a может относиться к width, переход b к height, переход c к x, переход d к y, переход e к transform атрибуту, переход f в color стиль и так далее.

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

Есть ли способ кодировать это в компактном виде?

var t1 = d3
.transition() // transition "a" specifications 
...
.transition() // transition "b" specifications 
...
.transition() // transition "c" specifications 
...
.transition() // transition "d" specifications 
...
;
var t2 = d3
.transition() // transition "e" specifications 
...
.transition() // transition "f" specifications 
...
.transition() // transition "g" specifications 
...
.transition() // transition "h" specifications 
...
;
someelement1
.transition(t1).transition(t2); 
someelement2
.transition(t2).transition(t1); 

1 Ответ

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

Как отмечается в комментариях, принципы ответа на этот вопрос такие же, как ваш предыдущий вопрос.В этом случае у вас есть набор различных переходов, которые могут применяться в любом порядке, указанном разными ключами.Давайте сохраним их в объекте:

var transitions = {
  a: function(sel){ return sel.transition().duration(1000).delay(1000).attr('cy', 200) },
  b: function(sel){ return sel.transition().duration(2000).delay(0).attr('r', 40) },
  c: function(sel){ return sel.transition().duration(500).delay(1500).attr('fill', 'red') },
  d: function(sel){ return sel.transition().duration(1500).delay(500).attr('opacity', 0.5) },
  e: function(sel){ return sel.transition().duration(1000).delay(3000).attr('cy', 300) },
  f: function(sel){ return sel.transition().duration(2000).delay(0).attr('r', 60) },
  g: function(sel){ return sel.transition().duration(500).delay(1500).attr('fill', 'magenta') },
  h: function(sel){ return sel.transition().duration(1500).delay(500).attr('opacity', 0.25) }
};

Каждая функция принимает объект d3.selection и применяет к нему конкретные параметры перехода и наборы преобразований.Эти функции могут быть как угодно длинными и сложными.Мне лень с небольшим воображением, поэтому они делают только одно преобразование в этой версии.

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

var transitions = {
  a: function(){ return this.duration(1000).delay(1000).attr('cy', 200) },
  b: function(){ return this.duration(2000).delay(0).attr('r', 40) },
  c: function(){ return this.duration(500).delay(1500).attr('fill', 'red') },
  d: function(){ return this.duration(1500).delay(500).attr('opacity', 0.5) },
  e: function(){ return this.duration(1000).delay(3000).attr('cy', 300) },
  f: function(){ return this.duration(2000).delay(0).attr('r', 60) },
  g: function(){ return this.duration(500).delay(1500).attr('fill', 'magenta') },
  h: function(){ return this.duration(1500).delay(500).attr('opacity', 0.25) }
};

Теперь мы можем выполнить эти переходы, вызвав код, подобный

transitions['a'].call( selection.transition() )
transitions.f.call( d3.select('circle').transition() )

. Вы хотите указать массив переходов для применения к выделению, что-то вроде этого:

apply_transitions( group.select(":nth-child(1)"), ['a','b','c','d'] );
apply_transitions( group.select(":nth-child(2)"), ['e','f','g','h'] );

Это может быть реализовано следующим образом:

/**
* apply a series of transitions to a selection
*
* @param selection - d3 selection
* @param tr_arr - array of transition identifiers, referring to functions in the `transitions` object
*/
function apply_transitions( selection, tr_arr ) {

  // turn the current selection into a d3.transition
  // call the transition function referred to by the first ID in the array
  // with the d3.transition as the `this` context
  // note that the function returns a transition object, so it can be chained
  transitions[ tr_arr[0] ].call( selection.transition() )
  // add a handler to be applied at the end of the transition
    .on('end', function(){
      // if there are more transitions to be applied, call
      // apply_transitions again with tr_arr minus the first element
      // note that the `this` context in the `on` function is a DOM element,
      // so use `d3.select(this)` to turn it into a d3 selection
      if ( tr_arr.length > 1 ) {
        apply_transitions( d3.select(this), tr_arr.slice(1) );
      }
    })
}

Пример живого действия:

    var svg = d3.select('svg').attr('width', 500).attr('height', 500);

    var dataSet = [20, 20];

    var group=svg.append("g");
    var circles = group.selectAll('circle')
    .data(dataSet)
    .enter()
    .append('circle')
    .attr("r",function(d){ return d })
    .attr("cx",function(d, i){ return i * 100 + 50 })
    .attr("cy",50)
    .attr("fill",'black');

    apply_transitions( group.select(":nth-child(1)"), ['a','b','c','d'] );

    apply_transitions( group.select(":nth-child(2)"), ['e','f','g','h'] );

  function apply_transitions( selection, tr_arr ) {

    var transitions = {
      a: function(){ return this.duration(1000).delay(1000).attr('cy', 200) },
      b: function(){ return this.duration(2000).delay(0).attr('r', 40) },
      c: function(){ return this.duration(500).delay(1500).attr('fill', 'red') },
      d: function(){ return this.duration(1500).delay(500).attr('opacity', 0.5) },
      e: function(){ return this.duration(1000).delay(3000).attr('cy', 300) },
      f: function(){ return this.duration(2000).delay(0).attr('r', 60) },
      g: function(){ return this.duration(500).delay(1500).attr('fill', 'magenta') },
      h: function(){ return this.duration(1500).delay(500).attr('opacity', 0.25) }
    };

      transitions[ tr_arr[0] ].call( selection.transition() )
        .on('end', function(){
          if ( tr_arr.length > 1 ) {
            apply_transitions( d3.select(this), tr_arr.slice(1) );
          }
        })
  }
<script src="http://d3js.org/d3.v5.js"></script>
<svg></svg>
...