如何从路径的中心"transform: scale()"?

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

我想在悬停时增加线段的比例,同时保持它们的原始位置,看起来像“增加笔划宽度”(这不是它应该的工作方式,因为我希望整个路径由“实际路径”组成)

这样做时它们也会以某种方式改变位置,看起来执行放大的原点与路径中心不对应,而是左上角。

[1] 变换原点:中心;这不是我想在这里做的,因为它将原点设置为图像的中心,而不是路径的中心。

<?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" class="logo_segment" 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" class="logo_segment" 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" class="logo_segment" 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" class="logo_segment" 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>
 

您必须计算 6 个 <path> 形状中每个形状的缩放中心点(实际上是平移)。

使用标准 JavaScript Web 组件 <svg-hexagon> 动态创建。

我把动画留给你了:

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>

解决这个问题的一种方法是确保元素的中心是 0,0。我在示例中添加了一个额外的 <polygon>,以便您可以看到它以 0,0.

为中心

在示例中,我重复使用 <polygon> 包装在 <g> 中。所有变换都在 <g> 上完成,因此 <polygon> 上的唯一变换是悬停时的比例。

<polygon>的点是通过反复试验找到的,可以计算出来...)

.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 class="logo_segment" 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 class="logo_segment" 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>

您只需要 transform-origin:center 与 transform-box:fill-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" class="logo_segment" 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" class="logo_segment" 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" class="logo_segment" 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" class="logo_segment" 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>