Scale an SVG group element to dynamically track the path in the viewport

I want to scale an SVG group element so that it scales and translates to the point where the path is. This means that when I click on the path, the group should be scaled and centered along the path so that the path matches the height or width of the viewport. I've actually tried many ways, such as using getBBox()

to get the height, width, x and y of the path and subtract them from the offset of the viewports. I also tried d3.js to manipulate it. But I couldn't find a good approach.

This is HTML including SVG:

<div style="width: 700px; height:600px; border:1px solid #d0d0d0; background: #e8e8e8; margin: 0 auto;">
    <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
         viewBox="0 0 255.1 170.1" style="enable-background:new 0 0 255.1 170.1;" xml:space="preserve" width="100%" height="100%">

        <g id="floorplan">
            <path fill="#ED1C24" d="M35.8,51.8h36.3c1.6,0,2.8-1.3,2.8-2.8V22.1c0-1.6-1.3-2.8-2.8-2.8H35.8c-1.6,0-2.8,1.3-2.8,2.8v26.8
                C33,50.5,34.3,51.8,35.8,51.8z"/>
            <path fill="#4A68B1" d="M209.8,114.3h36.3c1.6,0,2.8-1.3,2.8-2.8V84.6c0-1.6-1.3-2.8-2.8-2.8h-36.3c-1.6,0-2.8,1.3-2.8,2.8v26.8
                C207,113,208.3,114.3,209.8,114.3z"/>
            <path fill="#F8991D" d="M134.3,158.8h36.3c1.6,0,2.8-1.3,2.8-2.8v-26.8c0-1.6-1.3-2.8-2.8-2.8h-36.3c-1.6,0-2.8,1.3-2.8,2.8v26.8
                C131.5,157.5,132.8,158.8,134.3,158.8z"/>
            <path fill="#ed2590" d="M13.1,124.3h36.3c1.6,0,2.8-1.3,2.8-2.8V94.6c0-1.6-1.3-2.8-2.8-2.8H13.1c-1.6,0-2.8,1.3-2.8,2.8v26.8
                C10.2,123,11.5,124.3,13.1,124.3z"/>
            <path fill="#356732" d="M161.1,42.5h36.3c1.6,0,2.8-1.3,2.8-2.8V12.8c0-1.6-1.3-2.8-2.8-2.8h-36.3c-1.6,0-2.8,1.3-2.8,2.8v26.8
                C158.2,41.2,159.5,42.5,161.1,42.5z"/>
        </g>
    </svg>
</div>

      

This is how it looks: enter image description here

And this is somehow what I want to get after clicking on the red path: enter image description here

+3


source to share


2 answers


@Alexander, beat me, but here's more d3

implementation:



<!DOCTYPE html>
<html>

<head>
  <script data-require="d3@4.0.0" data-semver="4.0.0" src="https://d3js.org/d3.v4.min.js"></script>
</head>

<body>
  <div style="width: 700px; height:600px; border:1px solid #d0d0d0; background: #e8e8e8; margin: 0 auto;">
    <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 255.1 170.1" style="enable-background:new 0 0 255.1 170.1;" xml:space="preserve" width="100%" height="100%">
      <g id="floorplan">
        <path fill="#ED1C24" d="M35.8,51.8h36.3c1.6,0,2.8-1.3,2.8-2.8V22.1c0-1.6-1.3-2.8-2.8-2.8H35.8c-1.6,0-2.8,1.3-2.8,2.8v26.8
                C33,50.5,34.3,51.8,35.8,51.8z"></path>
        <path fill="#4A68B1" d="M209.8,114.3h36.3c1.6,0,2.8-1.3,2.8-2.8V84.6c0-1.6-1.3-2.8-2.8-2.8h-36.3c-1.6,0-2.8,1.3-2.8,2.8v26.8
                C207,113,208.3,114.3,209.8,114.3z"></path>
        <path fill="#F8991D" d="M134.3,158.8h36.3c1.6,0,2.8-1.3,2.8-2.8v-26.8c0-1.6-1.3-2.8-2.8-2.8h-36.3c-1.6,0-2.8,1.3-2.8,2.8v26.8
                C131.5,157.5,132.8,158.8,134.3,158.8z"></path>
        <path fill="#ed2590" d="M13.1,124.3h36.3c1.6,0,2.8-1.3,2.8-2.8V94.6c0-1.6-1.3-2.8-2.8-2.8H13.1c-1.6,0-2.8,1.3-2.8,2.8v26.8
                C10.2,123,11.5,124.3,13.1,124.3z"></path>
        <path fill="#356732" d="M161.1,42.5h36.3c1.6,0,2.8-1.3,2.8-2.8V12.8c0-1.6-1.3-2.8-2.8-2.8h-36.3c-1.6,0-2.8,1.3-2.8,2.8v26.8
                C158.2,41.2,159.5,42.5,161.1,42.5z"></path>
      </g>
    </svg>
  </div>

  <script>

    var svg = d3.select("svg"),
        g = svg.select("g");
        
    var v = svg.attr("viewBox").split(" "),
        width = v[2],
        height = v[3];
    
    svg.on("click", function(d){
      g.attr("transform", "translate(" + [0,0] + ")scale(" + 1 + ")");
    });

    d3.selectAll("path")
      .on("click", function() {
        var bbox = this.getBBox(),
            dx = bbox.width - bbox.x,
            dy = bbox.height - bbox.y,
            x = (bbox.x + (bbox.x + bbox.width)) / 2,
            y = (bbox.y + (bbox.y + bbox.height)) / 2,
            scale = Math.min(height / bbox.height, width / bbox.width),
            translate = [width / 2 - scale * x, height / 2 - scale * y];
          
          g.attr("transform", "translate(" + translate + ")scale(" + scale + ")");
          
          d3.event.stopPropagation();
      });
  </script>

</body>

</html>
      

Run codeHide result


+4


source


Use the transform

attribute of the
selected element path

to scale and translate the object. I've used constants for the height and width of the svg element in the example below, but this will get you started.



$("#floorplan path").click(function() {
  if ($(this).attr("transform")) {
    $(this).removeAttr("transform");
    $("#floorplan path:not([transform])").show();
  } else {
    var objRect = this.getBoundingClientRect();
    var svgRect = $("#Layer_1")[0].getBoundingClientRect();
    var scaleX = svgRect.width / 255.1;
    var scaleY = svgRect.height / 170.1;
    var newX = (svgRect.left - objRect.left) / scaleX;
    var newY = (svgRect.top - objRect.top) / scaleY;
    var xScale = svgRect.width / objRect.width;
    var yScale = svgRect.height / objRect.height;
    $(this).attr("transform", "matrix(" + xScale + " 0 0 " + yScale + " " + newX * xScale + " " + newY * yScale + ")");
    $("#floorplan path:not([transform])").hide();
  }
});
      

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div style="width: 700px; height:600px; border:1px solid #d0d0d0; background: #e8e8e8; margin: 0 auto;">
  <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 255.1 170.1" xml:space="preserve">
        <g id="floorplan">
            <path fill="#ED1C24" d="M35.8,51.8h36.3c1.6,0,2.8-1.3,2.8-2.8V22.1c0-1.6-1.3-2.8-2.8-2.8H35.8c-1.6,0-2.8,1.3-2.8,2.8v26.8
                C33,50.5,34.3,51.8,35.8,51.8z"/>
            <path fill="#4A68B1" d="M209.8,114.3h36.3c1.6,0,2.8-1.3,2.8-2.8V84.6c0-1.6-1.3-2.8-2.8-2.8h-36.3c-1.6,0-2.8,1.3-2.8,2.8v26.8
                C207,113,208.3,114.3,209.8,114.3z"/>
            <path fill="#F8991D" d="M134.3,158.8h36.3c1.6,0,2.8-1.3,2.8-2.8v-26.8c0-1.6-1.3-2.8-2.8-2.8h-36.3c-1.6,0-2.8,1.3-2.8,2.8v26.8
                C131.5,157.5,132.8,158.8,134.3,158.8z"/>
            <path fill="#ed2590" d="M13.1,124.3h36.3c1.6,0,2.8-1.3,2.8-2.8V94.6c0-1.6-1.3-2.8-2.8-2.8H13.1c-1.6,0-2.8,1.3-2.8,2.8v26.8
                C10.2,123,11.5,124.3,13.1,124.3z"/>
            <path fill="#356732" d="M161.1,42.5h36.3c1.6,0,2.8-1.3,2.8-2.8V12.8c0-1.6-1.3-2.8-2.8-2.8h-36.3c-1.6,0-2.8,1.3-2.8,2.8v26.8
                C158.2,41.2,159.5,42.5,161.1,42.5z"/>
        </g>
    </svg>
</div>
      

Run codeHide result


You can adjust the data matrix to exactly match the expected result.

+3


source







All Articles