Прерывание переходов прокрутки в D3.js

#d3.js #scroll

#d3.js #прокрутка

Вопрос:

Я использую библиотеку javascript scrollama для написания статьи «scrollytelling», которая включает в себя переход к графикам D3 и из поля зрения при прокрутке пользователем. В основном это работает, но графики накладываются друг на друга, если я прокручиваю слишком быстро.

Вот jsfiddle, основанный на этом примере автором scrollama. В моем примере цветные точки должны исчезать по одной за раз. Если вы должны были быстро прокручивать до конца, прерывистые точки не должны отображаться. Следующие фрагменты показывают, как я настроил переходы:

Я определяю некоторые функции, которые создают мои «графики», а затем вызываю их.

 var makeCircle0 = function(){

  g.append("circle")
    .attr("cx", 50)
    .attr("cy", 100)
    .attr("r", 20)
    .attr("fill", "red")
    .attr("class", "redcircle")

  g.selectAll(".redcircle")
    .attr("opacity", 0)
}

makeCircle0();

// Do this for makeCircle1, 2, and 3, also. 
  

Затем я создаю функции для обработки переходов. В этом говорится, что красный круг исчезает, а остальные круги имеют непрозрачность 0. Я делаю это для всех кругов / этапов.

 var showCircle0 = function(){

  g.selectAll(".redcircle")
  .transition()
  .duration(1000)
  .attr("opacity", 1)

  g.selectAll(".yellowcircle").attr("opacity", 0)
  g.selectAll(".greencircle").attr("opacity", 0)
  g.selectAll(".bluecircle").attr("opacity", 0)

}
  

В этом разделе создается массив моих функций перехода, чтобы я мог вызывать их на определенных этапах страницы при прокрутке. Это похоже на то, как Джим Валландингем работал со своим скроллером.

 var activateFunctions = [];
activateFunctions[0] = showCircle0;
activateFunctions[1] = showCircle1;
activateFunctions[2] = showCircle2;
activateFunctions[3] = showCircle3;
  

Наконец, это вызывает нужную функцию на нужном шаге страницы. Что он и делает… но не без остановки других переходов, которые были запущены на предыдущем шаге, что приводит к появлению нескольких точек на разных этапах.

 function handleStepEnter(response) {
  step.classed('is-active', function (d, i) {
    return i === response.index;
  })

  figure.call(activateFunctions[response.index])
}
  

Как я могу это предотвратить?

Комментарии:

1. Я думаю, это то, что вы ищете (переход не совсем совпадает с сегментами слева, но круги соответствуют числам). Это правильно?

2. @AndrewReid это здорово! Итак, все, что вы сделали, это сначала «interrupt ()», прежде чем начинать какие-либо новые переходы?

3. В значительной степени — interrupt() отменит любые переходы при выборе.

4. Хорошо, интересно. Если у меня есть несколько классов, которые могут переходить (например, redcircle, yellowcircle и т. Д.) Мне пришлось бы прерывать их все?

5. Если есть риск, что они все еще переходят — вот почему я использовал class для выбора их всех и id для выбора одного по отдельности.

Ответ №1:

Если вам нужно прервать переход, в d3-transition есть метод для этого:

 selection.interrupt();
  

Это отменит переход в выделенном элементе. При использовании именованных переходов вы можете указать имя, предоставив прерыванию один аргумент, указывающий имя перехода для отмены.


Если это общая версия вашей функции для отображения элемента:

 function show() {
  selectionToHide.attr("opacity",0);

  selectionToShow.transition()
     .attr("opacity",1);
}
  

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

Однако есть другое решение — мы можем применить другой переход к элементам, которые мы хотим не показывать. Для этого мы просто заменяем переход на новый:

 function show() {
  selectionToHide.transition()
     .attr("opacity",0);

  selectionToShow.transition()
     .attr("opacity",1);
}
  

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

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

Комментарии:

1. Это здорово! Будет ли это работать, если есть задержка () как часть перехода?

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

3. Я могу продемонстрировать, что задержка ни на что не повлияет — вот скрипка, показывающая как прерывание, так и замену перехода на новый. Начальный переход изменяет радиус после задержки, но он никогда не запускается, поскольку он отменяется / заменяется.

4. @GerardoFurtado, спасибо! Подходит только для 1000-го — если я не ошибаюсь, я полагаю, что я дал вам ваш чуть более 2 лет назад, когда я был еще довольно свежим. С нетерпением жду возможности закрыть как обман — обычно с менее чем 5 постоянными пользователями в d3, как правило, ждали, когда вы выйдете в Интернет и увидите это.

5. @GerardoFurtado, я имел в виду просто обычный золотой значок для людей d3 или что-то еще, было трудно достичь порога в пять голосов за обман (или по любой другой близкой причине, если на то пошло) без поддержки gold из-за того, как мало постоянных пользователей. Но теперь, когда Alto со дня на день получит золото, надеюсь, ведение домашнего хозяйства станет немного проще.