如何确保billboard.js系列已经结束了所有已转换的转换?

时间:2018-08-24 13:25:16

标签: javascript d3.js charts billboard.js

我正在尝试在图表上添加一些元素,并在传递给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 个答案:

答案 0 :(得分:0)

问题在于,完成所有onrendered操作之后,将调用svg。但是过渡仍然必须开始。您必须等到转换完成。

天真的方法是在调用transitionc.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}`);
}

由于showhide过渡使用默认的1s持续时间,因此很难看出我们要等到过渡结束。要更改这些过渡的持续时间,我们需要装饰ChartInternal.endAll()方法。在这里,我为所有转换设置了5000ms的持续时间。

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

我尝试使用另一种装饰,该装饰使用atEndOf技术来调用用户定义的函数,但无法使其正常工作。

一个完整的示例,其中所有过渡的持续时间都设置为5000ms

<!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>

在{strong> TabVisible 中,billboard.js中有一些代码调用onrendered。过渡完成后将推迟到此时间。到目前为止,我还不知道。