2016-11-22 6 views
1

私はアニメーション化しようとしているスライドバーの表示を持っています。基本的に、横に横に2つのバーがあり、それぞれが全幅のパーセンテージを占めています。数値が変わると、幅とxの位置がアニメーション化され、新しいパーセンテージが反映されます。d3js最初にアニメートしないでください

項目が最初に読み込まれるときにアニメーションを必要としないことを除いて、数字が変更された場合のみ、うまくいきます。今は、アイテムの左側から所定の場所に撃たれます。

EDIT2:ここでは、スニペットの最初のバージョンがあります:

const d3SlidingBar = {}; 
 
// data should simply be an array with two numbers 
 
// future: add support for arbitrary number of numbers 
 
d3SlidingBar.create = function create(el, data, formatText) { 
 
    const svg = d3.select(el).append('svg') 
 
    .attr('class', 'sliding-bar__svg') 
 
    .attr('width', '100%') 
 
    .attr('height', '100%'); 
 

 
    svg.append('g') 
 
    .attr('class', 'sliding-bar__svg__bars') 
 
    // try 100% here. Should work. 
 
    .attr('width', el.offsetWidth) 
 
    .attr('height', el.offsetHeight); 
 

 
    if (data) this.update(el, data, formatText); 
 
}; 
 

 
d3SlidingBar.update = function update(el, data, formatText) { 
 
    // Re-compute the scales, and render the data points 
 
    const scales = this.scale(el, data); 
 
    this.drawBars(el, scales, data); 
 
    this.drawNumbers(el, scales, data, formatText); 
 
}; 
 

 
d3SlidingBar.scale = (el, data) => 
 
    d3.scaleLinear() 
 
    .range([0, el.offsetWidth]) 
 
    .domain([0, data.reduce((a, b) => a + b)]); 
 

 

 
d3SlidingBar.drawBars = (el, scale, data) => { 
 
    const t = d3.transition() 
 
    .duration(450); 
 

 
    const barHeight = el.offsetHeight; 
 

 
    // keep track of right side of stacks of bar so bars can stack further. 
 
    // Useful if we have more than two bars. 
 
    let greatestWidth = 0; 
 

 
    const g = d3.select(el).selectAll('.sliding-bar__svg__bars'); 
 

 
    const bar = g.selectAll('.sliding-bar__svg__bar') 
 
    .data(data); 
 

 
    bar.enter().append('rect') 
 
    .attr('class', (point, ind) => `sliding-bar__svg__bar sliding-bar__svg__bar--${ind}`) 
 
    .attr('height', barHeight) 
 
    .merge(bar) 
 
    .transition(t) 
 
    .attr('width', point => scale(point)) 
 
    .attr('x', (point) => { 
 
     const oldGreatestWidth = greatestWidth; 
 
     greatestWidth += scale(point); 
 
     return oldGreatestWidth; 
 
    }); 
 

 
    bar.exit().remove(); 
 
}; 
 

 
// This function needs an overhaul, but I'm not sure how 
 
d3SlidingBar.drawNumbers = (el, scale, data, formatText = point => point) => { 
 
    const barHeight = el.offsetHeight; 
 

 
    // keep track of right side of stacks of bar so bars can stack further. 
 
    // Bar position is used to position text 
 

 
    const g = d3.select(el).selectAll('.sliding-bar__svg__bars'); 
 

 
    const number = g.selectAll('.sliding-bar__svg__number') 
 
    .data(data); 
 

 
    number.enter().append('text') 
 
    .style('font-size', barHeight - 10) 
 
    .attr('y', barHeight - 10) 
 
    .attr('class', (point, ind) => `sliding-bar__svg__number sliding-bar__svg__number--${ind}`) 
 
    .merge(number) 
 
    .attr('y', barHeight - 10) 
 
    .style('font-size', barHeight - 10) 
 
    .text(point => formatText(point)) 
 
    .attr('x', function xPosition(point, ind) { 
 
     return (ind % 2) ? 
 
     el.offsetWidth - this.getComputedTextLength() - 8 
 
     : (0 + 8); 
 
    }); 
 

 
    // This is for if we want the number to stay at the left of each bar, 
 
    // const greatestWidth = 0; 
 
    // 
 
    // ...number.enter... 
 
    // 
 
    // useful for more than 2 bars. 
 
    // .attr('x', (point, ind) => { 
 
    // const oldGreatestWidth = greatestWidth; 
 
    // greatestWidth += scale(point); 
 
    // return oldGreatestWidth + 5; 
 
    // }) 
 
    // 
 

 
    number.exit().remove(); 
 
}; 
 

 

 
let count = 0; 
 
const data = [[50, 50], [75,25]]; 
 
const formatText = text => `%${text}`; 
 

 
const bars = document.getElementById('bars') 
 

 
d3SlidingBar.create(bars, data[0], formatText) 
 

 
setInterval(() => { 
 
    count++; 
 
    d3SlidingBar.update(bars, data[count % 2], formatText) 
 
}, 1000)
.sliding-bar__container { 
 
    width: 400px; 
 
    height: 50px; 
 
    border: 2px solid black; 
 
    background-color: black; 
 
    position: absolute; 
 
    display: inline-block; 
 
} 
 

 
.sliding-bar__svg__bars { 
 
    height: 100%; 
 
    width: 100%; 
 
} 
 

 
.sliding-bar__svg__bar--0 { 
 
    fill: #33708E; 
 
} 
 

 
.sliding-bar__svg__bar--1 { 
 
    fill: #CF8D3A; 
 
} 
 

 
.sliding-bar__svg__number { 
 
    fill: white; 
 
    font-weight: bold; 
 
}
<script src="https://d3js.org/d3.v4.min.js"></script> 
 

 
<body> 
 
    <div class="sliding-bar__container" id='bars'> 
 
    </div> 
 
</body>

編集:私はこれまで、それを変更しようとしたが、今それが更新されるたびに、バーが右からのシュート側...

d3SlidingBar.drawBars = (el, scale, data) => { 
    const t = d3.transition() 
    .duration(450); 

    const barHeight = el.offsetHeight; 

    // keep track of right side of stacks of bar so bars can stack further. 
    // Useful if we have more than two bars. 
    let greatestWidth = 0; 
    let greatestWidthEnter = 0; 

    const g = d3.select(el).selectAll('.sliding-bar__svg__bars'); 

    const bar = g.selectAll('.sliding-bar__svg__bar') 
    .data(data); 

    bar.transition(t) 
    .attr('width', point => scale(point)) 
    .attr('x', (point) => { 
     const oldGreatestWidth = greatestWidth; 
     greatestWidth += scale(point); 
     return oldGreatestWidth; 
    }); 


    bar.enter().append('rect') 
    .attr('class', (point, ind) => `sliding-bar__svg__bar sliding-bar__svg__bar--${ind}`) 
    .attr('height', barHeight) 
    .merge(bar) 
    .attr('width', point => scale(point)) 
    .attr('x', (point) => { 
     const oldGreatestWidth = greatestWidthEnter; 
     greatestWidthEnter += scale(point); 
     return oldGreatestWidth; 
    }); 

    bar.exit().remove(); 
}; 
+0

コードをStackExchangeスニペットに変更して実行することができますか?何が起こっているのかを視覚化するのは難しいです。 – Ian

+0

OK、完了!最初の読み込み時に左からアニメーションがどのようにあるかに注目してください。私はむしろ、最初の読み込み時にアニメーションが存在しないと思います。 –

答えて

1

OK、わかりました。

bar 
    .transition(t) 
    .attr('width', point => scale(point)) 
    .attr('x', (point) => { 
     const oldGreatestWidth = greatestWidth; 
     greatestWidth += scale(point); 
     return oldGreatestWidth; 
    }); 




bar.enter().append('rect') 
    .attr('class', (point, ind) => `sliding-bar__svg__bar sliding-bar__svg__bar--${ind}`) 
    .attr('height', barHeight) 
    .attr('width', point => scale(point)) 
    .attr('x', (point) => { 
     const oldGreatestWidth = greatestWidth; 
     greatestWidth += scale(point); 
     return oldGreatestWidth; 
    }); 

基本的には、私の2番目の試みでしたが、マージ(バー)行を削除しました。私はmerge()が何をしているのかは分かりませんが、私がやっていることには必要ではないようです。私はそれが更新パターンを使用するたびに必要と思ったが、それがなければ正常に動作している。

マージ(bar)がenter()ブロックの最後で、真ん中ではない場合はまだ動作すると思います。

関連する問題