我是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)
}
答案 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)
我在代码中看到了两件事:
数据绑定的关键功能不一致 - 您在初始创建圈子时正确使用它(.data(dataset, function(d) { return d.id })
),但在更新圈子时不要引用它,在更新时添加相同的键确保您正在更新相同的元素。
DOM排序 - 您在最初创建圈子时使用selection.sort似乎合乎逻辑且恰当(.sort(function(a, b){ return d3.descending(a[14], b[14]); })
)我建议将此扩展到您的更新功能,而不是重新绑定数据。
我已对您的代码进行了这些快速更新,它似乎可以解决您的问题: http://jsfiddle.net/AbHfk/3/