2016-11-22 66 views
1

我有滑动条显示,我试图动画。基本上,水平方向上有两个相邻的条,每个条占总宽度的百分比。随着数字的变化,宽度和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

好的,完成了!注意第一次加载时左边有一个动画。我宁愿在第一次加载时没有动画。 –

回答

1

好的,我想通了。

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; 
    }); 

基本上,这是我第二次尝试,但删除合并(酒吧)线。我不确定merge()是什么,但对于我正在做的任何事情来说似乎没有必要。我认为任何时候我们都需要使用更新模式,但没有它就可以正常工作。

我认为它仍然工作,如果合并(酒吧)在enter()块的末尾,而不是在中间。