2016-09-04 4 views
2

Я следил за example here относительно переходов с элементами холста. Поскольку я использую d3 версию 4.2.2, я попытался прикрепить пример без успеха. Проблема заключается в том, что (в зависимости от продолжительности d3.timer) анимация останавливается в точке, где точки не находятся в правильном положении. Он отлично работает с d3 v3. Вот часть кода:D3 V4 - Canvas Переходы: d3.timer duration

var duration = 1000; 
var delay = function(d) { 
    return d.i; 
} 
var maxDelay = 0; 
var timeScale = d3.scaleLinear() 
    .domain([0, duration]) 
    .range([0, 1]); 

data.forEach(function(d) { 
    d.trans = { 
    i: d3.interpolateNumber(height, d.y), 
    delay: delay(d) 
    }; 
    if (d.trans.delay > maxDelay) { 
    maxDelay = d.trans.delay; 
    } 
}); 

var renderTime = 0; 
var timer = d3.timer(moveCircles); 

function moveCircles(t) { 
    data.forEach(function(d) { 
    var time = timeScale(t - d.trans.delay); 
    d.y = d.trans.i(time); 
    }); 
    var start = new Date(); 
    drawCircles('black'); 
    var end = new Date(); 
    renderTime += (end - start); 
    if (t >= duration + maxDelay) { 
    console.log('Render time:', renderTime); 
    timer.stop(); 
    return true; 
    } 
} 

See this plunker для полного примера. Красные точки указывают правильное положение (x/y) данных. Таким образом, каждая черная точка должна пересекаться с одной красной точкой. Чем выше значение у точки, тем выше расстояние до его правильного положения. Это привело меня к предположению, что в интерполяции значения y имеется ошибка?

Есть ли способ установить длительность (например, 1000) и анимировать точки s.t. каждая точка находится в правильном положении после указанной продолжительности?

EDIT: Оказалось, что с использованием того же easeCubicInOut, что и в приведенном примере, он отлично работает. Я не знаю, почему это работает.

var ease = d3.easeCubicInOut; 
... 
function moveCircles(t) { 
    data.forEach(function(d) { 
    //var time = timeScale(t - d.trans.delay); // without the ease it won't work 
    var time = ease(timeScale(t - d.trans.delay)); 
    d.y = d.trans.i(time); 
    }); 
... 

Как я могу пропустить непринужденность?

ответ

1

Не прямой ответ, как я не после всех вычислений, но есть что-то с математикой здесь:

var time = timeScale(t - d.trans.delay); 
d.y = d.trans.i(time); 

t - d.trans.delay потребности для получения значения от 0 до 1000, так что она будет масштабироваться между 0 до 1. Очевидно, что вы кормите свои interpolate функции значения больше, то 1. Я считаю, что это:

if (t >= duration + maxDelay) { 

является виновником, как вы собираетесь запустить анимацию мимо 1000 миллисекунд.

Наивный подход был бы просто довершение:

var time = timeScale(t - d.trans.delay); 
if (time > 1) time = 1; 
d.y = d.trans.i(time); 

Тем не менее, я не уверен, что этот код должен быть настолько сложным. Основной transition должен быть в состоянии делать то, что вы после:

d3.select({}) 
    .transition() 
    .duration(duration) 
    .tween("animate.circles", function() { 
    return function(t) { 
     data.forEach(function(d,i){ 
     d.y = d.trans.i(t); 
     }); 
     drawCircles('black'); 
    }; 
}); 

Обновлено plunker.

+0

Большое спасибо за ваши усилия. Я полностью согласен с вами, и ваш плункер отлично работает! Проблема в том, что переход afaik не является масштабируемым по отношению к числу точек данных (или существует обходное решение?), Что было в основном одним из моих намерений использовать также холст вместо svg. Если вы, например, измените 'size = 10000', переход уже не является гладким. –

Смежные вопросы