轨迹播放
SqsMap 的路线播放现在由地图核心持有。网页主线程、严格 Worker、桌面脚本和独立动态库 QuickJS 使用相同的 map.sqs.animations.route / map.sqs.playbacks 入口。底图、图源与图层继续使用 MapLibre 风格的 addSource、getSource、addLayer;路线播放是 SqsMap 扩展。scenePlayback、sceneRoutePlayback 为 true;共同线动画与样式曲线已接通,sceneLinePlayback、sceneTracks 为 true。
可复制的脚本
// @gis-api 0.5-session
// @permissions ["project.read", "map.write"]
import { map } from 'sqsmap';
map.addSource('path', { type: 'geojson', data: {
type: 'LineString', coordinates: [[116.39, 39.90], [116.41, 39.90]]
}});
map.addSource('vehicle', { type: 'geojson', data: {
type: 'Point', coordinates: [116.39, 39.90]
}});
map.addLayer({ id: 'vehicle', type: 'circle', source: 'vehicle',
paint: { 'circle-color': '#e24d42', 'circle-radius': 8 } });
const scene = await map.sqs.scenes.create({ id: 'trip' });
const source = await map.getSource('path');
const target = await map.getSource('vehicle');
await scene.attachSource(target);
const playback = await map.sqs.animations.route({
id: 'drive', source, target, duration: 6000
}, { owner: scene });
const subscription = map.on('sqs.playbackchange', event => {
console.log(event.reason, event.playback.state, event.playback.position);
});
await scene.start();
const completed = await playback.finished();
console.log(completed.position);
subscription.unsubscribe();
脚本需要真实持续会话来等待尚未完成的播放。桌面与网页脚本宿主提供持续会话。独立动态库须调用 sqsm_map_script_session_start 并持续 sqsm_map_script_session_pump_json,同时轮询公开地图事件;一次性 sqsm_map_script_run_json 的待完成等待明确返回 CAPABILITY_UNAVAILABLE,已完成轮次可立即读取。独立宿主也可直接使用 C JSON 控制器并轮询状态。
完整 HTML/CSS/JavaScript 示例包含地图初始化、图层样式以及播放、暂停、停止、拖动进度条的全部点击事件。将文件保存为 HTML 可引用官网公开 SDK;在自己的站点部署 SDK 时修改加载地址。示例仅使用自行构造数据,来源标注为 Synthetic example data。
控制与等待
map.sqs.playbacks.get(id) 返回绑定实例的句柄,list() 返回不可变快照,remove(playback) 释放控制器。句柄提供 getState()、play()、pause()、stop()、seek(timeMs)、finished()。纯查询观察上次提交,不推进动画、不增加写入水位。finished() 表示终点的目标数据及显示缓存已接受;需要呈现帧再使用 map.sqs.flush({ render: true })。
场景草稿中的播放为 ready,准备不改变目标坐标;快照 position 表示轨迹在 positionMs 的准备位置。start/resume 启动 ready 播放;场景暂停冻结最后位置,恢复不补播暂停时间。手动暂停独立于场景暂停,场景恢复不会自动恢复手动暂停。播放 stop 取消当前等待,在仍运行的场景内 play 可重播并更换 epoch;旧轮次等待取消。无限 loop 永不自然完成,等待通过停止、失败、移除或销毁结束。
场景 stop 取消未完成播放并隐藏所附着目标,保留已完成有限轮次的成功状态。共同场景停止后不能重启;重新播放应创建新的场景或在仍运行的场景中重播。场景 remove 释放控制器但保留显式图源,遵循既有静态图源解除归属后的显示行为。脚本退出不删除地图持有的控制器;地图销毁清理等待和资源。
数据、坐标和限制
source 必须是已加载、静态、非聚合的一个 LineString;target 是一个 Point。可使用几何、Feature 或仅含一个 Feature 的 FeatureCollection;两者均使用当前 {id, sourceInstanceId} 身份或 getSource 句柄。target 必须先附着到同一 owner;每目标最多一个控制器,移除旧控制器后方可重新准备。多条线、多点、三维轨迹和极区输入明确拒绝。
duration 与 offsets 互斥,单位毫秒。duration 默认5000,支持1至86400000,按 Web Mercator 平面距离分配时间;offsets 为每个顶点的严格递增时间,首值为0,保留重复点的停留。delay 为启动延迟。输入经纬度采用 WGS84,纬度限制±85.0511287798066。日期变更线使用相邻顶点短路径,位置保留展开后的经度,例如179到−179经过180并到181。图源经度允许显式世界副本(绝对值≤1000000度),不会静默换成其他世界;与共享 project/unproject 一致。headingRadians 使用共享平面轨迹的方向计算,保持停留与转角规则。
每地图最多64控制器,每场景128资源包含静态源、接收器及控制器;最多100000轨迹点,控制/列表/事件 JSON 为64KiB,历史事件最多128。finished 也受宿主订阅和等待预算限制。身份重建后旧句柄返回 STALE_HANDLE。准备时捕获图源实例与数据修订;用户更新或删除图源、修改目标归属后,下一次采样或控制使旧播放失败,保留用户的新数据。
目标几何、全部显示缓存和对外输出成功准备后才一起提交。输出、资源预算或缓存失败不发布候选位置或完成;事件压力要求宿主先消费事件,资源压力可重试。sqs.playbackchange 提供准备、控制、完成、失败及归属变更的有界历史快照,不逐帧发送该事件;连续位置通过 getState 与 sourcedata 观察。
动态库与验收
C 沿用 sqsm_map_scene_json 的 {method,args} 通道:animation.route、playback.get/list/getState/play/pause/stop/seek/remove,使用 {id,playbackInstanceId} 身份;无需新导出函数。头文件、原生 JavaScript 声明和完整地图持有 Rust 渲染例子与官网 SDK 来自同一核心提交。
原生容量检查已验证64控制器同时完成并产生128个离散事件,内部推进不增加写入水位。组控制也受宿主事件预算限制;先运行空场景再逐项准备,可避免大量初始事件一起产生。当前环境记录原生软件 Vulkan 的18个实际帧,涵盖二维及日期变更线的准备、移动、暂停、完成、隐藏和移除;同一脚本通过动态库保留 QuickJS 与桌面实际 ScriptService/MapView。网页主线程与严格 Worker 分别通过31项同脚本检查,另有68项浏览器检查及28个实际帧。移动设备宿主、Windows/macOS外机、真实显卡与正式发行仍需独立验收。
播放已移除时,尚未完成的 finished 等待以 CANCELLED 结束;直接查询或控制旧句柄仍为 STALE_HANDLE。暂停时 seek 到终点仍保持暂停,恢复播放后确认完成。延迟和顶点时间均不超过一天。
播放过程中,外部编辑输入或目标数据会以 CONFLICT 结束当前播放,保留用户的新数据;RESOURCE_LIMIT 表示资源或通知预算超限,不发布部分结果。
共同脚本验证输入可在支持相同能力的脚本宿主运行;完整 HTML 在 pagehide 时解除监听并销毁地图。