Javascript 转换条形图中的数字标签

Javascript 转换条形图中的数字标签,javascript,d3.js,Javascript,D3.js,我正在学习d3.js,我有一个问题: d3中的以下代码基本上绘制了一个条形图,带有一个更新按钮,该按钮按降序和升序分别对数据进行排序。此外,条形图上还会显示数字标签 我想将数字标签从当前值转换为更新值。例如,如果第一个条的数字标签为20,排序后的新更新值为100,我希望此标签在特定转换时间内从20转换为100(20,21,…,100),反之亦然,如果原始标签为100,更新值为20,则转换为100,99,…,20 我知道我可以用条形图转换数值,但作为练习,我想知道如何从当前数值转换到新的更新值 c

我正在学习d3.js,我有一个问题:

d3中的以下代码基本上绘制了一个条形图,带有一个更新按钮,该按钮按降序和升序分别对数据进行排序。此外,条形图上还会显示数字标签

我想将数字标签从当前值转换为更新值。例如,如果第一个条的数字标签为20,排序后的新更新值为100,我希望此标签在特定转换时间内从20转换为100(20,21,…,100),反之亦然,如果原始标签为100,更新值为20,则转换为100,99,…,20

我知道我可以用条形图转换数值,但作为练习,我想知道如何从当前数值转换到新的更新值

const data = [
  {key: 0, value: 50},
  {key: 1, value: 20},
  {key: 2, value: 100},
  {key: 3, value: 30},
  {key: 4, value: 40},
  {key: 5, value: 70}
]
// const dataset = [50, 20, 100, 30, 40]

const svgWidth = 800;
const svgHeight = 400;

const xScale = d3.scaleBand()
  .domain(d3.range(data.length))
  .rangeRound([0, svgWidth])
  .paddingInner(0.1);

const yScale = d3.scaleLinear()
  .domain([0, d3.max(data, d => d.value)])
  .range([0, svgHeight]);


const svg = d3.select('#chart')
  .append('svg')
  .attr('width', svgWidth)
  .attr('height', svgHeight);

let bars = svg.selectAll('rect').data(data, d => d.key);
let labels = svg.selectAll('text').data(data);

bars.enter()
  .append('rect')
  .each(function(d){return this._old = d;})
  .attr('width', xScale.bandwidth)
  .attr('height', d => yScale(d.value))
  .attr('fill', d => `rgb(${d.value}, ${d.value * 2}, ${d.value * 3})`)
  .attr('x', (d, i) => xScale(i))
  .attr('y', d => svgHeight - yScale(d.value))
  .attr('stroke', 'black')
  .attr('stroke-width', 3)

labels.enter()
  .append('text')
  .attr('x', (d, i) => xScale(i) + (xScale.bandwidth() / 2))
  .attr('y', d => svgHeight - yScale(d.value) + 20)
  .attr('font-size', 20)
  .attr('text-anchor', 'middle')
  .attr('fill', 'white')
  .text(d => d.value);

  let asc = false;



d3.select('button').on('click', () => {
  if(!asc){
    data.sort((a,b) => b.value - a.value );
  }else{
    data.sort((a,b) => a.value - b.value );
  };

  asc = !asc;




  bars = svg.selectAll('rect').data(data, d => d.key);
  labels = svg.selectAll('text').data(data);

  bars
    .transition()
    .delay((d, i) => (i * 10))
    .duration(3000)
    .each(function(d){return this._old = d;})
    .attr('x', (d, i) => xScale(i))
    .attr('height', d => yScale(d.value))
    .attr('y', d => svgHeight - yScale(d.value));

  labels
    .transition()
    .delay((d, i) => (i * 10))
    .duration(3000)
    .tween("text", function(d) {
      var that = this;
      var i = d3.interpolate(0, d.value);  // Number(d.percentage.slice(0, -1))
      return function(t) {
          d3.select(that).text(i(t).toFixed(0));
      }
    })
    .attr('y', d => svgHeight - yScale(d.value) + 20);
})
我发现上面代码中包含的“tween”函数用于一个类似但不完全相同的问题。我不知道如何使插值从当前值开始,而不是从0开始。我知道我需要以某种方式存储旧值,并在tween中访问它,但不确定如何访问

关于tween函数的另一个问题:为什么我们在返回的函数中分配
var that=this
并选择
that


提前感谢

您可以通过不同的方式获取每个文本的当前值

例如,使用vanilla JavaScript:

var current = +(this.textContent);
或者使用D3吸气剂:

var current = +(d3.select(this).text());
以下是更改后的代码:

const数据=[{
关键字:0,
价值:50
},
{
重点:1,,
价值:20
},
{
重点:二,,
数值:100
},
{
重点:三,,
价值:30
},
{
重点:四,,
价值:40
},
{
重点:五,,
价值:70
}
]
//常量数据集=[50,20,100,30,40]
常数svgWidth=800;
常数svgHeight=400;
常量xScale=d3.scaleBand()
.域(d3.范围(数据.长度))
.rangeRound([0,svgWidth])
.填充器(0.1);
常量yScale=d3.scaleLinear()
.domain([0,d3.max(数据,d=>d.value)])
.范围([0,svgHeight]);
const svg=d3.select('body')
.append('svg')
.attr('width',svgWidth)
.attr('高度',Svghight);
让bar=svg.selectAll('rect').data(data,d=>d.key);
让labels=svg.selectAll('text').data(数据);
输入()
.append('rect')
.每个功能(d){
将此返回。_old=d;
})
.attr('width',xScale.bandwidth)
.attr('height',d=>yScale(d.value))
.attr('fill',d=>`rgb(${d.value},${d.value*2},${d.value*3})`)
.attr('x',(d,i)=>xScale(i))
.attr('y',d=>svgHeight-yScale(d.value))
.attr('笔划','黑色')
.attr('stroke-width',3)
标签。输入()
.append('文本')
.attr('x',(d,i)=>xScale(i)+(xScale.bandwidth()/2))
.attr('y',d=>svgHeight-yScale(d.value)+20)
.attr('font-size',20)
.attr('text-anchor','middle')
.attr('填充','白色')
.text(d=>d.value);
设asc=false;
d3.选择('按钮')。在('点击',()=>{
如果(!asc){
data.sort((a,b)=>b.value-a.value);
}否则{
data.sort((a,b)=>a.value-b.value);
};
asc=!asc;
bar=svg.selectAll('rect').data(data,d=>d.key);
labels=svg.selectAll('text').data(数据);
酒吧
.transition()
.延迟((d,i)=>(i*10))
.持续时间(3000)
.每个功能(d){
将此返回。_old=d;
})
.attr('x',(d,i)=>xScale(i))
.attr('height',d=>yScale(d.value))
.attr('y',d=>svgHeight-yScale(d.value));
标签
.transition()
.延迟((d,i)=>(i*10))
.持续时间(3000)
.tween(“文本”,功能(d){
var current=+(d3.select(this.text());
var=这个;
var i=d3.interpolate(当前,d.value);//Number(d.percentage.slice(0,-1))
返回函数(t){
d3.选择(that).text(i(t).toFixed(0));
}
})
.attr('y',d=>svgHeight-yScale(d.值)+20);
})

点击


我刚刚意识到,不将数据绑定到键上的元素在视觉上更有意义。这样,条和标签的转换将同步进行。再次感谢。