2016-11-22 6 views
1

У меня есть раздвижная панель, которую я пытаюсь оживить. В принципе, есть две полосы рядом друг с другом по горизонтали, каждая из которых занимает процент от общей ширины. По мере того, как цифры меняются, ширина и х позиционируются, чтобы отразить новый процент.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; 
    }); 

В принципе, это была моя вторая попытка, но удаление линии слияния (бар). Я не уверен, что делает merge(), но это не кажется необходимым для всего, что я делаю. Я думал, что это требуется в любое время, когда мы использовали шаблон обновления, но он отлично работает без него.

Я думаю, что он по-прежнему работает, если merge (bar) находится в конце блока enter(), а не в середине.

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