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

时间:2013-03-06 00:24:21

标签: javascript d3.js

我是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)
}

2 个答案:

答案 0 :(得分:1)

我不确定我是否掌握了整个代码(这很长),但我认为解决方案就是这样:

1 - 最初创建圆圈时,请使用按键功能。好的,你这样做:

.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属性,因此最好始终使用键功能,而不是尝试使用排序来排列。

如果您想要更具体的答案,我认为您需要将示例简化为最简单的形式,以重现问题。

答案 1 :(得分:1)

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

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

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

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