Selecting data based on multiple d3 attributes

I have a grid represented using d3 and svg. I am trying to select adjacent (adjacent) tiles for any particular tile in the grid. tiles are accessed through their x and y coordinates on the grid. The fact that I feel rather dirty, and does not do exactly what I want, I do not want the selected tile to be selected, or tiles diagonal to it.

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/

I am wondering: is there a way to select data through two attributes, for example:

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

This does not work for me, but its logic is how I would like to select the data.

+4
source share
3 answers

:

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");

}

, !

+2

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 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 .

+3

, , . [ = '40 '] [ = '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) {
  	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>
Hide result

Or, if you just need a cross without a center, as you describe in the question, you can do it ...

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>
Run codeHide result
+3
source

Source: https://habr.com/ru/post/1622885/


All Articles