主题文件编辑器:function
function svg_business_map_shortcode() {
ob_start();
?>
<div class="svg-business-wrap">
<!-- SVG -->
<div class="svg-area">
<svg viewBox="0 0 1000 1000" class="business-svg">
<circle class="circle circle-a" cx="400" cy="400" r="320" />
<circle class="circle circle-b" cx="580" cy="360" r="260" />
<circle class="circle circle-c" cx="320" cy="520" r="220" />
<circle class="node" data-target="a" cx="140" cy="260" r="8" />
<circle class="node" data-target="b" cx="700" cy="300" r="8" />
<circle class="node" data-target="c" cx="260" cy="720" r="8" />
</svg>
</div>
<!-- 内容 -->
<div class="panel">
<div class="content active" data-id="a">
<h3>project1</h3>
<p>content1</p>
</div>
<div class="content" data-id="b">
<h3>project2</h3>
<p>content2</p>
</div>
<div class="content" data-id="c">
<h3>project3</h3>
<p>content3</p>
</div>
</div>
</div>
<?php
return ob_get_clean();
}
add_shortcode('svg_business_map', 'svg_business_map_shortcode');
function svg_business_map_scripts() {
wp_enqueue_script(
'svg-business-map',
get_theme_file_uri('/svg-business-map.js'),
[],
false,
true
);
}
add_action('wp_enqueue_scripts', 'svg_business_map_scripts');
服务器端public_html/wp-content/themes/twentytwentyfive
新建:svg-business-map.js
document.addEventListener('DOMContentLoaded', function () {
const wrap = document.querySelector('.svg-business-wrap');
if (!wrap) return;
const circles = wrap.querySelectorAll('.circle');
// 初始化描边隐藏
circles.forEach(circle => {
const length = circle.getTotalLength();
circle.style.strokeDasharray = length;
circle.style.strokeDashoffset = length;
});
// 滚动监听
const observer = new IntersectionObserver(
entries => {
entries.forEach(entry => {
if (entry.isIntersecting) {
animateCircles();
observer.disconnect(); // 只执行一次
}
});
},
{
threshold: 0.4 // 进入40%才触发
}
);
observer.observe(wrap);
function animateCircles() {
circles.forEach((circle, index) => {
setTimeout(() => {
circle.style.transition = "stroke-dashoffset 1.6s ease";
circle.style.strokeDashoffset = 0;
}, index * 300); // 每个圆延迟300ms
});
}
/* =====================
下面是你原来的点击逻辑
===================== */
const nodes = wrap.querySelectorAll('.node');
const contents = wrap.querySelectorAll('.content');
const circleMap = {
a: wrap.querySelector('.circle-a'),
b: wrap.querySelector('.circle-b'),
c: wrap.querySelector('.circle-c'),
};
function activate(key) {
Object.values(circleMap).forEach(c => c.classList.remove('active'));
circleMap[key].classList.add('active');
contents.forEach(c => c.classList.remove('active'));
wrap.querySelector('.content[data-id="' + key + '"]').classList.add('active');
}
nodes.forEach(node => {
const key = node.dataset.target;
node.addEventListener('click', () => activate(key));
node.addEventListener('touchstart', () => activate(key));
});
});
circle.style.opacity = 1;
setTimeout(() => {
wrap.querySelector('.circle-a').classList.add('active');
}, circles.length * 300 + 800);
自定义额外CSS
.svg-business-wrap {
display: flex;
gap: 40px;
align-items: center;
}
/* SVG 区域 */
.svg-area {
flex: 1;
}
.business-svg {
width: 100%;
max-width: 580px;
}
/* 圆样式 */
.circle {
fill: none;
stroke: #ccc;
stroke-width: 3;
transition: stroke 0.3s ease, stroke-width 0.3s ease;
}
.circle.active {
stroke: #e60012;
stroke-width: 5;
}
/* 节点 */
.node {
fill: #fff;
stroke: #e60012;
stroke-width: 2;
cursor: pointer;
}
/* 右侧内容 */
.panel {
flex: 1;
max-width: 360px;
}
.content {
display: none;
}
.content.active {
display: block;
}
/* =====================
📱 手机端优化
===================== */
@media (max-width: 768px) {
.svg-business-wrap {
flex-direction: column;
}
.panel {
max-width: 100%;
margin-top: 20px;
}
.business-svg {
max-width: 100%;
}
}
.circle {
fill: none;
stroke: #ccc;
stroke-width: 3;
stroke-dasharray: 2000;
stroke-dashoffset: 2000;
animation: drawCircle 2s ease forwards;
}
@keyframes drawCircle {
to {
stroke-dashoffset: 0;
}
}
.circle-a {
animation-delay: 0s;
}
.circle-b {
animation-delay: 0.4s;
}
.circle-c {
animation-delay: 0.8s;
}
.circle {
fill: none;
stroke: #ccc;
stroke-width: 3;
}
画好图后,发现主圆有一处缺口

检查了viewBox、 circle,发现不是裁切的问题。
是动画参数错误
CSS是:
stroke-dasharray: 2000;
stroke-dashoffset: 2000;
但主圆真实周长 ≈ 2011(r = 320 2 × 3.1416 × 320 ≈ 2010.6)
所以画主圆时 dasharray 不够完整一圈,就会留下一段空白“缺口”。
→ 修改主题文件编辑器:function
<circle
class="circle circle-a"
cx="400"
cy="400"
r="320"
pathLength="1"
/>
CSS
.circle {
stroke-dasharray: 1;
stroke-dashoffset: 1;
animation: drawCircle 2s ease forwards;
}
直接把路径长度(pathLength)定义为1
画圆时自动把 1 当成完整周长
这样不用计算圆周长,修改半径也不受影响。


