Skip to content

Instantly share code, notes, and snippets.

@ievgennaida
Created October 17, 2020 20:23
Show Gist options
  • Save ievgennaida/52eedf0b2dd8a2e6bae23f22b9adc3f5 to your computer and use it in GitHub Desktop.
Save ievgennaida/52eedf0b2dd8a2e6bae23f22b9adc3f5 to your computer and use it in GitHub Desktop.
Transform and fit any svg element into the given screeen bounds.
<html style="margin: 0px; padding: 0px;">
<body style="margin: 0px; padding: 0px;">
<svg width="1380" height="1340" xmlns="http://www.w3.org/2000/svg">
<g transform="skewX(10) translate(-3,4) rotate(30)">
<g transform="skewX(30) translate(-3,4) rotate(30)">
<g transform="skewX(10) translate(-3,4) rotate(10)">
<g transform="translate(350,30) skewX(10) rotate(30)">
<rect id="source" transform="scale(2) rotate(30) skewX(10)" x="20" y="50" width="30" height="30"
fill="red" />
</g>
</g>
</g>
</g>
<rect id="destination" x="30" y="30" width="120" height="100" fill="transparent" stroke="blue" />
</svg>
<div style="position: absolute; top:0; left:0" id="test2div"></div>
<script type="text/javascript">
function getElementMatrix(element) {
// Get consolidated element matrix:
var currentMatrix =
(element.transform.baseVal.consolidate() ||
element.ownerSVGElement.createSVGTransform()).matrix;
return currentMatrix;
}
function getScaleMatrix(scaleX, scaleY, el) {
// Return DOM matrix
var svgTransform = el.ownerSVGElement.createSVGTransform();
// Transform type is used because of the bug in chrome applying scale to the DOM matrix:
svgTransform.setScale(scaleX, scaleY);
var scaleMatrix = svgTransform.matrix;
return scaleMatrix
}
function getCenter(rect) {
return new DOMPoint((rect.x + rect.width / 2), (rect.y + rect.height / 2));
}
function fitElement(from, to, changePosition) {
var inputElement = document.getElementById(from);
var destinationElement = document.getElementById(to);
// Get center of figure in element coordinates:
var inputScreenBBox = inputElement.getBoundingClientRect();
var destinationScreenBBox = destinationElement.getBoundingClientRect();
var scaleX = destinationScreenBBox.width / inputScreenBBox.width;
var scaleY = destinationScreenBBox.height / inputScreenBBox.height;
var inputCenter = getCenter(inputScreenBBox);
var offsetX = 0;
var offsetY = 0;
if (changePosition) {
var destCenter = getCenter(destinationScreenBBox);
offsetX = destCenter.x - inputCenter.x;
offsetY = destCenter.y - inputCenter.y;
}
// create scale matrix:
var scaleMatrix = getScaleMatrix(scaleX, scaleY, inputElement);
// get element self transformation matrix:
var currentMatrix = getElementMatrix(inputElement);
scaleAndTransform = inputElement.ownerSVGElement.createSVGMatrix()
// multiply is used instead of the scale method while for some reasons matrix scale is giving proportional scaling...
// From a transforms proper matrix is generated.
.translate(offsetX, offsetY)
// Scale in screen coordinates around screen center:
.translate(inputCenter.x, inputCenter.y)
.multiply(scaleMatrix)
.translate(-inputCenter.x, -inputCenter.y)
var toScreenMatrix = inputElement.getScreenCTM();
// Scale element by a matrix in screen coordinates and convert it back to the element coordinates:
currentMatrix = currentMatrix.multiply(toScreenMatrix.inverse().multiply(scaleAndTransform).multiply(toScreenMatrix));
// Apply new created transform:
var newTransform = inputElement.ownerSVGElement.createSVGTransform();
newTransform.setMatrix(currentMatrix);
inputElement.transform.baseVal.initialize(newTransform);
}
fitElement('source', 'destination', true);
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment