根据d3js中的碰撞检测散点图显示标签

时间:2018-02-12 10:11:11

标签: d3.js collision scatter-plot

当我们没有碰撞/重叠时,我想在散点图的圆圈上显示标签。带标签的散点图的简单示例如下:

var width = 500;
var height = 500;

var margin = {
    top: 40,
    right: 40,
    bottom: 40,
    left: 40
};

var x = d3.scale.linear().range([0, width]);
var y = d3.scale.linear().range([height, 0]);

var minX = _(data).orderBy('x').first().x;
var maxX = _(data).orderBy('x').last().x;

x.domain([minX - 500, maxX + 500]);
y.domain([0, 100]);

var xAxis = d3.svg.axis()
        .scale(x)
        .orient("bottom");

var yAxis = d3.svg.axis()
        .scale(y)
        .orient("left");

var svg = d3
        .select("#d3")
        .append("svg")
        .attr("width", width + margin.left + margin.right)
        .attr("height", height + margin.top + margin.bottom)
        .append("g")
        .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

svg.append("g")
        .attr("class", "x axis")
        .attr("transform", "translate(" + 0 + "," + height / 2 + ")")
        .call(xAxis);

svg.append("g")
        .attr("class", "y axis")
        .attr("transform", "translate(" + width / 2 + "," + 0 + ")")
        .call(yAxis)
        .append("text");

var gdots =  svg.selectAll("g.dot")
        .data(data)
        .enter().append('g');

        gdots.append("circle")
        .attr("class", "dot")
        .attr("r", function (d) {
            return d.r;
        })
        .attr("cx", function (d) {
            return x(d.x);
        })
        .attr("cy", function (d) {
            return y(d.y);
        })
        .style("fill", function (d) {
            return d.c;
        });
        gdots.append("text").text(function(d){
            return d.name;
        })
        .attr("x", function (d) {
            return x(d.x);
        })
        .attr("y", function (d) {
            return y(d.y);
        });

这个例子可以在小提琴上找到: https://jsfiddle.net/8e7qmzw8/1/

如何在给定示例中应用碰撞检测以显示非碰撞圆圈的标签?

1 个答案:

答案 0 :(得分:0)

这是一种蛮力搜索方法:

gdots
   // filter out those in a colliding state
  .filter(function(d0, i){
    var isCollide = false,
        x0 = x(d0.x),
        y0 = y(d0.y);
    gdots.data().forEach(function(d1,j){
      // if it has a collision with another, stop looking
      if (!isCollide){
        // if it's not itself
        if (d0.name != d1.name){
          var x1 = x(d1.x),
              y1 = y(d1.y);
           // if they overlap             
           isCollide = Math.pow((x1-x0),2) + Math.pow((y1-y0),2) <= Math.pow((d0.r+d1.r), 2);
        }
      }
    });
    return !isCollide;
  })            
  .append("text").text(function(d){
    return d.name;
  });

运行代码:

var data = [
        {"x": -123, "y": 63, "r": 37, "c": "#50C2E3", "name": "A"},
        {"x": 71, "y": 0, "r": 15, "c": "#50C2E3", "name": "B"},
        {"x": 3845, "y": 77, "r": 15, "c": "#50C2E3", "name": "C"},
        {"x": 3176, "y": 90, "r": 15, "c": "#50C2E3", "name": "D"},
        {"x": -17, "y": 56, "r": 15, "c": "#50C2E3", "name": "D"},
        {"x": 1357, "y": 58, "r": 15, "c": "#50C2E3", "name": "E"},
        {"x": 7684, "y": 75, "r": 15, "c": "#50C2E3", "name": "F"}
    ];

    var width = 500;
    var height = 500;

    var margin = {
        top: 40,
        right: 40,
        bottom: 40,
        left: 40
    };

    var x = d3.scale.linear().range([0, width]);
    var y = d3.scale.linear().range([height, 0]);

    var minX = _(data).orderBy('x').first().x;
    var maxX = _(data).orderBy('x').last().x;

    x.domain([minX - 500, maxX + 500]);
    y.domain([0, 100]);

    var xAxis = d3.svg.axis()
            .scale(x)
            .orient("bottom");

    var yAxis = d3.svg.axis()
            .scale(y)
            .orient("left");

    var svg = d3
            .select("#d3")
            .append("svg")
            .attr("width", width + margin.left + margin.right)
            .attr("height", height + margin.top + margin.bottom)
            .append("g")
            .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

    svg.append("g")
            .attr("class", "x axis")
            .attr("transform", "translate(" + 0 + "," + height / 2 + ")")
            .call(xAxis);

    svg.append("g")
            .attr("class", "y axis")
            .attr("transform", "translate(" + width / 2 + "," + 0 + ")")
            .call(yAxis)
            .append("text");
              

  var gdots =  svg.selectAll("g.dot")
            .data(data)
            .enter().append('g');
            
            gdots.append("circle")
            .attr("class", "dot")
            .attr("r", function (d) {
                return d.r;
            })
            .attr("cx", function (d) {
                return x(d.x);
            })
            .attr("cy", function (d) {
                return y(d.y);
            })
            .style("fill", function (d) {
                return d.c;
            });
            gdots
            	.filter(function(d0, i){
              	var isCollide = false,
                		x0 = x(d0.x),
                    y0 = y(d0.y);
              	gdots.data().forEach(function(d1,j){
                	if (!isCollide){
                    if (d0.name != d1.name){
                      var x1 = x(d1.x),
                          y1 = y(d1.y);                  	
                      isCollide = Math.pow((x1-x0),2) + Math.pow((y1-y0),2) <= Math.pow((d0.r+d1.r), 2);
                    }
                  }
                });
                return !isCollide;
              })            
              .append("text").text(function(d){
                return d.name;
              })
              .attr("x", function (d) {
                  return x(d.x);
              })
              .attr("y", function (d) {
                  return y(d.y);
              });
.node {
            cursor: pointer;
        }

        .dot {
            opacity: .7;
            cursor: pointer;
        }

        .axis path,
        .axis line {
            fill: none;
            stroke: rgb(31, 119, 180);
            shape-rendering: crispEdges;
        }

        text {
            stroke: none;
            fill: #666666;
            font-size: .6em;
            font-family: "Helvetica Neue"
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.11.2/lodash.min.js"></script>
<div id="d3"></div>