如何从路径的中心"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>
我想在悬停时增加线段的比例,同时保持它们的原始位置,看起来像“增加笔划宽度”(这不是它应该的工作方式,因为我希望整个路径由“实际路径”组成)
这样做时它们也会以某种方式改变位置,看起来执行放大的原点与路径中心不对应,而是左上角。
[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>