gpt4 book ai didi

javascript - 带有自定义函数的 d3-attrTween。(我对 tween 函数有什么误解?)

转载 作者:行者123 更新时间:2023-11-30 23:55:21 24 4
gpt4 key购买 nike

我有一个关于 attrTween 的问题(有时是 tween())。

我将自定义补间函数理解为

在“attrTween('d' ”参数之后,我定义了自定义函数。因此,我编写了如下自定义函数。

        d3.selectAll('circle#circles1')
.transition()
.attrTween('d',function(){

let interpolator=d3.interpolateArray(sdata.vader,sdata1.vader);
return function(t){
return d3.select(this).attr('cy',interpolator(t))
}
})

我的目的是

For All the circles I drew,
makes a transition.
The transition is attrTween.
The changes is based on data array tied into the circles.
Original data array is sdata and the cy value in the sdata is sdata.vader.
And the transition is heading toward sdata1.and cy value for sdata1 is sdata1.vader.

To access all the cy value for every single circle,
I used d3.select(this).attr('cy')

但是,没有显示错误消息,但也没有制作动画。

我对自定义补间函数有什么误解?谁能帮我修复这个代码?

提前谢谢您。

完整代码位于以下链接中。

https://codepen.io/jotnajoa/pen/WNQeEBE

最佳答案

示例代码中存在多个问题,问题不小。提供minimal, reproducible example确实有助于解决问题。

  1. 对多个元素使用 HTML Id。

在 HTML 中,id 属性必须是唯一的。在这里,id 被分配给圆组。为此目的应使用 class 属性,而不是 id

.attr('id','circles1')

应该是:

.attr('class','circles1')

因此,attrTween 应查找类为 circle1 的圆,而不是 ID 为 #circle1 的唯一圆

d3.selectAll('circle#circles1')

应该是

d3.selectAll('.circles1')
  • ID(或类)分配在错误的位置。
  • circles1 类在创建圆之前分配,因此这些指令适用于空选择。类属性应在创建圆圈后立即设置。

    .attr('id','circles1')
    .enter()
    .append('circle')

    应该是

    .enter()
    .append('circle')
    .attr('class','circles1')
  • 补间属性错误
  • 要转换的属性是圆的 cy 属性,而不是路径的 d 属性。因此

    .attrTween('d',function(){

    应该是

    .attrTween('cy',function(){
  • 插入了错误的数据
  • sdata.vadersdata1.vader 不存在,sdatasdata1 似乎是数组对象,而这些对象又具有 vader 属性。

    您可能需要 d.vader,以及 sdata1 中相应的 .vader,即 sdata1[i]。 vader,以防两个数组中的项目顺序相同。

  • 对原始测量值而不是坐标进行插值。
  • cy 最初定义为:

    height-yscale(d.vader)

    在插值函数中,还应该使用缩放函数。

    attrTween 函数调用变为:

      .attrTween('cy',function(d, i){
    //console.log( i, height-yscale(d.vader), height-yscale(sdata1[i].vader))
    let interpolator=d3.interpolateArray(height-yscale(d.vader), height-yscale(sdata1[i].vader));

    return function(t) { return interpolator(t)}
    })
  • 在不需要的地方使用 attrTween
  • 只需使用 attr 转换圆圈就足以满足此用例,无需定义插值器。

    d3 会将圆的位置从原始位置移动到目的地,隐式插值。

    d3.selectAll('.circles1')
    .transition()
    .duration(2000)
    .attr('cy',function(d, i){
    return height-yscale(sdata1[i].vader)
    })

    出于演示目的,我添加了较长的持续时间,以明显看出圆圈移动到正确的位置。一旦到达最终位置,它们就会消失,因为它们位于粉红色圆圈下方。

    附注相同的更正集适用于相关的 circles2 设置。

    下面代码片段中的解决方案演示,因为 codepen 不允许在不创建帐户的情况下保存修改。

    var svg;
    var xscale;
    var yscale;
    var sdata;
    var xAxis;
    var yAxis;
    var width=1500;
    var height=500;
    var margin=50;
    var duration =250;
    var vader ='vader'
    var textblob='textblob'
    var delay =5000;
    var tbtrue=false;
    var areas
    var circles1,circles2;
    var sdata1,sdata2

    d3.csv('https://raw.githubusercontent.com/jotnajoa/Javascript/master/tweetdata.csv').then(function(data){
    svg=d3.select('body').append('svg').attr('width',width).attr('height',height)

    var parser = d3.timeParse("%m/%d/%y")

    // data를 처리했고, date parser 하는 법 다시한번 명심하자.
    sdata = data;
    sdata.forEach(function(d){
    d.vader = +d.vader;
    d.textblob= + d.textblob;
    d.date=parser(d.date)

    })




    // scale을 정해야 함. 나중에 brushable한 범위로 고쳐야함. nice()안하면 정렬도안되고, 첫번째 엔트리 미싱이고
    // 난리도 아님.

    xscale=d3.scaleTime()
    .domain(d3.extent(sdata, function(d) {return d.date }))
    .range([0,width*9/10])
    .nice()



    yscale =d3.scaleLinear()
    .domain(d3.extent([-1,1]))
    .range([height*4/5,height*1/5])
    .nice()

    //yaxis는 필요 없을 것 같은데.

    //캔버스에 축을 그려야 함 단, translate해서 중간에 걸치게 해야함.

    svg.append('g').attr('class','xaxis')
    .call(d3.axisBottom(xscale))
    .attr('transform','translate('+margin+','+height*1/2+')')


    //sdata plotting

    var circles = svg.append('g').attr('class','circles')
    var area = svg.append('g').attr('class','pathline')

    firststage();
    //generator로 데이터를 하나씩 떨어뜨리도록 한다.
    function firststage(){
    function* vaderdropping(data){
    for( let i=0;i<data.length;i++){
    if( i%50==0) yield svg.node();

    let cx = margin+xscale(data[i].date)
    let cy = height-yscale(data[i].vader)

    circles.append('circle')
    .attr('cx',cx)
    .attr('cy',0)
    .transition()
    .duration(duration)
    .ease(d3.easeBounce)
    .attr('cy',cy)
    .attr('r',3)
    .style('fill','rgba(230, 99, 99, 0.528)')
    }
    yield svg.node()

    }
    //generator 돌리는 부분

    let vadergen = vaderdropping(sdata);
    let result = vadergen.next()
    let interval = setInterval(function(){
    if(!result.done) {
    vadergen.next();
    }
    else {
    clearInterval(interval)

    }
    }, 100);
    setTimeout(secondstage,5000)
    }


    function secondstage(){
    function* textblobdropping(data){
    for( let i=0;i<data.length;i++){
    if( i%50==0) yield svg.node();

    let cx = margin+xscale(data[i].date)
    let cy = height-yscale(data[i].textblob)

    circles.append('circle')
    .attr('cx',cx)
    .attr('cy',0)
    .transition()
    .duration(duration)
    .ease(d3.easeBounce)
    .attr('cy',cy)
    .attr('r',3)
    .style('fill','rgba(112, 99, 230, 0.528)')
    }
    yield svg.node()

    }
    //generator 돌리는 부분

    let textblobgen = textblobdropping(sdata);
    let tresult = textblobgen.next()
    let tinterval = setInterval(function(){
    if(!tresult.done) {
    textblobgen.next();
    }
    else {
    clearInterval(tinterval)

    }
    }, 100);
    setTimeout(thirdstage,2500)
    }

    function thirdstage(){

    //진동을 만들기 위해서,
    //베이다와 텍스트 블랍 값을 플립한거다 (제발 워크 아웃하길...)
    //그 다음 트윈으로 sdata 와 sdata1을 왔다갔다 하게하면 되지않을까?
    sdata1 = sdata.map(function(x){
    var y={};
    y['date']=x.date;
    y['vader']=x.textblob;
    y['textblob']=x.vader;
    return y});
    sdata2 = sdata.map(function(x){

    var y={};
    y['date']=x.date;
    y['vader']=0;
    y['textblob']=0;
    return y});

    d3.selectAll('circle').transition()
    .duration(3500)
    .style('fill','rgba(1, 1, 1, 0.228)')

    //areas는 일종의 함수다, 에리아에다가 데이터를 먹이면,
    //에리아를 그리는 역할을 하는것임.

    areas = d3.area()
    .x(function(d){return margin+xscale(d.date)})
    .y0(function(d){return height-yscale(d.vader)})
    .y1(function(d){return height-yscale(d.textblob)})
    .curve(d3.curveCardinal)

    //이렇게 하지말고, sdata2도 만들었으니까 2->1->0 반복하는
    // 무한반복 on('end','repeat') loop를 만들어보자.

    var uarea=area.append('path')
    setTimeout(repeat,500)

    function repeat(){
    uarea
    .style('fill','rgba(112, 99, 230, 0.4)')
    .attr('d', areas(sdata))
    .transition()
    .duration(500)
    .attrTween('d',function(){
    var interpolator=d3.interpolateArray(sdata,sdata1);
    return function(t){
    return areas(interpolator(t))
    }
    })
    .transition()
    .duration(500)
    .attrTween('d',function(){
    var interpolator=d3.interpolateArray(sdata1,sdata2);
    return function(t){
    return areas(interpolator(t))
    }
    })
    .transition()
    .duration(500)
    .attrTween('d',function(){
    var interpolator=d3.interpolateArray(sdata2,sdata);
    return function(t){
    return areas(interpolator(t))
    }
    })
    .on('end',repeat)
    }
    setTimeout(fourthstage,500)
    }

    function fourthstage(){
    // console.log(d3.selectAll('circle#circles1').node())

    circles1=svg.append('g').selectAll('circle').data(sdata)
    .enter().append('circle').attr('class','circles1')
    .attr('cx',function(d){return margin+xscale(d.date)})
    .attr('cy',function(d){return height-yscale(d.vader)})
    .style('fill','green')
    .attr('r',3)

    circles2=svg.append('g').selectAll('circle').data(sdata)
    .enter().append('circle').attr('class','circles2')
    .attr('cx',function(d){return margin+xscale(d.date)})
    .attr('cy',function(d){return height-yscale(d.textblob)})
    .style('fill','pink')
    .attr('r',3)

    d3.selectAll('.circles1')
    .transition()
    .duration(5000)
    .attr('cy',function(d, i){
    return height-yscale(sdata1[i].vader)
    })

    // d3.selectAll('circle#circles2')
    // .transition()
    // .attr('cy',function(d){return 0})

    //tween 팩토리를 정의해야한다.
    //주의사항, 리턴을 갖는 함수여야한다는 것.

    //왜 꼭 return function(){}을 해야하나?
    /*
    function movey(d2){
    let y1 = this.attr('cy')
    let y2 = d2.vader
    let interpolate=d3.interpolate(y1,y2);
    interpolate;
    } 하면 안되나??
    */



    }

    })
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>

    关于javascript - 带有自定义函数的 d3-attrTween。(我对 tween 函数有什么误解?),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61095117/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com