Scale path from center
If you know the coordinates of the center point, then you can combine a translate and scale in one transformation. The translation is calculated as: (1 - scale) * currentPosition
.
If the center is (10, 20)
and you are scaling by 3
then translate by (1 - 3)*10, (1 - 3)*20
= (-20, -40)
:
<g transform="translate(-20, -40) scale(3)">
<path d="M45,11.5H33.333c0.735-1.159,1.167-2.528,1.167-4C34.5,3.364,31.136,0,27,0s-7.5,3.364-7.5,7.5c0,1.472,0.432,2.841,1.167,4H9l-9,32h54L45,11.5z M22.5,7.5C22.5,5.019,24.519,3,27,3s4.5,2.019,4.5,4.5c0,1.752-1.017,3.257-2.481,4h-4.037 C23.517,10.757,22.5,9.252,22.5,7.5z" id="control"/>
</g>
The transformations are applied in reverse order from the one they are declared, so in the example, above, the scale
is performed first and then the translate
. Scaling affects the coordinates so the translation here is in scaled coordinates.
You can calculate the center point programmatically using element.getBBox()
.
How to transform: scale() from the center of the path?
You have to calculate the Scale centerpoint (actually a translate) for each of the 6 <path>
shapes.
Use a standard JavaScript Web Component <svg-hexagon>
to create all dynamically.
I leave the animations to you:
customElements.define("svg-hexagon", class extends HTMLElement {
connectedCallback() {
this.innerHTML = `<svg viewBox="0 0 1500 1500">` +
`<style>path{stroke:red;stroke-width:15;fill:lightgreen}path:hover{fill:gold}</style>` +
`<g transform="scale(0.8) translate(200 200)"></g></svg>`;
let paths = this.querySelector("g");
let xPos = 360;
for (let i = 0; i < 6; i++) {
let path = document.createElementNS("http://www.w3.org/2000/svg", "path");
let pathlocation = `rotate(${i*60} 750 750)`;
path.setAttribute("transform", pathlocation);
path.setAttribute("d", `m${xPos} 935 0-369 0 0-301-173 0 0 0 716h0l301-173`);
paths.append(path);
path.onmouseenter = (e) => {
let {left,top,x,y,width,height } = path.getBBox();
let scale = 1.5;
let cx = -(x + (width / 2)) * (scale - 1);
let cy = -(y + (height / 2)) * (scale - 1);
path.setAttribute("transform",
`${pathlocation} translate(${cx} ${cy}) scale(${scale})`);
paths.append(path); // put path on top, there is no z-index in SVG
}
path.onmouseleave = (e) => {
if(!e.ctrlKey) path.setAttribute("transform", pathlocation);
}
}
}
})
svg-hexagon {
width: 180px;
display: inline-block;
background: rebeccapurple
}
<svg-hexagon></svg-hexagon>
<svg-hexagon></svg-hexagon>
<svg-hexagon></svg-hexagon>
SVG Scale group from his center
You appear to have got your centre wrong. You are scaling around the wrong centre point.
You are dividing canvasBBox
width
and height
by two, but you are not taking into account the x
and y
values of the bbox.
The centre of the #Canvas
element is at
var cx = canvasBbox.x + canvasBbox.width/2;
var cy = canvasBbox.y + canvasBbox.height/2;
If you update the calculation with these values, you get your expected result.
var rectangle = document.querySelector("#Rectangle")var rectangleScaled = document.querySelector("#RectangleScaled")
var canvasBbox = document.querySelector("#Canvas").getBBox()
var cx = canvasBbox.x + canvasBbox.width/2;var cy = canvasBbox.y + canvasBbox.height/2;
var x = -cx * (1.4 - 1)var y = -cy * (1.4 - 1)
rectangleScaled.style.transform = "translate("+x+"px, "+y+"px) scale(1.4)"
<svg width="411" height="731" viewBox="0 0 411 731" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> <g id="Canvas" transform="translate(721 384)"> <clipPath id="clip-0" clip-rule="evenodd"> <path d="M -721 -384L -310 -384L -310 347L -721 347L -721 -384Z" fill="#FFFFFF"/> </clipPath> <g id="Google Pixel" clip-path="url(#clip-0)"> <path d="M -721 -384L -310 -384L -310 347L -721 347L -721 -384Z" fill="#FFFFFF"/>
<g id="RectangleScaled"> <use xlink:href="#path1_fill" transform="translate(-614 -152)" fill="red"/> </g> <g id="Rectangle"> <use xlink:href="#path0_fill" transform="translate(-614 -152)" fill="#C4C4C4"/> </g> </g> </g> <defs> <path id="path0_fill" d="M 0 0L 196 0L 196 266L 0 266L 0 0Z"/> <path id="path1_fill" d="M 0 0L 196 0L 196 266L 0 266L 0 0Z"/> </defs></svg>
Svg scale path at a center point (pulsating)
There is a simple solution, that is cross-browser.
Just give each of your sunbeams its own absolute transform-origin
.
.wrapper { width: 100px; text-align: center; } .icon-sun-beam { animation-name: scale; animation-duration: 3s; animation-iteration-count: infinite; animation-timing-function: linear; animation-fill-mode: both; animation-direction: alternate; } .icon-sun-beam:nth-child(even) { animation-delay: 4.5s, 4.5s; } .icon-sun { animation-name: rotate; animation-iteration-count: infinite; animation-duration: 18s; animation-timing-function: linear; transform-origin: 50px 50px; } svg { shape-rendering: geometricPrecision; } @keyframes rotate { 0% { transform: rotate(0); } 100% { transform: rotate(360deg); } } @keyframes scale { 0% { transform: scale(0.85, 0.85); } 100% { transform: scale(1.35, 1.35); } }
<div class="wrapper"> <svg version="1.1" viewBox="20 20 60 60" > <g class="icon-sun"> <path class="icon-sun-beam" style="transform-origin: 70.0px 50.0px;" d="M72.03,51.999 h-3.998 c-1.105,0-2-0.896-2-1.999 s0.895-2,2-2h3.998 c1.104,0,2,0.896,2,2 S73.136,51.999,72.03,51.999z"/> <path class="icon-sun-beam" style="transform-origin: 64.2px 35.9px;" d="M64.175,38.688c-0.781,0.781-2.049,0.781-2.828,0c-0.781-0.781-0.781-2.047,0-2.828l2.828-2.828c0.779-0.781,2.047-0.781,2.828,0c0.779,0.781,0.779,2.047,0,2.828L64.175,38.688z"/> <path class="icon-sun-beam" style="transform-origin: 50.0px 30.0px;" d="M50.034,34.002c-1.105,0-2-0.896-2-2v-3.999c0-1.104,0.895-2,2-2c1.104,0,2,0.896,2,2v3.999C52.034,33.106,51.136,34.002,50.034,34.002z"/> <path class="icon-sun-beam" style="transform-origin: 35.9px 35.9px;" d="M35.893,38.688l-2.827-2.828c-0.781-0.781-0.781-2.047,0-2.828c0.78-0.781,2.047-0.781,2.827,0l2.827,2.828c0.781,0.781,0.781,2.047,0,2.828C37.94,39.469,36.674,39.469,35.893,38.688z"/> <path class="icon-sun-beam" style="transform-origin: 30.0px 50.0px;" d="M34.034,50c0,1.104-0.896,1.999-2,1.999h-4c-1.104,0-1.998-0.896-1.998-1.999s0.896-2,1.998-2h4C33.14,48,34.034,48.896,34.034,50z"/> <path class="icon-sun-beam" style="transform-origin: 35.9px 64.1px;" d="M35.893,61.312c0.781-0.78,2.048-0.78,2.827,0c0.781,0.78,0.781,2.047,0,2.828l-2.827,2.827c-0.78,0.781-2.047,0.781-2.827,0c-0.781-0.78-0.781-2.047,0-2.827L35.893,61.312z"/> <path class="icon-sun-beam" style="transform-origin: 50.0px 70.0px;" d="M50.034,65.998c1.104,0,2,0.895,2,1.999v4c0,1.104-0.896,2-2,2c-1.105,0-2-0.896-2-2v-4C48.034,66.893,48.929,65.998,50.034,65.998z"/> <path class="icon-sun-beam" style="transform-origin: 64.2px 64.1px;" d="M64.175,61.312l2.828,2.828c0.779,0.78,0.779,2.047,0,2.827c-0.781,0.781-2.049,0.781-2.828,0l-2.828-2.827c-0.781-0.781-0.781-2.048,0-2.828C62.126,60.531,63.392,60.531,64.175,61.312z"/> <circle class="icon-sun-outline" cx="50.034" cy="50" r="11.999"/> <circle class="icon-sun-fill" fill="#FFFFFF" cx="50.034" cy="50" r="7.999"/> </g> </svg> </div>
SVG - scale path from center repetitively (pulsating)
The scale()
transformation (as all others do similarly) basically just multiplies all coordinate values with the respective scaling factor. As a result, if your object is not centered at the origin (0,0), it seems to move away from the center.
So the easy solution is, to have your object with its center at the origin, apply the transformation and the move it to wherever you want to have it.
For the sake of laziness I just moved your path element using a transform="translate(-100 -100)"
. The same effect could be achieved by modifying the coordinates themselves.
<!-- the other code -->
<path d="..." opacity="0.5" fill="url(#SVGID_4_)"
stroke="url(#SVGID_4_)" stroke-width="0.5" stroke-miterlimit="10"
transform="translate(-100 -100)"/>
<!-- more other code -->
Example Fiddle
Scale svg from center with css animation
Use transform-origin and transform-box and avoid all that translate guessing you're doing.
div { width: 100px; height: 100px; background: rgba(0,0,0,0.2)} #circle { transform: scale(1); transform-box: fill-box; transform-origin: center; animation: circle .5s linear 1.3s forwards; } @keyframes circle { to { transform: scale(4.1); } }
<div> <svg width="100px" height="100px" viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> <g id="circle" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"> <circle id="Oval" fill="#2A2C32" cx="50" cy="50" r="11.5"></circle> </g> </svg> </div>
SVG scaling from center point
You've made it hard for yourself by using clip paths. Your problem is that the clip Paths have absolute coordinates. When you scale the <a>
element up, you can't tell anything has happened because the clip path has stayed the same size.
You need to scale the clip path up. Which you can only do with Javascript. See below.
var item = document.getElementById("item1");
item.addEventListener("mouseover", function(evt) { document.querySelector("#c1 path").setAttribute("transform", "translate(155,40) scale(1.5) translate(-155,-40)");});
item.addEventListener("mouseout", function(evt) { document.querySelector("#c1 path").removeAttribute("transform");});
a { display: block; width: 1500px; height: 850px; transition: all .2s; font-size: 0; position: absolute; background: black;}
a:hover { background: gray;}
svg { display: block; height: 0;}
div#navPanel { margin-top: 50px; margin-left: 10vw;}
<head> <svg> <defs> <clipPath id="c1"> <path d=" M 10, 0 L 200, 80 L 300, 60 Z " /> </clipPath> </defs> </svg></head><body> <div id="navPanel"> <a id="item1" href="#1" class="clipPath1" style="clip-path: url(#c1)">Click me...</a> </div></body>
How to make svg path element scale up and down from the elements unknown center point?
- you actually need to calculate cx and cy in selected_colour at the moment you're just using strings
- you'd need to convert from the cx and cy strings to the values of those variables
- there's no such attribute as translate and even if there were the translates would overwrite.
- you need to set all the transforms in a single step
function unselected_colour(evt) {
// get the element that triggered the browser event
let target = evt.target;
// modify the element
target.setAttribute('transform', 'scale(1)')
}
function selected_colour(evt) {
// get the element that triggered the browser event
let target = evt.target;
// modify the element
let rect = target.getBBox();
let cx = rect.x + rect.width / 2;
let cy = rect.y + rect.height / 2;
target.setAttribute('transform', `translate(${cx}, ${cy}) scale(1.25) translate(${-cx},${-cy})`)
}
// find the SVG rectangle in the DOM
let mileEndRoad_obj = document.getElementById('mile_end_road');
let bandcroftRoad_obj = document.getElementById('bandcroft_road');
let godwardSquare_obj = document.getElementById('godward_sqaure');
var godWard_Rect = godwardSquare_obj.getBBox();
godwardSquare_obj.setAttribute('x', godWard_Rect.x);
godwardSquare_obj.setAttribute('y', godWard_Rect.y);
godwardSquare_obj.setAttribute('width', godWard_Rect.width);
godwardSquare_obj.setAttribute('height', godWard_Rect.height);
godwardSquare_obj.setAttribute('cx', (godWard_Rect.x+0.5*godWard_Rect.width));
godwardSquare_obj.setAttribute('cy', (godWard_Rect.y+0.5*godWard_Rect.height));
let compSci_obj = document.getElementById('computer_science');
let itl_obj = document.getElementById('itl');
let engineering_obj = document.getElementById('engineering');
let peoplePalace_obj = document.getElementById('people_palace');
// pass the above functions as callbacks, to be triggered by mouse events
godwardSquare_obj.addEventListener('mouseover', selected_colour, false);
godwardSquare_obj.addEventListener('mouseout', unselected_colour, false);
compSci_obj.addEventListener('mouseover', selected_colour, false);
compSci_obj.addEventListener('mouseout', unselected_colour, false);
itl_obj.addEventListener('mouseover', selected_colour, false);
itl_obj.addEventListener('mouseout', unselected_colour, false);
engineering_obj.addEventListener('mouseover', selected_colour, false);
engineering_obj.addEventListener('mouseout', unselected_colour, false);
peoplePalace_obj.addEventListener('mouseover', selected_colour, false);
peoplePalace_obj.addEventListener('mouseout', unselected_colour, false);
<svg width="1640" height="480" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">
<!-- Created with SVG-edit - https://github.com/SVG-Edit/svgedit-->
<g class="layer">
<title>map</title>
<path d="m38,86.66667l0,94l64.66666,0l0.00001,-28l8.66666,0l0,27.33333l35.33334,0l-11.33334,-20l-12.66666,0l-0.00001,-8c8,0 12.66667,0 12.66667,0c0,0 -0.66667,-65.33333 0,-65.33333c0.66667,0 -89.33333,0 -97.33333,0z"
fill="rgb(94,43,126)" id="computer_science" stroke="#000000" stroke-width="5"/>
<rect fill="#10a3a3" height="447.44527" id="bandcroft_road" stroke="#10a3a3" stroke-width="5" width="35.76642" x="308.90512" y="-24.52553"/>
<rect fill="#10a3a3" height="54.74453" id="mile_end_road" stroke="#10a3a3" stroke-width="5" width="647.44528" x="-1.31387" y="425.10952"/>
<path d="m239.41174,257.50001l-133.52938,-0.14706l-0.00001,-69.85294l50.7353,-0.00001l-16.17647,-31.61765l58.82353,0l0,30.14706l39.70588,0l0.44115,71.4706z"
fill="#1bd1a6" id="godward_sqaure" stroke="#1bd1a6" stroke-width="5"/>
<rect fill="rgb(94,43,126)" height="100.5" id="itl" stroke="#000000" stroke-width="5" width="65" x="37" y="192"/>
<path d="m174.99947,274.5c-0.33149,41.16667 0.33149,82.83333 0,124l290.39161,0l0,-11.5l69.138332,0l0,-37l-68.641082,0l0,-142.5l-101.93541,0l0,167.5l-73.09515,0l0,-101l-115.8583,0.5z"
fill="rgb(94,43,126)" id="engineering" stroke="#000000" stroke-width="5"/>
<path d="m534.99996,206.029419l70.147082,-0.147072c0,0 0.441155,35.441191 -0.294139,34.705896c-0.735294,-0.735294 33.088235,0.000001 32.64708,-0.147072c-0.441155,-0.147073 0.441156,39.852955 0,39.705882c-0.441155,-0.147073 -18.676491,0.147074 -19.117647,0c-0.441156,-0.147073 0.441155,116.323546 0,116.176471c-0.441155,-0.147076 -82.647081,0.882369 -83.088235,0.735294c-0.441154,-0.147076 -0.294141,-191.764693 -0.294141,-191.029399z"
fill="rgb(94,43,126)" id="people_palace" stroke="#000000" stroke-width="5"/>
</g>
</svg>
Related Topics
Inline Style to Act as: Hover in CSS
How to Communicate Between Frames
How to Print a Portion of an HTML Page
Why Is a Trailing Punctuation Mark Rendered at The Start with Direction:Rtl
Why Would The Height Increase with a Smaller Font Size
How to Change The Style of a <Select>'s <Optgroup> Label
How to Get Equal Width of Input and Select Fields
How to Make a Div Tag into a Link
Images in Github Pages and Relative Links
What's The Point of Having Hidden Input in HTML? What Are Common Uses for This
Tools for Obfuscating HTML and CSS
How to Create a Frosted Glass Effect Using CSS
Table Overflowing Outside of Div
CSS Overflow Hidden with Absolute Position
Center a Div Horizontally and Vertically and Keep Centered When Resizing The Parent