Home > Enterprise >  How to "transform: scale()" from the center of the path?
How to "transform: scale()" from the center of the path?

Time:05-29

I want to increase the scale of the segments on hover, while keeping their original position what would look like "increasing the stroke width" (what isn't the way it should work, because i want the whole path consist of "actual path")

Somehow they also change position when doing so, it looks like the origin the upscaling is performed from doesn't correspond with the center of the path, but rather the top left corner.

[1] transform-origin: center; isn't what I want to do here because it sets the origin to the center of the image, not to the center of the path.

<?xml version="1.0" encoding="UTF-8"?>
<svg version="1.1" viewBox="0 0 1500 1500" xmlns="http://www.w3.org/2000/svg" id="logo">
<style type="text/css">
<!-- segments -->
.logo_segment {
fill:#000;
transition: all .2s ease-in-out;
<!-- transform-origin: center; < [1] Doesn't work the way I want to-->
}
.logo_segment:hover {
transform: scale(1.05);
transition: all .2s ease-in-out;
}
</style>
<!-- segments; clockwise, starting left-->
<path stroke="red" stroke-width="5"  d="m390.56 934.47-3e-3 -369.1-6e-3 6e-3 -300.53-173.36-0.01962 2e-3 -0.002003 715.79h3e-3l300.58-173.35"/>
<path stroke="red" stroke-width="5"  d="m410.21 531.4 318.07-183.59 2.0982-1.1952-0.02653-345.87 0.00601-0.74104-620.16 357.8-0.67685 0.24497 300.69 173.35"/>
<path stroke="red" stroke-width="5"  d="m769.58 346.54 320.1 184.8v0.0693l300.57-173.32-0.036-0.0367-619.97-357.68-0.65801-0.36979-0.01 344.55"/>
<path stroke="red" stroke-width="5"  d="m1109.4 565.35 0.01 369.46v0.01l300.56 173.35 0.053-716.15-0.071-0.0183-300.55 173.35"/>
</svg>
 

CodePudding user response:

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>

CodePudding user response:

One way to solve this is to make sure that the center of the element is 0,0. I added an extra <polygon> to the example, so that you can see that it is centered around 0,0.

In the example I reuse the <polygon> wrapped in a <g>. All transformations is done on the <g>, so that the only transform on the <polygon> is the scale on hover.

(the points of the <polygon> is found by trial and error. They could be calculated...)

.logo_segment {
  transition: all .2s ease-in-out;
}

.logo_segment:hover {
  transform: scale(1.05);
  transition: all .2s ease-in-out;
}
<svg version="1.1" viewBox="0 0 1500 1500" xmlns="http://www.w3.org/2000/svg" id="logo">
  <defs>
    <g id="segment">
      <polygon  points="184,150 357,-150 -357,-150 -184,150" stroke="red" stroke-width="5" />
    </g>
  </defs>
  <!--extra polygon to show that center is 0,0 -->
  <polygon  points="184,150 357,-150 -357,-150 -184,150" stroke="red" stroke-width="5" />
  <use href="#segment" transform="translate(750 750) rotate(30) translate(0 -510)" fill="gray" />
  <use href="#segment" transform="translate(750 750) rotate(90) translate(0 -510)" />
  <use href="#segment" transform="translate(750 750) rotate(150) translate(0 -510)" />
  <use href="#segment" transform="translate(750 750) rotate(210) translate(0 -510)" />
  <use href="#segment" transform="translate(750 750) rotate(270) translate(0 -510)" />
  <use href="#segment" transform="translate(750 750) rotate(330) translate(0 -510)" />
</svg>

CodePudding user response:

You just want transform-origin:center in combination with transform-box:fill-box to set the box to the path's box.

<?xml version="1.0" encoding="UTF-8"?>
<svg version="1.1" viewBox="0 0 1500 1500" xmlns="http://www.w3.org/2000/svg" id="logo">
<style type="text/css">
<!-- segments -->
.logo_segment {
fill:#000;
transform-origin: center;
transform-box: fill-box;
transition: all .2s ease-in-out;
<!-- transform-origin: center; < [1] Doesn't work the way I want to-->
}
.logo_segment:hover {
transform: scale(1.05);
transition: all .2s ease-in-out;
}
</style>
<!-- segments; clockwise, starting left-->
<path stroke="red" stroke-width="5"  d="m390.56 934.47-3e-3 -369.1-6e-3 6e-3 -300.53-173.36-0.01962 2e-3 -0.002003 715.79h3e-3l300.58-173.35"/>
<path stroke="red" stroke-width="5"  d="m410.21 531.4 318.07-183.59 2.0982-1.1952-0.02653-345.87 0.00601-0.74104-620.16 357.8-0.67685 0.24497 300.69 173.35"/>
<path stroke="red" stroke-width="5"  d="m769.58 346.54 320.1 184.8v0.0693l300.57-173.32-0.036-0.0367-619.97-357.68-0.65801-0.36979-0.01 344.55"/>
<path stroke="red" stroke-width="5"  d="m1109.4 565.35 0.01 369.46v0.01l300.56 173.35 0.053-716.15-0.071-0.0183-300.55 173.35"/>
</svg>
 

  • Related