新闻详情

新闻详情

首页 / 资讯中心 / 详情

Remotion 地图解释器地图数据准备实战:用 prep-geo.mjs 从 GeoJSON 生成可逐帧驱动的河流、国境线与标签锚点数据

发布时间:2026/9/8 23:14:39来源:尧图网络
Remotion 地图解释器地图数据准备实战:用 prep-geo.mjs 从 GeoJSON 生成可逐帧驱动的河流、国境线与标签锚点数据
Remotion 地图解释器地图数据准备实战用 prep-geo.mjs 从 GeoJSON 生成可逐帧驱动的河流、国境线与标签锚点数据【免费下载链接】remotion Make videos programmatically with React项目地址: https://gitcode.com/GitHub_Trending/re/remotion本篇指南围绕 Remotion 仓库中 MapTiler 地图动画技术remotion-maps skill的地理数据预处理环节展开讲解地图解释器Map Explainer场景下基底图瘦身与prep-geo.mjs数据烘焙管线。你将掌握如何在地图load时清理底图的文字标注与内层行政边界、如何把一条完整的河流 GeoJSON 与多国国界多边形转换成语义确定的river-flow.json、borders.geojson与country-meta.json三类产物以及stop/anchor/border三个逐国字段各自的数学含义与调参旋钮最终服务于河水流动逐国点亮的确定性动画。为什么需要地理预处理而非运行时生成在 Remotion 中用 MapTiler 做地图解释器动画时画面里往往同时存在两种证据等级的要素底层是 MapTiler Planet 的矢量瓦片基底图河流、道路、边界、地名上层是本片独有的自定义地理证据被高亮的河流动画、按国家划片出现的国界与填充、POI 标签。瓦片数据天然被切割在各张 tile 中在渲染层不存在从源头流向入海口的全局有序线——这正是 map-data-sources.md 中反复强调的规则Do not treat a tiled line as one ordered path。如果一次语义起点→终点的线绘制、一次河到哪国哪国亮的触发序列、或一段必须完整呈现、不能因超出取景框被裁剪的国界线带有叙事含义就必须在渲染之前把地理数据离线烘焙成确定性几何。仓库中的 prep-geo.mjs 就是这条离线管线的实现其配套的调用者、时序模型与数据源决策分别在 TECHNIQUE.md、map-explainer-architecture.md 中。本文聚焦这份map-geo-prep.md关联文档带你逐段理解基底图清理与prep-geo.mjs的三个输出。基底图瘦身让你的地理成为主角MapTiler 基底图默认带有一整套图层。若把矢量要素国家填充、河流叠加其上而不做处理画面会充斥着地名、路名、次级行政边界等噪音。因此地图实例load之后第一步就是剥离杂讯。移除 symbol文字标注与内层行政边界文档给出的核心循环如下for (const l of m.getStyle().layers as any[]) if (l.type symbol || /other border/i.test(l.id)) m.removeLayer(l.id);l.type symbol会命中所有place/water/road 标签即 MapTiler labels 文字层将其整体移除。在 RiverReveal.tsx 的实际实现里这一步逻辑与这里的文档完全一致代码注释还补充了 MapTiler 基底图中内层行政边界层的典型命名Other border[ dash]admin_level 3–10。/other border/i用于移除州/省/县级的内层行政边界保留国家级与争议边界country disputed borders。文档特别提醒内层行政边界 layer ID 会随样式变化不同的 MapTiler style 可能有不同的命名例如带空格或dash后缀需要先m.getStyle().layers检查实际加载的样式再按需删除州/省/区县层级仅保留生产画面确实需要的那层上下文边界。import {AbsoluteFill, delayRender, useCurrentFrame} from remotion; // 地图实例只创建一次ref 守卫load 回调中清理杂讯后 // 才添加自定义 source/layer并在 map.once(idle) 后 continueRenderLogo 与版权控件的兜底隐藏MapTiler SDK 提供maptilerLogo: false与attributionControl: false构造参数但文档明确指出仅有这两个参数并不总够还应在组件内通过 CSS 兜底隐藏style { .maplibregl-ctrl-bottom-left, .maplibregl-ctrl-bottom-right, .maplibregl-ctrl-attrib, .maptiler-logo { display: none !important; } } /style为什么需要双保险底层是 MapLibre GL 引擎控制条与属性控件由引擎注入 DOM某些构建或自定义样式下仍会渲染出来。在逐帧截图的 Remotion 渲染中这些角落元素会污染画面因此文档建议用.maplibregl-ctrl-*与.maptiler-logo四个选择器做确定性隐藏。注意attributionControl的显示本身涉及 MapTiler 服务条款请在使用自有生产项目时自行核对授权约定仓库内示例未就该点给出合规建议实践时按你的协议执行。prep-geo.mjs一次运行产出三类数据脚本 prep-geo.mjs 的角色是从源地理数据烘焙组件消费的数据。它在CONFIG区块读取一条已路由好的河流GeoJSON 与每个国家一个多边形GeoJSON输出产物路径用途河流线out/river-flow.json拷贝到项目的src/geo/平滑的河流画线数据国界多边形out/borders.geojson拷贝到public/geo/经staticFile加载每个国家 polygon 被标记{country: name}同一 source 按国家 filter 出填充逐国元数据out/country-meta.json拷贝到src/geo/每国{ stop, anchor, border }三字段运行方式即脚本自述bun scripts/prep-geo.mjs或node见--help。仓库里assets/sample-data/country-meta.json与assets/sample-data/yarlung-flow.json就是这套输出的成品样例供直接对照阅读。前置条件河流必须是一条干净的 LineString脚本开头的注释是一道重要警告RIVER INPUT MUST BE ONE CLEAN LINESTRING, source → mouth … If your OSM river comes as many ways / braided channels, ROUTE it into a single line FIRST — a graph shortest-path from source node to mouth node. Do NOT greedily chain by nearest endpoint: it bounces between parallel channels.即OSM 等来源的辫状河braided river是大量并行小水道way如果贪心地就近端点串联轨迹会在平行河道之间来回弹跳得到一条锯齿状伪河流。正确做法是先做图上的最短路路由source 节点 → mouth 节点得到唯一一条从源头到入海口的有序主干线。这一路由步骤是脚本的前置条件不属于脚本本身。脚本只能消费features[0].geometry为单个LineString的输入。河流线简化剔末端跳跃 保形简化脚本对输入河线做两件事prep-geo.mjsconst havKm (a, b) { /* Haversine 公式返回两点间公里数 */ }; let end routed.length; while (end 2 havKm(routed[end - 2], routed[end - 1]) 15) end--; // 丢弃可能的末端跨辫跳跃 const flow turf.simplify(turf.lineString(routed.slice(0, end)), { tolerance: RIVER_SIMPLIFY_TOL, // 0.006 度更大 更简化 highQuality: true, }).geometry.coordinates;剔末端路由后的线在河口附近可能残留一段跨辫子的跳跃这里用 Haversine 距离循环检测若最后两点的直线距离超过 15 km判定为跳跃段并截掉。简化用 turfsimplify按度数容差RIVER_SIMPLIFY_TOL 0.006保形化简。文档解释为何必须做宽缩放级别下画线动画需要一条平滑的线不能用贝塞尔再拟合——在长河上如雅鲁藏布江会造成蜿蜒的过冲meander overshoot让描画抖出原河形。逐国数据stop / anchor / bordercountry-meta.json的每个国家生成{ stop, anchor, border }stop —— 国家何时被点亮文档定义沿着河流的顶点逐点走第一个落在某国境内的点用turf.booleanPointInPolygon判定其河长累积距离 ÷ 河流总长的弧长比例就是河水进入该国的时刻源头国COUNTRIES列表第一项 0。它驱动后续的触发时间COUNTRIES.forEach((c, i) { stops[c] i 0 ? 0 : 1; }); // 1 进入前的哨兵值 let acc 0; for (let i 0; i flow.length; i) { if (i 0) acc havKm(flow[i - 1], flow[i]); const frac acc / (flowKm || 1); const pt turf.point(flow[i]); for (const c of COUNTRIES) if (stops[c] 1 insideCountry(pt, c)) stops[c] frac; }在 map-explainer-architecture.md 的时序模型中stop被换算成触发秒数const trigger (c) RIVER_START META[c].stop * (RIVER_END - RIVER_START);即河水在[RIVER_START, RIVER_END]示例0.3s → 8.0s窗口内完成绘制某国的序列从trigger(c)开始执行。因此stop直接依赖河流几何本身——调河流形状/简化容差会让点亮时刻联动变化这是文末Tuning表格强调的一点。anchor —— 通过内点极求标签中心绝不用质心这是文档中技术含量最高的函数。目标把标签放在国家最内侧、离边界最远的点上。质心centroid会被拉到边界甚至外部例如 L 形、弧状国家严禁使用。仓库实现的是网格采样近似极内点pole of inaccessibilityconst pole (poly) { const bb turf.bbox(poly), edge turf.polygonToLine(poly), N 46; let best null, bestD -1; for (let i 0; i N; i) for (let j 0; j N; j) { const p turf.point([bb[0](bb[2]-bb[0])*i/N, bb[1](bb[3]-bb[1])*j/N]); if (!turf.booleanPointInPolygon(p, poly)) continue; const d turf.pointToLineDistance(p, edge); if (d bestD) { bestD d; best p.geometry.coordinates; } } return best; };算法要点取 polygon 的 bbox在 46×46 网格上采样N 46即 47×47 个点只有落在多边形内的点才参与booleanPointInPolygon对每个内点计算到边界polygonToLine后pointToLineDistance的距离保留距离最大的点。但还有一个叙事约束像中国、印度这样的大国其最大几何范围尤其是远离故事区域的远角凸出会让标签落在故事无关的边远地区。因此先做一步按故事区域 bbox 裁剪让大国标签居中在镜头真正关注的那一片const ANCHOR_BBOX { china:[82,27,96,32], india:[76,14,99,31], bangladesh:[86,20,93,27] }; // 故事区域 const NUDGE { china:[0,0.6], india:[-1.0,0], bangladesh:[0,-0.6] }; // 编导手调脚本中的完整流程是largestPolygon多国文件中取最大主多边形避免岛屿/飞地干扰→ 用ANCHOR_BBOX[name] || FRAME_BBOX做bboxClip得到故事区域片→ 在片内求极内点 → 再叠加一个很小的NUDGE经纬偏移const storyRegion biggestPoly(turf.bboxClip(poly, ANCHOR_BBOX[name] || FRAME_BBOX).geometry); const pole poleOfInaccessibility(storyRegion); const nudge NUDGE[name] || [0, 0]; countryMeta[name] { stop: stops[name], anchor: [pole[0] nudge[0], pole[1] nudge[1]], border: segs, };FRAME_BBOX [76, 14, 104, 33.5]是可见取景范围[W,S,E,N]仅作为未配置某国 story bbox 时的锚点回退。NUDGE里形如china: [0, 0.6]的偏移表示把中国标签从极内点向正北挪 0.6 个纬度避免被河流主脉或后续国名遮挡属于编导手调而非几何规则。有了anchor渲染侧每帧把经纬度投影为屏幕像素map.project(anchor)RiverReveal.tsx 与 CountryLabel.tsx 就是靠这个坐标用 HTML 叠加层放置国家名标签大写字名 短色条分隔线 上浮淡入动画pointerEvents: none。labels 每帧投影后存入 state 触发 React 重渲染但 effect 依赖排除labels避免自激循环。border —— 完整源几何绝不裁剪取景框文档给出了一条硬性纪律Preserve every exterior ring from the named country source. Never clip a country or bilateral border to the framed bbox and never discard an off-screen segment.即country-meta.json[country].border保存的是指定源文件中该国的全部外环exterior ring线段哪怕它们天然超出当前取景框。原因有两层语义画面叙事需要的国界可能是国与国之间的完整双边边界视图查询如querySourceFeatures会静默裁掉画面外的部分——这正是 map-data-sources.md 判据表里complete off-screen boundary matters要选自定义 GeoJSON 的理由渲染机制Renderer 会把这段MultiLineString按累积长度统一切片sliceBorder从而完整国界表现为一次计时的揭示动画不会因跨空隙而人为制造连接不虚构跨空隙的 join。const completeExteriorSegments (fc) { /* 遍历每个 feature 每个 polygon 的 polygon[0]外环*/ };同时borders.geojson是把每个国家源文件的 polygon 加上properties.country name标签后合并成一个 FeatureCollection。渲染侧为每个国家建fill-${c}fill 类型filter[, [get, country], c]与trail-${c}line 类型数据初始为空EMPTY供画线揭示使用——同一份borders.geojson源被 filter 出不同国家的填充参见 RiverReveal.tsx 的addSource(countries, …)与各fill-${c}图层。运行时如何消费这三类数据源码佐证把几何产物接到画面的是 RiverReveal.tsx其数据流正好闭环验证上文导入country-meta.json得到META导入yarlung-flow.json得河流顶点数组构造 turf line 并算lineKm预构建每国DRAW把每段外环转成 line、算逐段长度与累积长度cumtotal为总公里数——sliceBorder(d, fromKm, toKm)据此按累积长度对多段线做无跨空隙切片并输出MultiLineString逐帧河流按reveal秒 →interpolate 贝塞尔缓动Easing.bezier(0.645, 0.045, 0.355, 1)用lineSliceAlong截取[0, lineKm*reveal]写入riversource高亮电光头部另取最后 3% 段写入river-headsource头部完成reveal ≥ 0.999后在RIVER_END之后 0.5 秒内淡出逐国lt t - trigger(c)为该国的本地秒数先画边框恒定BORDER_S 2.5s时长文档强调用触发后的恒定时长而非 reveal 的一部分否则复杂/长边界会在几分之一秒内闪过再填充爆发FILL_S透明度过冲1.25×后回落到FILL_OPACITY最后标签上浮LABEL_S。动画全程由useCurrentFrame()/useVideoConfig()驱动配合delayRender/continueRender守卫初始化时delayRender直到map.once(idle)才continueRender每帧同样先delayRender、setData/setPaintProperty后等待once(idle)再continueRender并triggerRepaint()从而保证 Remotion 无头渲染拿到的是完整绘制帧。图层自下而上的结构与调色遵循 map-explainer-architecture.mdriver-glow电蓝#49C6FF、宽 11、透明度 0.32、blur 6→river-line冰核#E8F7FF、宽 3→river-headglowrgba(120,225,255,.95)、宽 16、blur 9→river-head纯白、宽 4.5。文档特别注明不加深色描边明亮的冰核自身就能压住任何填充底。国界则使用比该国填充色更深的色阶COUNTRY_DARK电光感在河上不在国界上。把 geo prep 调到新场景旋钮一览文档用一张表总结了为新的河流 / 新的国家组合调参时的全部旋钮这里结合脚本CONFIG区块逐一对应你想控制的对应旋钮位于 prep-geo.mjs CONFIG涉及哪些国家COUNTRIES数组有序源头国在首位第一项 stop 0 为每个国家提供name.geojson多边形源文件标签居中在正确的区域ANCHOR_BBOX[country]每国 story bbox[W,S,E,N]未配置时回退FRAME_BBOX微调某个标签NUDGE[country]经纬偏移量画哪条国界始终是命名源文件的完整几何绝不取可见范围——border字段每国何时点亮由stop推导依赖于河流几何与COUNTRIES顺序其他随场景要动的常量还包括RIVER_SIMPLIFY_TOL 0.006度数——河流画线的平滑度越大越简化FRAME_BBOX [76, 14, 104, 33.5]——可见取景范围仅用于锚点回退[W,S,E,N]输出路径OUT_RIVER/OUT_META/OUT_BORDERS源数据目录geo脚本假定techniques/maptiler/../geodata下按focus-rivers/与project-borders/组织输入运行时需按你的数据实际位置 ADAPT河流数据源RIVER、国界源BORDER(name)。运行后脚本会在控制台打印每条河的点数与公里数、每国 entry stop、锚点坐标与国界总公里数供验证并提示把产物拷贝到项目src/geo/与public/geo/。注意脚本自身只做读取源多边形因体量过大未随 skill 分发仓库仅随附assets/sample-data/输出成品运行它需要你自备并编辑输入路径。与渲染稳定性的衔接处理完地理数据后还有一条与prep-geo互补的纪律需要记住详细配方见 render-stability.md当镜头需要平移/缩放时不要逐帧调用map.jumpTo()——无头捕获中这会让 MapTiler 的 hillshade 与卫星影像发生逐帧重采样抖动这是渲染器问题不是数据/网络/标签问题。正确的固定底板fixed map plate模式是地图渲染器保持静态、超大容器按最大缩放级别渲染、逐帧用 CSStranslatescale平移画布并把同样的变换应用到每个投影标签。GeoJSON 数据与 paint 属性仍逐帧命令式更新——只有渲染器相机被冻结。这解释了为什么prep-geo烘焙出的anchor需要配合 plate 变换一起换算坐标RiverReveal.tsx 中map.project后乘plateScale再加plateX/plateY偏移。小结map-geo-prep.md描述了一条把原始地理转成动画可驱动数据的完整思路仓库中的 prep-geo.mjs 与 RiverReveal.tsx 为其落地样板。记住三条主线底图清理symbol 内层行政边界 Logo CSS 兜底让叙事地理浮出水面烘焙三产物有序河流线、带标签的国界多边形、逐国 stop/anchor/border把瓦片里不存在的全局顺序变成确定性几何极内点锚定 完整源边界 恒定时长序列让标签不悬空、国界不裁剪、长边界的揭示不闪瞬。把文末的调参表和脚本 CONFIG 对着读就能把同一套管线搬到任何河流逐国推进的新故事场景。【免费下载链接】remotion Make videos programmatically with React项目地址: https://gitcode.com/GitHub_Trending/re/remotion创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

rustc 错误码 E0424 深入解析:在无接收者的关联函数中误用 `self` 关键字 2026/9/8 23:50:43

rustc 错误码 E0424 深入解析:在无接收者的关联函数中误用 `self` 关键字

rustc 错误码 E0424 深入解析:在无接收者的关联函数中误用 self 关键字 【免费下载链接】rust Empowering everyone to build reliable and efficient software. 项目地址: https://gitcode.com/GitHub_Trending/ru/rust 本文围绕 rustc 官方错误码文档 E042…

阅读更多 →
Electron 最近文档(Recent Documents)实战指南:接入 Windows JumpList 与 macOS Dock 菜单 2026/9/8 23:50:43

Electron 最近文档(Recent Documents)实战指南:接入 Windows JumpList 与 macOS Dock 菜单

Electron 最近文档(Recent Documents)实战指南:接入 Windows JumpList 与 macOS Dock 菜单 【免费下载链接】electron :electron: Build cross-platform desktop apps with JavaScript, HTML, and CSS 项目地址: https://gitcode.com/GitHu…

阅读更多 →
RuView archive/v1 弃用指南:从纯 Python DensePoseHead 到 Rust v2 工作区的迁移路线与确定性证明解读 2026/9/8 23:50:43

RuView archive/v1 弃用指南:从纯 Python DensePoseHead 到 Rust v2 工作区的迁移路线与确定性证明解读

RuView archive/v1 弃用指南:从纯 Python DensePoseHead 到 Rust v2 工作区的迁移路线与确定性证明解读 【免费下载链接】RuView π RuView turns commodity WiFi signals into real-time spatial intelligence, vital sign monitoring, and presence detection — …

阅读更多 →
Java小型档案管理系统实验:从分层设计到文件持久化实现 2026/9/8 23:50:43

Java小型档案管理系统实验:从分层设计到文件持久化实现

简介:这是一份面向Java课程设计或综合实训的完整项目源码包,围绕C/S架构实现小型档案管理系统,适合正在完成实验设计、需要参考Socket通信与多线程并发处理方案的高校学生。资源共47个文件,包含14个Java源文件、15个已编译class文…

阅读更多 →
XL5301 dToF传感器深度解析:宽电压、低功耗、高稳定性实战指南 2026/9/8 23:50:43

XL5301 dToF传感器深度解析:宽电压、低功耗、高稳定性实战指南

1. 项目概述:为什么XL5301一出来,我就立刻拆了三颗样片上电测试TOF传感器这个圈子其实很小,老玩家基本都用过XL5300——它在2020年前后是国产dToF方案里少有的能稳定做到2.5米10%反射率、功耗压到8mA10Hz的型号,被大量用在扫地机避…

阅读更多 →
res-downloader:一步下载解密 2026/9/8 23:47:43

res-downloader:一步下载解密

res-downloader:一步下载解密 【免费下载链接】res-downloader 视频号、小程序、抖音、快手、小红书、直播流、m3u8、酷狗、QQ音乐等常见网络资源下载! 项目地址: https://gitcode.com/GitHub_Trending/re/res-downloader 微信视频号里的视频,存下…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞