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>
And this is somehow what I want to get after clicking on the red path:
source to share
@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>
source to share
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>
You can adjust the data matrix to exactly match the expected result.
source to share