更新形状属性时的对象一致性

Object Consistency when updating shape attributes

本文关键字:对象 一致性 属性 更新      更新时间:2023-09-26

我是D3和Javascript的新手,所以如果我的代码看起来有点丑或组织不好,请原谅我。

我一直在研究一个利用3个指标的绘图:x轴和y轴,以及圆的半径作为绘图的数据指标。我正在读取的数据是一个二维数组,每一行是一个不同的度量,每一列是一个新的数据点。我已经成功地实现了一种方法,通过从下拉框中选择不同的度量来动态地改变圆的半径,但这是在与一个非常特殊的问题进行无休止的斗争之后-我的数据被分配到错误的圆!

当我最初创建我的圆圈时,我首先使用sort()从默认半径度量(在我的代码中,它的"impactcpu")降序排序圆圈。这样做是为了解决一个问题,即在较小的圆圈之后绘制较大的圆圈会阻碍较小的圆圈,所以我想先"绘制"最大的圆圈。

我能够解决这个问题,首先排序我的计算数据数组,然后将其分配给圆圈,这保留了默认的顺序。然而,我现在尝试对X轴和Y轴做类似的事情。虽然我的下拉菜单是正确分配公制值的圆圈,它是这样做的错误的圆圈。我还没有找到解决这个问题的方法,因为在分配之前重新排序数组就像我为半径做的那样不起作用(这是我所期望的)。有什么建议,我如何才能确保正确的数据点分配到正确的圆?最好是一个不需要修改我其余代码的代码:)

请查看我的jsfiddle,以了解我的上述情况:

http://jsfiddle.net/kingernest/YDQR4/3/

创建圆圈的例子:

var circles = svg.selectAll("circle")
    .data(dataset, function(d) { return d.id })
    .enter()    
    .append("circle")
    .sort(function(a, b){    //Sort by radius size, helps reduce obstruction of circles
        return d3.descending(a[14], b[14]);
    })
    .attr("cx", function(d){ //x axis is Req IO, col index 9
        return xScale(d[9]);
    })
    .attr("cy", function(d){ //y axis is Req CPU, col index 8
        return yScale(d[8]);
    })
    .attr("r", function(d){ //radius is based off Impact CPU, col 14
        console.log("Rad: " + d[14])
        return d[14] * 1.5;
    })
    .attr("class", "dataCircle")

我当前如何改变我的半径:

function changeRad() {
     console.log(this.value); 
     var myRadData = [];
     var index = metricHash[this.value];
     var weight; //to adjust data to fit appropriately in graph
    switch(this.value) 
    {
        case "impactcpu": 
            weight = 1.5;
            break;
        case "spool": 
            weight = .0000001;    //spool is normally a very large value
            break;
        case "pji": 
            weight = 8;
            break;
        case "unnecio": 
            weight = 12;
            break;
        case "duration": 
            weight = .0002;
            break;
        default: alert("Invalid value: " + this.value); 
            break;
    }
     for(var i=0; i < dataset.length; i++)
     {         
         console.log(dataset[i][index]);
         myRadData.push(dataset[i][index] * weight);
     }
    myRadData.sort(function(a,b){return b-a});
    d3.selectAll("circle")
        .data(myRadData)
        .transition().duration(500)
        .attr("r", function(d){
            return d;
        });
    circles.data(dataset); //reassign old data set (with all data values)
}

我在你的代码中看到了两件事:

  1. 数据绑定上不一致的键函数-您在初始创建圆圈(.data(dataset, function(d) { return d.id }))时正确使用它,但在更新它们时不要引用它,在更新上添加相同的键将确保您更新相同的元素。

  2. DOM排序-选择的使用。排序时,最初创建您的圈子似乎合乎逻辑和适当的(.sort(function(a, b){ return d3.descending(a[14], b[14]); })),我建议将此扩展到您的更新功能,而不是重新绑定数据。

我已经对你的代码进行了这些快速更新,它似乎解决了你的问题:http://jsfiddle.net/AbHfk/3/

我不确定我是否掌握了您的整个代码(它相当长),但我认为解决方案是沿着这些行:

1 -当您最初创建圆圈时,使用keys函数。很好,你在这样做:

.data(dataset, function(d) { return d.id; })

2 -使用相同的函数给圆圈一个ID属性:

.attr("ID", function(d) { return d.id; })

3 -然后当你需要单独修改一个特定的圆时,你可以像这样选择它:

svg.select('#' + myCircleID).attr('blahblah', somevalue)

我还注意到,在构建myRadData数组时丢失了ID属性。这将阻止代码将它们连接到正确的圆圈上。由于一开始就有一个ID属性,因此最好始终使用keys函数,而不是尝试使用排序来使内容排列。

如果你想要一个更具体的答案,我认为你需要把这个例子浓缩成尽可能简单的形式来再现这个问题。