8.6 KiB
首页 GLOBAL PRESENCE 地图动画替换 — 设计文档
日期:2026-08-21 状态:已与用户确认(1:1 还原 demo)
轮播模式迭代:累积滑窗(2026-08-21 四次补充)
应用户要求,首页地图与 auto-export 地图的轮播从"独占切换"(同一时刻一个)改为累积滑窗:
- 每步激活下一个据点,已激活的保持显示
- 窗口满后(n-1=4 个),每次新激活时最旧的一个淡出(0.45s opacity 过渡)
- 稳态 = 同时显示 4 个:最新的播完整动画序列,最旧的渐隐离场
- 生命周期不变:可见才播 / 完全离开归零 / 每次进入从第一个完整累积
实现:main.js 两个地图块的 step()(tick % n 激活,tick ≥ n-1 时 (tick-(n-1)) % n 淡出);CSS 给 .location/.marker/.line 加 opacity 过渡。版本 bump ?v=20260821-6。
验证:两页 t0→t4 逐步累积至 4 个、t4 时首个淡出、t5 滑窗循环、离场归零、回来重播,全过。
丝滑包升级(2026-08-22)
应用户要求做动效升级,四项全部落地(两张地图统一):
- 弧线引线:首页 5 条折线
d改为三次贝塞尔曲线(水平出发→自然弯到点位),绘制缓动cubic-bezier(.3,.7,.2,1) - 退场反擦除:入场=animation(.active),退场=反向 animation(.out 类,main.js 的 exit() 添加、650ms 后移除):线倒收回(lineOut dashoffset 0→1)、圆点缩小(dotOut)、标签下滑淡出(labelOut)、光环衰减(haloOut)。⚠️ 不能用 transition 实现退场 — CSS 规范规定 animation 移除时的值跳变不触发 transition
- 重叠时序:label .28s@.02s / line .55s@.12s / dot .32s@.5s — 各元素交叉进场
- 呼吸 + 双涟漪:dot 落定后 CSS
r属性呼吸(breatheR 7.5→8.3px / ae-breatheS 5.5→6.3 / ae-breatheL 6→6.9,r与 transform 不冲突可同元素并存);每个点加第二圈光环/涟漪(halo2 / pulse.p2,延迟错开)
结构变化:子元素自管隐藏基态(group 不再切 opacity);HTML 每点 +1 光晕圆。版本 ?v=20260821-9。
验证注意:Playwright 窗口不可见时 Chrome 冻结动画时钟(currentTime 恒 0)— 动画类验证必须先 Page.bringToFront。带前台后实测退场淡出中间态(175ms 时 opacity 0.71)精确符合曲线。
目标
把 index.html 首页 GLOBAL PRESENCE 板块的静态占位地图(image/home/global-map.png)替换为 global-map-animation-demo.html 中的据点轮播动画效果,1:1 还原。
效果(以 demo 为准)
- 背景图:
image/home/Frame 119.png(1219 × 661) - SVG 覆盖层与背景图共享
viewBox="0 0 1219 661"坐标系,所有点/线/文字用原图坐标 - 5 个据点:DUBAI、ABU DHABI、ETHIOPIA、GHANA、RUSSIA
- 每个据点 = 白色标签 + 橙色(
--orange-700=#ff6a00)折线引线 + 圆点 + 脉冲光环 - 同一时刻只激活一个据点,每 3 秒切换下一个(循环)
- 动画序列:标签滑入(.35s)→ 引线绘制(.85s 延迟 .18s)→ 圆点弹出(.4s 延迟 1s)→ 光环脉冲(1.4s 无限循环)
- 含大屏首帧防闪烁修复:非 active 线
stroke-dasharray: 1; stroke-dashoffset: 1; opacity: 0
改动文件
| 文件 | 改动 |
|---|---|
index.html |
替换 .map-wrap 内部为 img.map-bg + svg.map-overlay(保留外层 reveal、aria-hidden、loading="lazy") |
css/style.css |
GLOBAL PRESENCE 段合入 demo 样式:.map-wrap 改 aspect-ratio: 1219/661,新增 .map-bg/.map-overlay/.location 系列 + 4 个 keyframes(颜色用 var(--orange-700));删除废弃 .map-img;删除 ≤560px 媒体查询里 .map-wrap { height: 260px }(与 aspect-ratio 冲突,比例自适应后手机端高度 ≈200px 与原设计一致) |
css/mobile.css |
.map-wrap 规则去掉写死 height: 200px,保留 margin |
js/main.js |
新增独立 IIFE:查 .map-overlay,.location 每 3s 轮播 active(选择器限定,不影响其他页面) |
刻意不做的(YAGNI)
- 不做全部常显模式(用户已确认单点轮播)
- 不移植 demo 里 vestigial 的
--path-lengthJS:CSS 从未读取该变量,pathLength="1"属性已完成路径长度归一化 - 不删旧图
global-map.png(可能被 WP 主题或其他地方引用) - 不加 demo 工具栏按钮(那是调试用的)
降级行为
prefers-reduced-motion:站点全局animation: none,当前据点显示标签+圆点(静止),引线保持未绘制 — 可接受- 无 JS:DUBAI 常显(HTML 里初始
active)— 可接受
防闪加固(2026-08-21 补充)
用户报告症状:大屏上到达地图时先闪一帧完整线路 → 重置 → 才正常播放。
根因(Playwright 取证确认):非 CSS 首帧竞态(demo 的 base-state 修复已移植且有效),而是状态机时序——轮播从页面加载就开始空转,加载 6s 后(地图仍在视口外 2380px 处)ABU DHABI 的引线已处于 fill: both 保持的完结状态(opacity 1 / dashoffset 0)。用户滚到时第一眼撞见这条"陈旧完结帧"(= 闪一下),3s 后下个 tick 归零重置(= 消失),下一个据点才从头播放(= 正常出现)。屏幕越大板块离首屏越近,越容易触发。
修复(js/main.js):
- init 时先
show(-1)清掉 HTML 里 DUBAI 的active(main.js 是 body 末尾同步脚本,先于首帧执行;无 JS 时保留 DUBAI 静态回退) - 首次激活用 IntersectionObserver 门控(观察
.map-wrap,threshold 0.12,与站点 reveal/count-up 同模式),触发后双 rAF 再show(0)——先让不可见 base 状态绘制一帧,动画永远从已沉淀的样式树起步 - 进入视口才开始 3s 轮播;无 IO 的老浏览器直接 begin()
防闪加固第二层:re-entry 重启 + 缓存击穿(2026-08-21 二次补充)
用户反馈"还是会出现"。系统排查后确认两条残余路径:
- re-entry 陈旧态:第一层修复只管"首次到达"。轮播一旦启动永不停 → 用户滚走再滚回时,当前据点又处于完结状态 → 闪 → 重置 → 下一个正常播放(症状与首次完全相同)。
- 旧版 main.js 缓存:python http.server 等无缓存头环境下,普通 F5 会命中启发式缓存执行旧 JS(Playwright 验证时实测踩中)。
修复:
- 轮播改为可见才播放的生命周期:IO 持续观察(threshold 0.12),
isIntersecting→start()(每次进入都从 DUBAI 从头播,双 rAF 起步);完全离开 →stop()(清定时器 + 归零到不可见 base 态)。首次到达、回访、F5 原位刷新(Chrome 恢复滚动位置)三种场景统一为"从 DUBAI 完整播放" start()内 rAF 等待期若已离开视口则放弃启动(守卫if (!timer) return)- index.html 脚本标签加版本号
main.js?v=20260821击穿缓存(今后 main.js 有实质改动时手动 bump)
验证(Playwright):
- 静置顶部不滚动:零激活、所有线 opacity 0
- 滚入 → DUBAI dashoffset 0.93(从 0 画起);3.3s 后 ABU DHABI
- 滚到页脚离开 7s:
active: null(轮播已停、已归零) - 滚回:DUBAI dashoffset 重现从 0 画起;3.3s 后 ABU DHABI —— re-entry 不再撞见完结帧
- 原位 reload(Chrome 恢复 scrollY=2309 地图在视口):t=135ms DUBAI 已干净启动,无闪帧;t=10.2s 轮到 GHANA,节奏精准
- 控制台 0 错误 0 警告
A/B 验证:
- 修复前:加载 6s 未滚入 → ABU DHABI 激活、线完整(陈旧完结帧)
- 修复后:加载 8s 未滚入 → 零激活、所有线 opacity 0
- 滚入 0.6s → DUBAI 从 dashoffset 0.83 开始绘制;3.1s → ABU DHABI;6.3s → ETHIOPIA,循环正常
- 控制台 0 错误 0 警告
相关:bento 业务格渐显重播(2026-08-21 三次补充)
用户要求 FOUR CORE BUSINESSES(STRONG RESOURCES, RELIABLE DELIVERY)板块的图片逐个渐显在每次进入视口时重播(原 reveal 一次即 unobserve)。
- index.html:5 个
.cell.reveal追加reveal-repeat标记类(仅此板块) - main.js reveal 观察器:带
reveal-repeat的元素不 unobserve,按isIntersecting切换.in— ≥12% 可见整组阶梯重播,完全离开归零;其余元素保持一次性 reveal - 脚本版本 bump 至
?v=20260821-2
验证:滚入 5/5 in → 滚走 0/5 → 滚回 5/5 重播;标题等一次性 reveal 不受影响;控制台 0 错误。
验证
- Playwright 打开 index.html:控制台无报错、3s 轮播切换、桌面/移动端尺寸比例正常