Как убедиться, что серия billboard.js завершила все переходы в onrendered?

Я пытаюсь добавить некоторые элементы в диаграмму, и я делаю это в onrendered функция передана billboard.js конфигурации.

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

Как убедиться, что происходит в onrendered это после того, как все серии показаны / скрыты от графика? Так что после всех переходов закончились.

<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <script src="https://d3js.org/d3.v4.min.js"></script>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/billboard.js/dist/billboard.min.css" />
  <script src="https://cdn.jsdelivr.net/npm/billboard.js/dist/billboard.pkgd.min.js"></script>
  <title>JS Bin</title>
</head>

<body>
 <div id="chart"></div>
  <script>
  console.log('should be d1=1,d2=1')
  var c = bb.generate({
    bindto: "#chart",
    size: {
      width: 500,
      height: 250
    },
    transition: 0,
    data: {
      x: "x",
      columns: [
        ["x", "2013-01-01", "2013-01-02", "2013-01-03", "2013-01-04", "2013-01-05", "2013-01-06"],
        ["data1", 30, 200, 100, 400, 150, 250],
        ["data2", 130, 340, 200, 500, 250, 350],
      ]
    },
    axis: {
      x: {
        type: "timeseries",
        tick: {
          format: "%Y-%m-%d"
        }
      }
    },
    onrendered: function() {
      var data1op = d3.select(".bb-chart-line.bb-target.bb-target-data1").style("opacity");
      var data2op = d3.select(".bb-chart-line.bb-target.bb-target-data2").style("opacity");
      console.log(`data1 op: ${data1op} --- data2 op: ${data2op}`);
    }
  });
  
  setTimeout(function(){console.log('should be d1=0,d2=1');c.hide('data1')},500);
  setTimeout(function(){console.log('should be d1=0,d2=0');c.hide('data2')},1000);
  setTimeout(function(){console.log('should be d1=1,d2=0');c.show('data1')},1500);
  setTimeout(function(){console.log('should be d1=1,d2=1');c.show('data2')},2000);

  setTimeout(function(){console.log('more waiting between hide/show')},3500);

  setTimeout(function(){console.log('should be d1=0,d2=1');c.hide('data1')},5000);
  setTimeout(function(){console.log('should be d1=0,d2=0');c.hide('data2')},6000);
  setTimeout(function(){console.log('should be d1=1,d2=0');c.show('data1')},7000);
  setTimeout(function(){console.log('should be d1=1,d2=1');c.show('data2')},8000);
  </script>
</body>

</html>

1 ответ

Проблема в том, что onrendered называется, когда все svg манипуляции сделаны. Но переходы еще должны начаться. Вы должны ждать, пока переходы не будут закончены.

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

function atEndOf(dataN, action) {
  setTimeout(function() {
    var transition = d3.active(d3.select(".bb-chart-line.bb-target.bb-target-"+dataN).node());
    if (!transition) { return; } // no transition running
    transition.transition().on("start", action);
  }, 10);
}

Чтобы узнать, когда переходы скрытия и показа сделаны, вы можете создать atEndOf цепь

// wait till main animation is finished
setTimeout(function() {
  c.hide('data1');
  atEndOf('data1', function () {
    console.log('should be d1=0,d2=1');
    showOpacity();
    c.hide('data2');
    atEndOf('data2', function () {
      console.log('should be d1=0,d2=0');
      showOpacity();
    });
  });
}, 6000);

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

Это использует следующую функцию

function showOpacity() {
  var data1op = d3.select(".bb-chart-line.bb-target.bb-target-data1").style("opacity");
  var data2op = d3.select(".bb-chart-line.bb-target.bb-target-data2").style("opacity");
  console.log(`data1 op: ${data1op} --- data2 op: ${data2op}`);
}

Поскольку show а также hide переходы используют длительность по умолчанию 1 с, трудно увидеть, что мы ждем до конца перехода. Чтобы изменить продолжительность этих переходов, нам нужно украсить ChartInternal.endAll() метод. Здесь я установил длительность 5000 мс для всех переходов.

var bb_endall = bb.chart.internal.fn.endall;
bb.chart.internal.fn.endall = function (transition, callback) {
  transition.duration(5000);
  bb_endall(transition, callback);
};

Я пытался использовать другое украшение, которое использует atEndOf техника для вызова пользовательской функции, но я не мог заставить ее работать.

Полный пример со всеми переходами, установленными на длительность 5000 мс

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <script src="https://d3js.org/d3.v4.min.js"></script>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/billboard.js/dist/billboard.min.css" />
  <script src="https://cdn.jsdelivr.net/npm/billboard.js/dist/billboard.pkgd.min.js"></script>
  <title>JS Bin</title>
</head>

<body>
 <div id="chart"></div>
<script>
  var bb_endall = bb.chart.internal.fn.endall;
  bb.chart.internal.fn.endall = function (transition, callback) {
    transition.duration(5000);
    bb_endall(transition, callback);
  };

  //console.log('should be d1=1,d2=1');
  var c = bb.generate({
    bindto: "#chart",
    size: {
      width: 500,
      height: 250
    },
    // transition: 0,
    transition: {duration: 5000},
    data: {
      x: "x",
      columns: [
        ["x", "2013-01-01", "2013-01-02", "2013-01-03", "2013-01-04", "2013-01-05", "2013-01-06"],
        ["data1", 30, 200, 100, 400, 150, 250],
        ["data2", 130, 340, 200, 500, 250, 350],
      ]
    },
    axis: {
      x: {
        type: "timeseries",
        tick: {
          format: "%Y-%m-%d"
        }
      }
    },
    onrendered: function() {
      // not usefull for end of transition
    }
  });
  function showOpacity() {
    var data1op = d3.select(".bb-chart-line.bb-target.bb-target-data1").style("opacity");
    var data2op = d3.select(".bb-chart-line.bb-target.bb-target-data2").style("opacity");
    console.log(`data1 op: ${data1op} --- data2 op: ${data2op}`);
  }
  function atEndOf(dataN, action) {
    setTimeout(function() {
      var transition = d3.active(d3.select(".bb-chart-line.bb-target.bb-target-"+dataN).node());
      if (!transition) { return; } // no transition running
      transition.transition().on("start", action);
    }, 10);
  }

  // wait till main animation is finished
  setTimeout(function() {
    c.hide('data1');
    atEndOf('data1', function () {
      console.log('should be d1=0,d2=1');
      showOpacity();
      c.hide('data2');
      atEndOf('data2', function () {
        console.log('should be d1=0,d2=0');
        showOpacity();
      });
    });
  }, 6000);


//   setTimeout(function(){console.log('should be d1=0,d2=1');c.hide('data1')},500);
//   setTimeout(function(){console.log('should be d1=0,d2=0');c.hide('data2')},1000);
//   setTimeout(function(){console.log('should be d1=1,d2=0');c.show('data1')},1500);
//   setTimeout(function(){console.log('should be d1=1,d2=1');c.show('data2')},2000);

//   setTimeout(function(){console.log('more waiting between hide/show')},3500);

//   setTimeout(function(){console.log('should be d1=0,d2=1');c.hide('data1')},5000);
//   setTimeout(function(){console.log('should be d1=0,d2=0');c.hide('data2')},6000);
//   setTimeout(function(){console.log('should be d1=1,d2=0');c.show('data1')},7000);
//   setTimeout(function(){console.log('should be d1=1,d2=1');c.show('data2')},8000);
  </script>
</body>

</html>

Есть некоторый код в billboard.js что вызывает onrendered когда есть TabVisible. Он будет отложен до завершения перехода. Я пока понятия не имею, когда это так.

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