실시간 차트에 들어가는 항목을 (전환과 함께) 애니메이션화하려고합니다.
보시다시피 '원 추가'버튼을 클릭하면 원이 차트 하단에 유지되고 위쪽으로 움직이지 않습니다.
흥미롭게도 .ease(d3.easeLinear)
전환에 추가 하면 문제가 해결됩니다.
왜?
d3에서 타이머와 함께 전환을 사용하는 것이 개념적으로 잘못 되었습니까?
const width = 300;
const height = 100;
const margin = { top: 0, right: 30, bottom: 30, left: 50 };
const main = d3.select('.chart')
.append('svg')
.attr('width', width + margin.left + margin.right)
.attr('height', height + margin.top + margin.bottom)
.append('g')
.attr('transform', `translate(${margin.left}, ${margin.top})`);
const now = Date.now();
const xScale = d3.scaleTime().domain([now - 10000, now]).range([0, width]);
const xAxis = d3.axisBottom(xScale).ticks(5);
const xAxisG = main.append('g')
.attr('transform', `translate(0, ${height})`)
.call(xAxis);
let data = [];
function drawCircles() {
const t = d3.transition().duration(1000); //.ease(d3.easeLinear);
const update = main.selectAll('circle').data(data);
update.enter()
.append('circle')
.attr('r', d => d.value)
.merge(update)
.attr('cx', d => xScale(d.timestamp))
.attr('cy', height)
.transition(t)
.attr('cy', height / 2);
}
d3.timer(() => {
const now = Date.now();
xScale.domain([now - 10000, now]);
xAxisG.call(xAxis);
drawCircles();
});
d3.select('.add-circle').on('click', () => {
data.push({
timestamp: Date.now() - 3000,
value: 10
});
});
svg {
margin: 30px;
}
.add-circle {
margin-left: 200px;
}
<script src="https://unpkg.com/[email protected]/build/d3.js"></script>
<button class="add-circle">Add circle</button>
<div class="chart"></div>
여기서 문제는 완화 의 부족이 아닙니다 . 문제는 대부분의 아마의 혼합이다 d3.timer
와 selection.transition
.
단계별로 살펴 보겠습니다. 당신은 이렇게 말했습니다 :
const t = d3.transition().duration(1000);
작동하지 않는 동안 :
const t = d3.transition().duration(1000).ease(d3.easeLinear);
공장. 글쎄, 그것은 사실이 아닙니다. 작동하지 않습니다. 사용하는 사람은 easeLinear
이것이 선형 전환이 아니라는 것을 쉽게 알 수 있습니다! 여기서 재미있는 일이 일어나고 있습니다 ...
이제 여유를 변경해 보겠습니다. 기본 이징 (즉, 설정하지 않은 경우)은 easeCubic
입니다. 따라서 이렇게하면 :
const t = d3.transition().duration(1000).ease(d3.easeCubic);
.NET Framework없이 첫 번째 코드와 동일한 효과를 갖습니다 ease
. 따라서 ease
전환을 일으킨 것은 우리가 설정 한 사실이 아닙니다 .
나는 당신의 코드로 모든 이징을 테스트했고 그들 중 일부는 easeLinear
또는 같은 "작동"했습니다 easeCircle
. 는 일을 여기 전환이 때문에 따옴표 사이에 되지 정상적인 하나, 예상 하나. 그들 중 일부 easeCubic
는 전혀 효과가 없었습니다.
d3.timer
전환과 혼합 할 수 없기 때문 입니다. 나는 소스 코드를 볼 기회가 없었지만 대부분은 아마도 같은 방법을 사용하고 requestAnimationFrame()
충돌합니다.
해결 방법 : d3.timer
.
제안 된 솔루션을 구현하는 데는 여러 가지 방법이 있지만 (다른 코더는 다른 대안을 만들 것입니다) 이것은 내 것입니다. 먼저 전환 기능을 정의합니다.
function transitioning(elem) {
const t = d3.transition().duration(1000).ease(d3.easeCubic);
d3.select(elem)
.transition(t)
.attr('cy', height / 2);
}
그런 다음 함수 내부 에서 각 원을 drawCircles
호출 transitioning
합니다. 그러나 플래그를 설정해야하므로 transitioning
동일한 요소에 대해 함수를 반복해서 호출하지 않습니다 .
function drawCircles() {
const update = main.selectAll('circle').data(data);
update.enter()
.append('circle')
.attr('r', d => d.value)
.attr('cy', height)
.attr("flag", 0)
.merge(update)
.attr('cx', d => xScale(d.timestamp))
.each(function() {
if (!(+d3.select(this).attr("flag"))) {
transitioning(this)
}
d3.select(this).attr("flag", 1);
});
}
그리고 이것은 업데이트 된 CodePen입니다 : http://codepen.io/anon/pen/ZLyXma?editors=0010
위의 CodePen에서는 easeCubic
. 그러나이 다른 Pen에서는 여유를 설정하지 않고 작동 함을 알 수 있습니다. http://codepen.io/anon/pen/apwLxR?editors=0010
이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.
침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제
몇 마디 만하겠습니다