D3.js的反向转换不起作用

d3.js reverse transition does not work

本文关键字:转换 不起作用 js D3      更新时间:2023-09-26

我正在制作水平线段条形图。我想使它使条形图将根据每隔几秒钟随机生成的值在各个部分之间动画化颜色过渡。

我也有一个文本框,现在说"hello",它与过渡同时移动。它只在一个方向上起作用,从左到右。我无法在段之间进行颜色过渡,也无法将文本框从左向右平移。从左到右表示上次生成的数大于当前生成的数。条形图应该从右到左关闭分段。但它是从左到右的,而且文本框在反向翻译时也表现得很奇怪。

我也得到这个错误:g属性变换:预期的变换函数,"null"。在我的代码中,我想对我的valueLabel进行过渡,我认为我使用的方式是不正确的。尽管有这个错误,代码仍然执行。我的代码在这里

谢谢你的建议

var configObject = {
    svgWidth : 1000,
    svgHeight : 1000,

    minValue : 1,
    maxValue : 100,
    midRange : 50,
    highRange : 75,
    numberOfSegments : 50
};
//define variables
var newValue;
var gaugeValue = configObject.minValue - 1;
var mySegmentMappingScale;
var rectArray=[];

//define svg
var svg = d3.select("body").append("svg")
    .attr("width", configObject.svgWidth)
    .attr("height", configObject.svgHeight)
    .append("g")
    .attr("transform", 'translate(' + configObject.svgWidth/2 + ',' + configObject.svgHeight/2 + ')');
//var myG=svg.append('g');
var valueLabel= svg.append("text")
    .attr('x',0)
    .attr('y', (configObject.svgHeight/13)+15)
    .text("hello");
var backgroundRect=svg.append("rect")
    .attr("fill", "black")
    .attr("x",0) 
    .attr("y", 0)
    .attr("width", (configObject.svgWidth/3))
    .attr("height",  configObject.svgHeight/13);
for(i = 0; i <= configObject.numberOfSegments; i++){
    var myRect=svg.append("rect")
        .attr("fill", "#2D2D2D")
        .attr("x",i * ((configObject.svgWidth/3)/configObject.numberOfSegments)) 
        .attr("y", 0)
        .attr("id","rect"+i)
        .attr("width", ((configObject.svgWidth/3)/configObject.numberOfSegments)-3)
        .attr("height",  configObject.svgHeight/13);    
         rectArray.push(myRect);
    }
//define scale
function setmySegmentMappingScale(){
        var domainArray = [];
        var x=0;
        for(i = configObject.minValue; i <= configObject.maxValue+1; i = i + (configObject.maxValue - configObject.minValue)/configObject.numberOfSegments){
          if(Math.floor(i) != domainArray[x-1]){ 
               var temp=Math.floor(i);
               domainArray.push(Math.floor(i));
               x++;
           }
       }
        var rangeArray = [];
        for(i = 0; i <= configObject.numberOfSegments+1; i++){//  <=
            rangeArray.push(i);
        }
        mySegmentMappingScale = d3.scale.threshold().domain(domainArray).range(rangeArray);
    }
//generate random number
function generate(){
    var randomNumber = Math.random() * (configObject.maxValue - configObject.minValue) + configObject.minValue;     
    newValue = Math.floor(randomNumber);
    setmySegmentMappingScale(); 
    animateSVG();
}     
function animateSVG(){
var previousSegment = mySegmentMappingScale(gaugeValue) -1;
var newSegment = mySegmentMappingScale(newValue) -1;
    if(previousSegment <= -1 && newSegment > -1){
        for(i = 0; i <= newSegment; i++){ 
            rectArray[i].transition()
                .ease("linear")
                .duration(50)
                .delay(function(d){return i * 90})
                .styleTween("fill", function() { return d3.interpolate( "#2D2D2D","red"); });
                valueLabel
                .transition().ease("linear")
                .duration(50)
                .delay(function(d){return i * 90})
                .attr("transform","translate(" + (i * ((configObject.svgWidth/3)/configObject.numberOfSegments)+((configObject.svgWidth/3)/configObject.numberOfSegments)) + "," + 0 + ")")

        }
    }
    else if(newSegment > previousSegment){
        for(i = previousSegment; i <= newSegment; i++){
            rectArray[i].transition()
                        .ease("linear")
                        .duration(50)
                        .delay(function(d){return i * 90})
                         .styleTween("fill", function() { return d3.interpolate( "#2D2D2D","red"); });
            //console.log(temp);
            valueLabel
            .transition()
            .ease("linear")
            .duration(50)
            .delay(function(d){return i * 90})
            .attr("transform","translate(" + (i * ((configObject.svgWidth/3)/configObject.numberOfSegments)+((configObject.svgWidth/3)/configObject.numberOfSegments)) + "," + 0 + ")")


        }
    }
    else if(newSegment < previousSegment){
        for(i = previousSegment; i > newSegment; i--){
            rectArray[i].transition()
                        .ease("linear")
                        .duration(50)
                        .delay(function(d){return i * 90})
                        .styleTween("fill", function() { return d3.interpolate( "red","#2D2D2D"); });

                        valueLabel
                        .transition()
                        .ease("linear")
                        .duration(50)
                        .delay(function(d){return i * 90})
                        .attr("transform","translate(" + (i * ((configObject.svgWidth/3)/configObject.numberOfSegments)-((configObject.svgWidth/3)/configObject.numberOfSegments)) + "," + 0 + ")")
        }
    }   
     gaugeValue = newValue;
}
setInterval(function() {
    generate()
}, 8000);

问题只是delay

newSegment > previousSegment时,您可以这样设置延迟:

.delay(function(d){return i * 90})

这是有意义的,因为i是一个递增的变量。但是,当newSegment < previousSegment时,相同的数学不再工作:i是一个递减变量,延迟必须随着i 减小而增加,而不是相反。

这就是你需要的:

.delay(function(d){return Math.abs(i -previousSegment)*90})

这是你更新的小提琴:https://jsfiddle.net/b7usw2nr/