跳到主要内容

共同线动画核心

已接通的 Rust 控制器、原子材质提交及当前脚本边界

共同线控制器已在 Rust 地图会话中接通,时间和样式曲线复用共享核心。它叠加显示流动、虚线、渐显、箭头、光晕和图片纹理,不把逐帧采样写回用户的图层样式或图源数据。图层面板、播放按钮及其布局由使用方实现。

本文保留 Rust 核心示例;当前共同脚本门面与双语完整 HTML 已接通,见共同线动画与样式曲线。sceneLinePlayback / sceneTracks 在匹配版本中为 true。

下面代码在当前核心仓库中使用 sqs_map::session::MapSession,它展示核心场景 JSON 通道,不代表已发布的 npm 接口或动态库发行包:

use serde_json::json;
use sqs_map::session::{MapSession, SessionError};

fn main() -> Result<(), SessionError> {
    let mut map = MapSession::new_headless(1, 256, 192)?;
    map.camera_call("jumpTo", &[json!({"center":[0,0],"zoom":12})])?;
    let owner = map.scene_call("create", &[json!({"id":"lines"})])?;
    let owner = json!({"id":owner["id"],"sceneInstanceId":owner["sceneInstanceId"]});
    let source = map.source_call(
        "addSource",
        &[
            json!("road"),
            json!({"type":"geojson","lineMetrics":true,
            "data":{"type":"LineString","coordinates":[[-0.003,0],[0.003,0]]}}),
        ],
    )?;
    let source = json!({"id":source["id"],"sourceInstanceId":source["sourceInstanceId"]});
    map.scene_call("attachSource", &[owner.clone(), source])?;
    map.layer_call(
        "addLayer",
        &[json!({"id":"road-line","type":"line","source":"road",
        "paint":{"line-color":"#ff0000","line-width":8}})],
    )?;
    // getLayer follows MapLibre and returns the style specification.
    // getLayers returns the small state snapshots that include instance identities.
    let layers = map.layer_call("getLayers", &[])?;
    let layer = &layers.as_array().unwrap()[0];
    let layer = json!({"id":layer["id"],"layerInstanceId":layer["layerInstanceId"]});
    let playback = map.scene_call(
        "animation.line",
        &[
            json!({"id":"flow","layer":layer,"timing":{"duration":3000,"loop":true},
            "effects":[{"type":"flow","spacing":0.3,"trailLength":0.2}],
            "tracks":{"widthScale":[{"offset":0,"value":1},{"offset":1,"value":2}]}}),
            json!({"owner":owner}),
        ],
    )?;
    map.scene_call("start", &[owner.clone()])?;
    let _rgba = map.render_rgba()?; // The host keeps rendering to advance playback.
    let identity = json!({"id":playback["id"],"playbackInstanceId":playback["playbackInstanceId"]});
    map.scene_call("playback.stop", &[identity])?;
    map.scene_call("remove", &[owner])?;
    Ok(())
}

目标必须是真实 line 图层,绑定已加载、非聚合、静态 GeoJSON 图源,并设置 lineMetrics:true;图源还须显式附着到所属场景。当前共同线仅接受二维线坐标,纬度绝对值不超过 85.0511287798066;三维坐标和超出范围的坐标明确拒绝。每层最多4096路径、十万个顶点,最多64个共同控制器;实际同时渲染最多32个线动画图层,总 GPU 预算256 MiB,还会检查像素单位的路径精度。

timing 使用 duration、delay(毫秒)、loop、direction(forward/reverse/alternate)、easing(linear/ease-in-out)和 fill(forwards/none)。tracks 支持 color、opacity、widthScale 曲线;每条曲线有2至32个严格递增的 offset,覆盖0到1。场景暂停和控制器手动暂停分别保存;暂停时 seek 到终点保持暂停,恢复并接受终点后完成。有限播放按 fill 保留最终叠加或恢复静态样式,循环播放不会自行完成。

纹理效果使用 {"type":"pattern","image":"已登记图片名称"},保存当前图片实例及修订,不把本地文件路径作为共同接口;当前不支持 SDF 线纹理。图层实例、图源数据/状态、样式或图片被外部修改后,旧控制器失败并保留新数据。移除控制器或所属场景恢复原静态样式,保留图源和图层;场景 stop 遵循场景隐藏规则。

显示计划先准备 CPU 几何、总预算和 GPU 候选,再发布状态;失败不推进控制器或发送虚假的完成事件。普通帧只更新相位及材质参数,不重建路径几何。实际 Linux 软件 Vulkan 检查已覆盖六种效果及组合、36帧、输出失败回滚和33层启动失败后保留全部草稿;移除一个控制器后32层启动通过。10项新增模型检查、16项路线回归、既有线生命周期和4项渲染检查通过。浏览器共同控制器、四宿主同脚本、GL 控制器、硬件、移动设备、外机和正式发行仍分别验收。

完整 Rust 示例源码可在核心仓库运行:cargo run --locked -p sqs-map --example managed_line_playback。