javascript - 如何在重叠时改变两个圆圈的颜色?

标签 javascript html css d3.js svg

您好,我想知道如何使两个圆圈在重叠时改变颜色。最好重叠的部分会变成白色,因为它意味着代表集合。

var canvas = d3.select("canvas"),
    context = canvas.node().getContext("2d"),
    width = canvas.property("width"),
    height = canvas.property("height"),
    radius = 32;

var circles = d3.range(4).map(function(i) {
  return {
    index: i,
    x: Math.round(Math.random() * (width - radius * 2) + radius),
    y: Math.round(Math.random() * (height - radius * 2) + radius)
  };
});

var color = d3.scaleOrdinal()
    .range(d3.schemeCategory20);

render();

canvas.call(d3.drag()
    .subject(dragsubject)
    .on("start", dragstarted)
    .on("drag", dragged)
    .on("end", dragended)
    .on("start.render drag.render end.render", render));

function render() {
  context.clearRect(0, 0, width, height);
  for (var i = 0, n = circles.length, circle; i < n; ++i) {
    circle = circles[i];
    context.beginPath();
    context.moveTo(circle.x + radius, circle.y);
    context.arc(circle.x, circle.y, radius, 0, 2 * Math.PI);
    context.fillStyle = color(circle.index);
    context.fill();
    if (circle.active) {
      context.lineWidth = 2;
      context.stroke();
    }
  }
}

function dragsubject() {
  for (var i = circles.length - 1, circle, x, y; i >= 0; --i) {
    circle = circles[i];
    x = circle.x - d3.event.x;
    y = circle.y - d3.event.y;
    if (x * x + y * y < radius * radius) return circle;
  }
}

function dragstarted() {
  circles.splice(circles.indexOf(d3.event.subject), 1);
  circles.push(d3.event.subject);
  d3.event.subject.active = true;
}

function dragged() {
  d3.event.subject.x = d3.event.x;
  d3.event.subject.y = d3.event.y;
}

function dragended() {
  d3.event.subject.active = false;
}
<canvas width="800" height="500"></canvas>
<script src="//d3js.org/d3.v4.min.js"></script>

我理想的解决方案是允许我将重叠部分的颜色更改为另一种颜色以表示 2 组之间的交集。

提前致谢

编辑:已经进行了一些更新,但是我只找到了如何为静态元素着色而不是移动元素

var   x1 = 100,
      y1 = 100,
      x2 = 150,
      y2 = 150,
      r = 70;

    var svg = d3.select('svg')
      .append('svg')
      .attr('width', 500)
      .attr('height', 500);

    svg.append('circle')
      .attr('cx', x1)
      .attr('cy', y1)
      .attr('r', r)
      .style('fill', 'steelblue')
      .style("fill-opacity",0.5)
      .style("stroke","black");

    svg.append('circle')
      .attr('cx', x2)
      .attr('cy', y2)
      .attr('r', r)
      .style('fill', 'orange')
      .style("fill-opacity",0.5)
      .style("stroke","black");

    var interPoints = intersection(x1, y1, r, x2, y2, r);

    svg.append("g")
      .append("path")
      .attr("d", function() {
        return "M" + interPoints[0] + "," + interPoints[2] + "A" + r + "," + r +
          " 0 0,1 " + interPoints[1] + "," + interPoints[3]+ "A" + r + "," + r +
          " 0 0,1 " + interPoints[0] + "," + interPoints[2];
      })
      .style('fill', 'red')
      .style("fill-opacity",0.5)
      .style("stroke","black");


    function intersection(x0, y0, r0, x1, y1, r1) {
      var a, dx, dy, d, h, rx, ry;
      var x2, y2;

      /* dx and dy are the vertical and horizontal distances between
       * the circle centers.
       */
      dx = x1 - x0;
      dy = y1 - y0;

      /* Determine the straight-line distance between the centers. */
      d = Math.sqrt((dy * dy) + (dx * dx));

      /* Check for solvability. */
      if (d > (r0 + r1)) {
        /* no solution. circles do not intersect. */
        return false;
      }
      if (d < Math.abs(r0 - r1)) {
        /* no solution. one circle is contained in the other */
        return false;
      }

      /* 'point 2' is the point where the line through the circle
       * intersection points crosses the line between the circle
       * centers.  
       */

      /* Determine the distance from point 0 to point 2. */
      a = ((r0 * r0) - (r1 * r1) + (d * d)) / (2.0 * d);

      /* Determine the coordinates of point 2. */
      x2 = x0 + (dx * a / d);
      y2 = y0 + (dy * a / d);

      /* Determine the distance from point 2 to either of the
       * intersection points.
       */
      h = Math.sqrt((r0 * r0) - (a * a));

      /* Now determine the offsets of the intersection points from
       * point 2.
       */
      rx = -dy * (h / d);
      ry = dx * (h / d);

      /* Determine the absolute intersection points. */
      var xi = x2 + rx;
      var xi_prime = x2 - rx;
      var yi = y2 + ry;
      var yi_prime = y2 - ry;

      return [xi, xi_prime, yi, yi_prime];
    }
<script data-require="d3@3.5.3" data-semver="3.5.3" src="//cdnjs.cloudflare.com/ajax/libs/d3/3.5.3/d3.js"></script>
<svg width="500" height="500"></svg>

^这适用于静力学

var svg = d3.select("svg"),
    width = +svg.attr("width"),
    height = +svg.attr("height"),
    radius = 32;

var circles = d3.range(4).map(function() {
  return {
    x: Math.round(Math.random() * (width - radius * 2) + radius),
    y: Math.round(Math.random() * (height - radius * 2) + radius)
  };
});

var color = d3.scaleOrdinal()
    .range(d3.schemeCategory20);

svg.selectAll("circle")
  .data(circles)
  .enter().append("circle")
  	.style("fill-opacity",0.3)
    .style("stroke","black")
    .attr("cx", function(d) { return d.x; })
    .attr("cy", function(d) { return d.y; })
    .attr("r", 60)
    .style("fill", function(d, i) { return color(i); })
    .call(d3.drag()
        .on("start", dragstarted)
        .on("drag", dragged)
        .on("end", dragended));

function dragstarted(d) {
  d3.select(this).raise().classed("active", true);
}

function dragged(d) {
  d3.select(this).attr("cx", d.x = d3.event.x).attr("cy", d.y = d3.event.y);
}

function dragended(d) {
  d3.select(this).classed("active", false);
}
<svg width="500" height="500"></svg>
<script src="//d3js.org/d3.v4.min.js"></script>

^这是我要添加上述效果的移动圆圈。

有什么办法可以结合这两个代码来实现这个目标吗?

再次感谢

最佳答案

您可以使用 intersection dragged 中的static 方法(第二个片段)的功能您的动态方法的功能(第三个片段)。

首先,让我们创建 2 个组,这样“交点” 路径将始终在圆圈的前面:

var g1 = svg.append("g");
var g2 = svg.append("g");

现在到了重要的部分。

dragged里面函数,获取另一个(未拖动的)圆的位置:

var otherCircle = circles.filter(function(e, j) {
    return i !== j;
}).datum();

如果你有两个以上的圆圈,你将不得不重构它,但我下面的演示只有两个圆圈,所以让我们继续。

然后,检查它们是否重叠:

Math.hypot(d.x - otherCircle.x, d.y - otherCircle.y) < 2 * radius

如果他们这样做,请调用 intersection , 并设置路径的 d属性:

var interPoints = intersection(d.x, d.y, radius, otherCircle.x, otherCircle.y, radius);
path.attr("d", function() {
  return "M" + interPoints[0] + "," + interPoints[2] + "A" + radius + "," + radius +
    " 0 0,1 " + interPoints[1] + "," + interPoints[3] + "A" + radius + "," + radius +
    " 0 0,1 " + interPoints[0] + "," + interPoints[2];
})

如果他们不这样做,删除路径:

path.attr("d", null)

这是工作演示:

var svg = d3.select("svg"),
  width = +svg.attr("width"),
  height = +svg.attr("height"),
  radius = 60;

var data = d3.range(2).map(function(d, i) {
  return {
    x: i ? 200 : 400,
    y: 150
  };
});

var g1 = svg.append("g");
var g2 = svg.append("g");

var color = d3.scaleOrdinal()
  .range(d3.schemeCategory10);

var circles = g1.selectAll("circle")
  .data(data)
  .enter().append("circle")
  .style("fill-opacity", 0.3)
  .style("stroke", "black")
  .attr("cx", function(d) {
    return d.x;
  })
  .attr("cy", function(d) {
    return d.y;
  })
  .attr("r", radius)
  .style("fill", function(d, i) {
    return color(i);
  })
  .call(d3.drag()
    .on("start", dragstarted)
    .on("drag", dragged)
    .on("end", dragended));

var path = g2.append("path")
  .style("fill", "white")
  .style("stroke", "black")
  .attr("d", null);

function dragstarted(d) {
  d3.select(this).raise().classed("active", true);
}

function dragged(d, i) {
  d3.select(this).attr("cx", d.x = d3.event.x).attr("cy", d.y = d3.event.y);
  var otherCircle = circles.filter(function(e, j) {
    return i !== j;
  }).datum();
  if (Math.hypot(d.x - otherCircle.x, d.y - otherCircle.y) < 2 * radius) {
    var interPoints = intersection(d.x, d.y, radius, otherCircle.x, otherCircle.y, radius);
    path.attr("d", function() {
      return "M" + interPoints[0] + "," + interPoints[2] + "A" + radius + "," + radius +
        " 0 0,1 " + interPoints[1] + "," + interPoints[3] + "A" + radius + "," + radius +
        " 0 0,1 " + interPoints[0] + "," + interPoints[2];
    })
  } else {
    path.attr("d", null)
  }
}

function dragended(d) {
  d3.select(this).classed("active", false);
}

function intersection(x0, y0, r0, x1, y1, r1) {
  var a, dx, dy, d, h, rx, ry;
  var x2, y2;

  /* dx and dy are the vertical and horizontal distances between
   * the circle centers.
   */
  dx = x1 - x0;
  dy = y1 - y0;

  /* Determine the straight-line distance between the centers. */
  d = Math.sqrt((dy * dy) + (dx * dx));

  /* Check for solvability. */
  if (d > (r0 + r1)) {
    /* no solution. circles do not intersect. */
    return false;
  }
  if (d < Math.abs(r0 - r1)) {
    /* no solution. one circle is contained in the other */
    return false;
  }

  /* 'point 2' is the point where the line through the circle
   * intersection points crosses the line between the circle
   * centers.  
   */

  /* Determine the distance from point 0 to point 2. */
  a = ((r0 * r0) - (r1 * r1) + (d * d)) / (2.0 * d);

  /* Determine the coordinates of point 2. */
  x2 = x0 + (dx * a / d);
  y2 = y0 + (dy * a / d);

  /* Determine the distance from point 2 to either of the
   * intersection points.
   */
  h = Math.sqrt((r0 * r0) - (a * a));

  /* Now determine the offsets of the intersection points from
   * point 2.
   */
  rx = -dy * (h / d);
  ry = dx * (h / d);

  /* Determine the absolute intersection points. */
  var xi = x2 + rx;
  var xi_prime = x2 - rx;
  var yi = y2 + ry;
  var yi_prime = y2 - ry;

  return [xi, xi_prime, yi, yi_prime];
}
svg {
  background-color: wheat;
}
<script src="https://d3js.org/d3.v5.min.js"></script>
<svg width="600" height="300"></svg>

关于javascript - 如何在重叠时改变两个圆圈的颜色?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47786807/

相关文章:

javascript - 将数组的元素转换为对象/Javascript

javascript - TS 中 "every"函数的 TypeError

javascript - javascript中NaN的保留关键字是什么?

html - 我可以使用 html 5 并访问电话 API 吗?

html - 使用 CSS 隐藏 HTML 元素

vim 中的 Javascript 语法高亮显示

javascript - jquery 选择当前 tr 的第二个和第三个单元格

javascript - jQuery |将焦点设置为输入(固定焦点)

css - 如何创建网格/平铺 View ?

javascript - jQuery Flot 垂直条形图工具提示位置