如何使用 svg 路径创建时髦的圆圈?
How to create funky circle using svg path?
我正在尝试复制 Patrick Heng (patrickheng.com) 在他的网站上所做的事情。当您将鼠标悬停在固定的圆圈上时,我想创建这种时髦的效果。我最接近的是使用路径创建圆然后更改路径值,但这会产生非常糟糕的结果并且不受控制。
<path
d="
M 25, 50
a 25,25 0 1,1 50,0
a 25,25 0 1,1 -50,0
" />
我们可以更改 M
和 a
的值。
这里有一些与 二次贝塞尔曲线 路径类似的东西:
const angleFromCenter = (cx, cy, mx, my) => {
const mAngle = Math.atan2(mx - cx, - my + cy);
return mAngle > 0 ? mAngle : (Math.PI * 2 + mAngle);
};
const circlePath = (cx, cy, r, mx, my) => {
const dist = Math.hypot(mx - cx, my - cy);
let path = '';
if (dist > r) {
const angle = angleFromCenter(cx, cy, mx, my);
const delta = Math.acos(r / dist);
const p0x = cx + r * Math.sin(angle - delta);
const p0y = cy - r * Math.cos(angle - delta);
const p2x = cx + r * Math.sin(angle + delta);
const p2y = cy - r * Math.cos(angle + delta);
const anchorR = dist > r * 2 ? r * 4 - dist : dist;
const p1x = cx + anchorR * Math.sin(angle);
const p1y = cy - anchorR * Math.cos(angle);
path = `M ${p0x},${p0y} Q ${p1x},${p1y} ${p2x},${p2y}`;
}
return path + `M ${cx},${cy - r} A ${r},${r} 1 1 1 ${cx},${cy + r} A ${r},${r} 1 1 1 ${cx},${cy - r} Z`;
}
const svg = d3.select('svg')
const path = circlePath(100, 100, 50, 100, 100);
const circle = svg.append('path')
.attr('d', path)
.style('fill', 'blue');
svg.on('mousemove', (e) => {
const d = circlePath(100, 100, 50, e.offsetX, e.offsetY);
circle.attr('d', d);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.7.0/d3.min.js"></script>
<svg width="200" height="200">
</svg>
我正在尝试复制 Patrick Heng (patrickheng.com) 在他的网站上所做的事情。当您将鼠标悬停在固定的圆圈上时,我想创建这种时髦的效果。我最接近的是使用路径创建圆然后更改路径值,但这会产生非常糟糕的结果并且不受控制。
<path
d="
M 25, 50
a 25,25 0 1,1 50,0
a 25,25 0 1,1 -50,0
" />
我们可以更改 M
和 a
的值。
这里有一些与 二次贝塞尔曲线 路径类似的东西:
const angleFromCenter = (cx, cy, mx, my) => {
const mAngle = Math.atan2(mx - cx, - my + cy);
return mAngle > 0 ? mAngle : (Math.PI * 2 + mAngle);
};
const circlePath = (cx, cy, r, mx, my) => {
const dist = Math.hypot(mx - cx, my - cy);
let path = '';
if (dist > r) {
const angle = angleFromCenter(cx, cy, mx, my);
const delta = Math.acos(r / dist);
const p0x = cx + r * Math.sin(angle - delta);
const p0y = cy - r * Math.cos(angle - delta);
const p2x = cx + r * Math.sin(angle + delta);
const p2y = cy - r * Math.cos(angle + delta);
const anchorR = dist > r * 2 ? r * 4 - dist : dist;
const p1x = cx + anchorR * Math.sin(angle);
const p1y = cy - anchorR * Math.cos(angle);
path = `M ${p0x},${p0y} Q ${p1x},${p1y} ${p2x},${p2y}`;
}
return path + `M ${cx},${cy - r} A ${r},${r} 1 1 1 ${cx},${cy + r} A ${r},${r} 1 1 1 ${cx},${cy - r} Z`;
}
const svg = d3.select('svg')
const path = circlePath(100, 100, 50, 100, 100);
const circle = svg.append('path')
.attr('d', path)
.style('fill', 'blue');
svg.on('mousemove', (e) => {
const d = circlePath(100, 100, 50, e.offsetX, e.offsetY);
circle.attr('d', d);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.7.0/d3.min.js"></script>
<svg width="200" height="200">
</svg>