D3 запускать анимацию внутри функции по порядку

Я пытаюсь запустить анимацию по порядку. Вот пример.

function rect1() {
  d3.select("svg")
    .append("rect")
    .attr("id", "r1")
    .attr("x", 300)
    .attr("y", 100)
    .attr("height", 0)
    .attr("width", 0)
    .transition()
    .duration(1000)
    .attr("height", 30)
    .attr("width", 50);
}
function rect2() {
  d3.select("svg")
    .append("rect")
    .attr("id", "r2")
    .attr("x", 300)
    .attr("y", 50)
    .attr("height", 0)
    .attr("width", 0)
    .transition()
    .duration(1000)
    .attr("height", 30)
    .attr("width", 50);
}
function highlightRect(id) {
  d3.select(id)
    .style("fill", "yellow")
} 

Итак, я хочу создать такую ​​функцию, чтобы я мог запускать их в порядке rect1(), rect2(), highlightRect() один за другим (после окончания каждой анимации).

function startAnim (f1, f2, f3, f3a) {
  f1();
  f2();
  f3(f3a);
}
startAnim(rect1, rect2, highlightRect, "#r1");

Я пробовал что-то подобное, но когда появляется больше анимаций, все становится беспорядочно.

// rect1
d3.select("svg")
    .append("rect")
    .attr("id", "r1")
    .attr("x", 300)
    .attr("y", 100)
    .attr("height", 0)
    .attr("width", 0)
    .transition()
    .duration(1000)
    .attr("height", 30)
    .attr("width", 50)
    .on("end", () => {
      // rect2
      d3.select("svg")
        .append("rect")
        .attr("id", "r2")
        .attr("x", 300)
        .attr("y", 50)
        .attr("height", 0)
        .attr("width", 0)
        .transition()
        .duration(1000)
        .attr("height", 30)
        .attr("width", 50)
        .on("end", ....);
    });;

Может быть, невежественный вопрос, можно ли это сделать с помощью обещаний?

Спасибо

создайте список этих функций анимации, пусть они возвращают transition и в основной функции анимации вызывают эти функции анимации по порядку и модифицируют возвращенный transition для вызова основной анимации на end

rioV8 27.12.2018 01:18
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
0
1
61
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

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

function rect1(next) {
  d3.select("svg")
    .append("rect")
    .attr("id", "r1")
    .attr("x", 300)
    .attr("y", 100)
    .attr("height", 0)
    .attr("width", 0)
    .transition()
    .duration(1000)
    .attr("height", 30)
    .attr("width", 50);
  next();
}

function rect2(next) {
  d3.select("svg")
    .append("rect")
    .attr("id", "r2")
    .attr("x", 300)
    .attr("y", 50)
    .attr("height", 0)
    .attr("width", 0)
    .transition()
    .duration(1000)
    .attr("height", 30)
    .attr("width", 50);
  next();
}
function highlightRect(id, next) {
  d3.select(id)
    .style("fill", "yellow")
  next();
}

Потом...

function startAnim(f1, f2, f3, f3a) {
  f1(f2(f3(f3a)));

startAnim(rect1, rect2, highlightRect, '#r1');

Честно говоря, я не уверен, что это сработает в вашей ситуации, но попробовать стоит.

Анимации d3 являются асинхронные. Это просто попытка уволить их всех сразу. Обратный вызов next необходимо передать обработчику .on("end", . . .).

CollinD 27.12.2018 02:24
Ответ принят как подходящий

Обещать это на самом деле было бы довольно просто:

Сначала мы заставим функции возвращать объект, с которым мы связываемся.

function rect1() {
  return d3.select("svg")
    .append("rect")
    .attr("id", "r1")
    .attr("x", 300)
    .attr("y", 100)
    .attr("height", 0)
    .attr("width", 0)
    .transition()
    .duration(1000)
    .attr("height", 30)
    .attr("width", 50);
}

function rect2() {
  return d3.select("svg")
    .append("rect")
    .attr("id", "r2")
    .attr("x", 300)
    .attr("y", 50)
    .attr("height", 0)
    .attr("width", 0)
    .transition()
    .duration(1000)
    .attr("height", 30)
    .attr("width", 50);
}

function highlightRect(id) {
  return d3.select(id)
    .style("fill", "yellow")
}

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

// Returns a promise that resolves after the given
// animation function finishes. Can optionally take args as a second parameter
// obviously this could just take a function and allow consumers
// to use anonymous functions for parameter-binding, but this function
// relies on the return value, so this is, maybe, slightly less easy to
// break on accident.
function runAnimation(fn, ...args) {
    return new Promise(resolve => fn(...args).on("end", resolve));
}

Тогда связать их в цепочку довольно просто:

runAnimation(rect1)
  .then(() => runAnimation(rect2))
  .then(() => runAnimation(highlightRect, "#r1"))

Здесь тоже будет довольно легко создать помощника, который принимает массив функций или что-то еще.

Не тестировал, но я думаю, что общая идея сработает.

Другие вопросы по теме