2016-01-05 45 views
4

我有一个表示使用d3和svg的网格。我正在尝试选择网格上任何特定图块的相邻(相邻)图块。通过网格上的x和y坐标访问切片。 我感觉相当混乱,并没有按照我想要的去做,我不希望被点击的瓷砖被选中,或者瓷砖对角。根据多个属性选择数据d3

var w = 960, 
    h = 500, 
    z = 20, 
    x = w/z, 
    y = h/z; 

var svg = d3.select("body").append("svg") 
    .attr("width", w) 
    .attr("height", h); 

svg.selectAll("rect") 
    .data(d3.range(x * y)) 
    .enter().append("rect") 
    .attr("width", z) 
    .attr("height", z) 
    .attr("clicked", false) 
    .attr('x', horizontalpos) 
    .attr('y', verticalpos) 
    .on("click", test) 
    .style("stroke", "rgb(6,120,155)") 
    .style("stroke-width", 2) 
    .style("fill", "rgb(255, 255, 255)") 

function translate(d) { 
    return "translate(" + (d % x) * z + "," + Math.floor(d/x) * z + ")"; 
} 


function verticalpos(d) { 
    return ((d % x) * z); 
} 

function horizontalpos(d) { 
    return (Math.floor(d/x) * z); 
} 

function test(){ 
    var d = d3.selectAll("[x='40']").filter("[y='40']"); 
    d3.selectAll("[x=" + "'"+ (parseInt(d.attr("x")) +20).toString() +"'" +"],[x=" + "'"+ (parseInt(d.attr("x")) -20).toString() +"'" +"],"+ "[x=" + "'"+ (parseInt(d.attr("x"))).toString() +"'" +"]") 
    .filter("[y=" + "'"+ (parseInt(d.attr("y"))).toString() +"'" +"],[y=" + "'"+ (parseInt(d.attr("y")) +20).toString() +"'" +"]"+",[y=" + "'"+ (parseInt(d.attr("y")) -20).toString() +"'" +"]") 
    .transition() 
    .style("fill", "black"); 

} 

的jsfiddle - https://jsfiddle.net/wkencq2w/15/

什么我不知道是 - 通过两个属性有没有一种方法来选择数据,就像这样:

d3.select("[x='40'], [y='40']") 

这并没有为我工作,但其背后的逻辑是我想如何选择数据。

回答

2

我试图使用过滤器来解决这个问题:

function test(d){ 
    var x = d3.select(this); 
    var x1 = (parseInt(x.attr("x")) +20); 
    var x2 = (parseInt(x.attr("x")) -20); 
    var y1 = (parseInt(x.attr("y")) +20); 
    var y2 = (parseInt(x.attr("y")) -20); 
var f = d3.selectAll("rect")[0].filter(function(d){ 
    //left rect 
    if (d3.select(d).attr("x") == x1 && d3.select(d).attr("y") == parseInt(x.attr("y"))) 
    return true; 
    //right rect 
    if (d3.select(d).attr("x") == x2 && d3.select(d).attr("y") == parseInt(x.attr("y"))) 
    return true; 
    //bottom rect 
    if (d3.select(d).attr("y") == y1 && d3.select(d).attr("x") == parseInt(x.attr("x"))) 
    return true; 
    //top rect 
    if (d3.select(d).attr("y") == y2 && d3.select(d).attr("x") == parseInt(x.attr("x"))) 
    return true; 

    return false; 
}); 
//select all filtered and make their fill black 
d3.selectAll(f).transition().delay(100).style("fill", "black"); 

} 

工作代码here

希望这有助于!

+1

谢谢!我一直在玩弄这个,并寻找年龄选项。新的JavaScript和D3,所以我感谢帮助。 – user3636636

+1

@ user3636636这两个问题,以及这个答案都混淆了网格的方向。根据'x'和'y'方块应该形成一个水平对齐的矩形,以完全填充视口。然而,现在绘制它时,它将它直立放置在SVG的底部,从而给它一个方形轮廓。尽管通过交换'verticalpos()'和'horizo​​ntalpos()'中的公式可以很容易地解决这个问题,但您可能需要查看一下我的[answer](/ a/34611132/4235784),它通过更多地依赖数据来避免此问题绑定和D3的内部工作。 – altocumulus

3

因为它是D3,我不会基于位置的计算而是基于数据绑定来做到这一点。这将大大简化事务并减少代码的数量和复杂性。一种可能的方式可能会定义为x和y属性的对象,然后将其绑定到D3选择的二维数组:

var grid = d3.range(y).map(function(dy) { 
    return d3.range(x).map(function(dx) { 
    return {x: dx, y: dy}; 
    }); 
}); 

var g = svg.selectAll("g") 
    .data(grid) 
    .enter().append("g")     // Group each row's rects in a svg:g 
    .selectAll("rect")     // Do a nested selection 
    .data(function(d) { return d; }) // Bind the sub-array for this row 

有利于大多数从这种方法的部分是你的test()功能,现在可能对绑定到每个矩形的数据进行操作,而不必获取属性值并使用它们进行计算。

function test(d) { 
    var clicked = d3.select(this).datum(); // Object bound to the rect. 
    d3.selectAll("rect").filter(function(d) { 
    // Do the filtering based on data rather than on positions. 
    return d.x === clicked.x && Math.abs(d.y - clicked.y) === 1 || 
      d.y === clicked.y && Math.abs(d.x - clicked.x) === 1; 
    }) 
    .transition() 
    .style("fill", "black"); 
} 

看看这个JSFiddle为一个完整的例子。

+0

感谢您的帮助,这看起来比我的方法更加干净和高效 – user3636636

3

您可以通过将两个属性放在一起来选择数据,例如, [X = '40 '] [Y = '40']。这与css运算符一起允许生成一个css选择字符串,该字符串为您提供了所要求的内容。

var w = 960, 
 
    h = 500, 
 
    z = 20, 
 
    x = w/z, 
 
    y = h/z; 
 

 
var svg = d3.select("body").append("svg") 
 
    .attr("width", w) 
 
    .attr("height", h); 
 

 
svg.selectAll("rect") 
 
    .data(d3.range(x * y)) 
 
    .enter().append("rect") 
 
    .attr("width", z) 
 
    .attr("height", z) 
 
    .attr("clicked", false) 
 
    .attr('x', horizontalpos) 
 
    .attr('y', verticalpos) 
 
    .on("click", test) 
 
    .style("stroke", "rgb(6,120,155)") 
 
    .style("stroke-width", 2) 
 
    .style("fill", "rgb(255, 255, 255)") 
 
    
 
function translate(d) { 
 
    return "translate(" + (d % x) * z + "," + Math.floor(d/x) * z + ")"; 
 
} 
 

 

 
function verticalpos(d) { 
 
    return ((d % x) * z); 
 
} 
 

 
function horizontalpos(d) { 
 
    return (Math.floor(d/x) * z); 
 
} 
 
    
 
function test(d) { 
 
    x = parseInt(d3.select(this).attr("x")); 
 
    y = parseInt(d3.select(this).attr("y")); 
 
    var selector = "" 
 
    for (var dx=-20;dx<=20;dx+=20) { 
 
    \t for (var dy=-20;dy<=20;dy+=20) { 
 
     selector += "[x='"+ (x + dx) +"'][y='"+ (y + dy) +"']," 
 
    } 
 
    } 
 
    // cut off the final extraneous comma 
 
    selector = selector.substring(0, selector.length - 1); 
 
    d3.selectAll(selector) 
 
    .transition() 
 
    .style("fill", "black"); 
 
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>

或者,如果你只是想而不中心的十字架你可以做到这一点的问题描述...

var w = 960, 
 
    h = 500, 
 
    z = 20, 
 
    x = w/z, 
 
    y = h/z; 
 

 
var svg = d3.select("body").append("svg") 
 
    .attr("width", w) 
 
    .attr("height", h); 
 

 
svg.selectAll("rect") 
 
    .data(d3.range(x * y)) 
 
    .enter().append("rect") 
 
    .attr("width", z) 
 
    .attr("height", z) 
 
    .attr("clicked", false) 
 
    .attr('x', horizontalpos) 
 
    .attr('y', verticalpos) 
 
    .on("click", test) 
 
    .style("stroke", "rgb(6,120,155)") 
 
    .style("stroke-width", 2) 
 
    .style("fill", "rgb(255, 255, 255)") 
 
    
 
function translate(d) { 
 
    return "translate(" + (d % x) * z + "," + Math.floor(d/x) * z + ")"; 
 
} 
 

 

 
function verticalpos(d) { 
 
    return ((d % x) * z); 
 
} 
 

 
function horizontalpos(d) { 
 
    return (Math.floor(d/x) * z); 
 
} 
 
    
 
function test(d) { 
 
    x = parseInt(d3.select(this).attr("x")); 
 
    y = parseInt(d3.select(this).attr("y")); 
 
    var selector = "" 
 
    var deltas = [[-20, 0], [20, 0], [0, 20], [0, -20]]; 
 
    for (var i=0;i < deltas.length;i++) { 
 
    selector += "[x='"+ (x + deltas[i][0]) +"'][y='"+ (y + deltas[i][1]) +"']," 
 
    } 
 
    
 
    // cut off the final extraneous comma 
 
    selector = selector.substring(0, selector.length - 1); 
 
    d3.selectAll(selector) 
 
    .transition() 
 
    .style("fill", "black"); 
 
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>