Проблема в том, что 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 . Он будет отложен до завершения перехода. Я не имею ни малейшего понятия, когда это так.