防止在d3v5中平移地图边界之外

时间:2019-05-04 23:00:45

标签: javascript d3.js

在d3 v3中,我使用this example来防止在SVG之外平移。以下是相关代码:

.on("zoom", function() {
    // the "zoom" event populates d3.event with an object that has
    // a "translate" property (a 2-element Array in the form [x, y])
    // and a numeric "scale" property
    var e = d3.event,

    // now, constrain the x and y components of the translation by the
    // dimensions of the viewport
    tx = Math.min(0, Math.max(e.translate[0], width - width * e.scale)),
    ty = Math.min(0, Math.max(e.translate[1], height - height * e.scale));

    // then, update the zoom behavior's internal translation, so that
    // it knows how to properly manipulate it on the next movement
    zoom.translate([tx, ty]);

    // and finally, update the <g> element's transform attribute with the
    // correct translation and scale (in reverse order)
    g.attr("transform", ["translate(" + [tx, ty] + ")","scale(" + e.scale + ")"].join(" "));
}

在d3 v5中,它不再起作用。所有示例都允许地图在屏幕外平移可笑的数量。我的目标是地图的最右边永远不会比div的最右边更远,等等。我怎么能做到这一点?还有最近的例子吗?

1 个答案:

答案 0 :(得分:1)

对于您链接的示例,这些是zoom函数内部的必要更改,以便与D3 v5一起使用:

var e = d3.event.transform,
tx = Math.min(0, Math.max(e.x, width - width * e.k)),
ty = Math.min(0, Math.max(e.y, height - height * e.k));

除此之外,更改组翻译功能并删除zoom.translate([tx, ty]);

这是经过更改的原始代码:

<html>

<head>
  <title>Restricted zoom behavior in d3</title>
  <meta charset="utf-8">
  <script src="https://d3js.org/d3.v5.min.js"></script>
  <style>

  </style>
</head>

<body>
  <script>
    // first, define your viewport dimensions
    var width = 960,
      height = 500;

    // then, create your svg element and a <g> container
    // for all of the transformed content
    var svg = d3.select("body").append("svg")
      .attr("width", width)
      .attr("height", height)
      .style("background-color", randomColor),
      g = svg.append("g");

    // then, create the zoom behvavior
    var zoom = d3.zoom()
      // only scale up, e.g. between 1x and 50x
      .scaleExtent([1, 50])
      .on("zoom", function() {
        // the "zoom" event populates d3.event with an object that has
        // a "translate" property (a 2-element Array in the form [x, y])
        // and a numeric "scale" property
        var e = d3.event.transform,
          // now, constrain the x and y components of the translation by the
          // dimensions of the viewport
          tx = Math.min(0, Math.max(e.x, width - width * e.k)),
          ty = Math.min(0, Math.max(e.y, height - height * e.k));
        // then, update the zoom behavior's internal translation, so that
        // it knows how to properly manipulate it on the next movement
        // and finally, update the <g> element's transform attribute with the
        // correct translation and scale (in reverse order)
        g.attr("transform", [
          "translate(" + [tx, ty] + ")",
          "scale(" + e.k + ")"
        ].join(" "));
      });

    // then, call the zoom behavior on the svg element, which will add
    // all of the necessary mouse and touch event handlers.
    // remember that if you call this on the <g> element, the even handlers
    // will only trigger when the mouse or touch cursor intersects with the
    // <g> elements' children!
    svg.call(zoom);

    // then, let's add some circles
    var circle = g.selectAll("circle")
      .data(d3.range(300).map(function(i) {
        return {
          x: Math.random() * width,
          y: Math.random() * height,
          r: .01 + Math.random() * 50,
          color: randomColor()
        };
      }).sort(function(a, b) {
        return d3.descending(a.r, b.r);
      }))
      .enter()
      .append("circle")
      .attr("fill", function(d) {
        return d.color;
      })
      .attr("cx", function(d) {
        return d.x;
      })
      .attr("cy", function(d) {
        return d.y;
      })
      .attr("r", function(d) {
        return d.r;
      });

    function randomColor() {
      return "hsl(" + ~~(60 + Math.random() * 180) + ",80%,60%)";
    }
  </script>
</body>

</html>