ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

deck.gl Standalone 独立脚本版(Scripting API)设计与使用指南:无需构建工具、免 React 的原生 JavaScript 可视化方案

deck.gl Standalone 独立脚本版(Scripting API)设计与使用指南:无需构建工具、免 React 的原生 JavaScript 可视化方案 deck.gl Standalone 独立脚本版Scripting API设计与使用指南无需构建工具、免 React 的原生 JavaScript 可视化方案【免费下载链接】deck.glWebGL2 powered visualization framework项目地址: https://gitcode.com/GitHub_Trending/de/deck.gldeck.gl 的核心库与图层本身并不依赖 React但早期版本的官方示例与教程几乎全部围绕 React 生态展开。本文基于仓库中 v5.0 时期的 purejs-standalone RFC完整梳理Standalone 独立版的动机、API 设计、完整示例代码并结合当前仓库中已经落地的实现DeckGL脚本接口类、MapWrapper地图封装、deck.gl预打包 bundle进行源码级验证与扩充。读完本文你将掌握如何像使用 d3.js 一样通过一行script标签引入 deck.gl在 Codepen、JSFiddle、Observable 或任何普通 HTML 页面中直接构建带交互的地图可视化。一、RFC 背景为什么需要一个免构建的 deck.gl在 v5.0 时代deck.gl 的官方入门路径存在明显的门槛。RFC 中指出了三个核心痛点React 依赖成为阻碍可视化社区中相当大比例的开发者并不使用 React社区持续出现关于在 Vue、Angular、Polymer 等框架中使用 deck.gl 的咨询RFC 中引用了 issue #694、#576 以及第三方 Polymer 移植项目。工程链门槛过高并非所有潜在用户都熟悉包管理、打包工具和响应式编程范式。在官方工作坊中组织者不得不花费大量时间指导参与者安装 Node.js、安装 npm 包、排查版本不兼容问题并复制一份超过 50 行、附带相当吓人的 webpack 配置的 hello world 示例。创意编程群体的习惯几乎所有创意编程者都熟悉 d3.js 的使用模型——在 HTML 中引入一个 minified 版本再从示例中复制几行代码即可运行无需任何编译步骤。基于这些观察RFC 提出为 deck.gl 增加一种standalone独立脚本版本该版本预先打包所有依赖并封装掉视口控制器viewport controller的状态管理复杂度从而显著降低以下场景的使用门槛引导普通开发者用 deck.gl 快速原型分享代码片段与概念验证RFC 引用 PR #1171提交 issue 时附带最小复现RFC 引用 issue #1071。这一设计理念最终演变为今天官方文档中的Scripting API脚本接口其完整使用指南见 docs/get-started/using-standalone.md对应的 API 参考见 docs/api-reference/core/deckgl.md。二、提议的 API 形态两个全局对象DeckGL与LumaGLRFC 对 standalone 版本的接口做了如下设计The standalone version of deck.gl exposes two global objects:DeckGLandLumaGL.DeckGLcontains all exports fromdeck.gl/coreanddeck.gl/layers.LumaGLcontains all exports ofluma.gl.DeckGL聚合deck.gl/core核心框架与deck.gl/layers基础图层的所有导出LumaGL聚合luma.gldeck.gl 底层的 WebGL 渲染引擎的所有导出DeckGL同时是一个包装类wrapper class负责协调管理底图map、deck.gl canvas、视口控制器三者之间的共享状态。对照当前仓库的实现这一设计已经落地并有清晰的分工全局对象deck与luma以及loaders由 modules/core/bundle/index.ts 组装luma与loaders来自deck.gl/core/scripting/lumagl与loadersgldeck则导出deck.gl/core的全部内容并额外导出DeckGL脚本接口类luma.gl API 的重导出清单见 modules/core/src/scripting/lumagl.ts包括Device、Buffer、Texture、Framebuffer、Model、Geometry、ScenegraphNode等渲染底层对象以及createDevice、enforceWebGL2等设备创建工具最终面向用户的预打包 bundle由 modules/main/bundle.ts 统一汇总它在 core 基础上继续聚合deck.gl/layers、deck.gl/aggregation-layers、deck.gl/extensions、deck.gl/geo-layers、deck.gl/mesh-layers、deck.gl/mapbox、deck.gl/maplibre与deck.gl/widgets即一个script标签即可获得完整的 deck.gl 图层全家桶。实现细节从源码看luma、loaders与deck三个全局对象采用globalThis注入与Object.assign合并的方式暴露modules/core/bundle/index.ts并对已经存在的同名全局对象做了|| {}保护避免重复加载时相互覆盖。三、DeckGL包装类的核心职责RFC 将DeckGL定义为管理底图、deck.gl canvas 与视口控制器之间共享状态的包装类。在当前源码中这一职责落在 modules/core/src/scripting/deckgl.tsDeckGL extends Deck脚本接口类直接继承核心 Deck 类因此天然拥有 Deck 的全部能力图层渲染、拾取、事件、过渡动画等创建 canvascreateCanvas()在指定的container中动态创建两个 DOM 元素——底图容器div.mapCanvas与 deck.gl 的canvas.deckCanvas两者都使用position: absolute; left: 0; top: 0; width: 100%; height: 100%的样式实现叠层渲染若容器position为static会自动改为relative作为定位基准container支持传入 DOM 元素或元素 id 字符串底图自动发现const {map globalThis.mapboxgl || globalThis.maplibregl} props——默认从全局作用域查找mapboxgl或maplibregl找到即自动创建底图找不到则不渲染底图状态同步重写_drawLayers()在每一帧绘制图层前将当前视口this.getViewports()[0]的宽高与经纬度/缩放/倾角/方位角同步给底图实例保证 deck.gl 图层与底图严格对齐资源释放finalize()会先释放底图资源再调用父类的finalize()。此外注释明确说明该类刻意不通过包根目录导出index.ts以保持核心模块与底图厂商解耦只通过预构建的deck.glbundle 暴露。这正是standalone 版专属 API的定位。四、构造函数与属性详解RFC 给出的构造方式是const deckgl new DeckGL(props);props中除canvas、width、height外的所有Deck属性这三者由container属性接管控制外加视口控制器的全部属性通过controller属性传入。下面逐项展开 RFC 定义的核心属性并对照当前实现补充细节。4.1containerDOM Element可选deck.gl canvas 所挂载的容器canvas 会自动调整尺寸以填满容器。RFC 默认值document.body当前实现扩展同时支持DOM 元素或元素 id 字符串两种形式modules/core/src/scripting/deckgl.ts 中typeof container string时走document.getElementById查找若容器不存在会抛出Deck: container not found错误官方示例 examples/get-started/scripting/basic/index.html 中的用法container: container配合div idcontainer/div。4.2mapObject底图实例。RFC 的设计是By default, if the global variablemapboxglis found, attempt to create a mapbox-gl map.当前实现已将默认查找范围扩展为globalThis.mapboxgl || globalThis.maplibregl即Mapbox GL JS 与 MapLibre GL JS 二选一。若要使用自定义底图可传入一个包含setProps(props)与finalize()两个方法的对象将map设为null或false则完全禁用底图。使用 Mapbox 时RFC 要求先引入库与样式表script srchttps://api.tiles.mapbox.com/mapbox-gl-js/v0.44.1/mapbox-gl.js/script link hrefhttps://api.tiles.mapbox.com/mapbox-gl-js/v0.44.1/mapbox-gl.css relstylesheet /并设置 access tokenmapboxgl.accessToken mapbox_access_token;当前文档推荐的引入方式docs/get-started/using-standalone.mdscript srchttps://api.mapbox.com/mapbox-gl-js/v3.2.0/mapbox-gl.js/script link hrefhttps://api.mapbox.com/mapbox-gl-js/v3.2.0/mapbox-gl.css relstylesheet / !-- 或使用 MapLibre -- script srchttps://unpkg.com/maplibre-gl3.0.0/dist/maplibre-gl.js/script link hrefhttps://unpkg.com/maplibre-gl3.0.0/dist/maplibre-gl.css relstylesheet /这两个库的脚本会把mapboxgl/maplibregl挂到全局作用域从而被DeckGL自动发现。在 Observable 这类无法把库导入全局作用域的环境下则需要手动传入mapboxgl require(mapbox-gl^3.0.0/dist/mapbox-gl.js); // 或 maplibregl require(maplibre-gl^3.0.0/dist/maplibre-gl.js); new deck.DeckGL({ // ... map: mapboxgl // 或 maplibregl });4.3mapStyleString | Object底图样式可以是 Mapbox / MapLibre 的样式 JSON 或样式 URL。当前类型定义为string例如mapStyle: https://basemaps.cartocdn.com/gl/positron-nolabels-gl-style/style.json从 modules/core/src/scripting/map-wrapper.ts 的实现可以看到当setProps()检测到mapStyle变化时会调用this.map.setStyle(newProps.mapStyle)热更新底图样式。4.4controllerObject视口控制器实例。RFC 的设计By default, attempt to create a controller that works with the deck.gl viewport (MapControllerJSforWebMercatorViewport, orOrbitControllerJSforOrbitViewport).默认行为根据视口类型自动创建配套控制器——WebMercatorViewport经纬度地图使用MapControllerOrbitViewport轨道视角使用OrbitController自定义控制器需提供setProps(props)与finalize()两个方法并可通过调用props.onViewStateChange更新视口controller: null可关闭全部交互。在脚本接口中最简单的方式是直接传controller: true启用默认控制器见下文的完整示例。4.5 当前版本补充属性随着实现演进DeckGL脚本类在 docs/api-reference/core/deckgl.md 中新增了两个属性mapboxApiAccessTokenstringMapbox 瓦片服务的访问令牌会直接写入底图库的accessToken见 map-wrapper.ts 中mapLib.accessToken props.mapboxApiAccessToken || mapOptionsobject透传给mapboxgl.Map/maplibregl.Map构造函数的额外选项如自定义交互、控件等与 deck.gl 内部参数interactive: false、trackResize: false、maxZoom: 24等合并后生效。五、方法与生命周期RFC 为DeckGL定义了以下方法当前实现均已在 modules/core/src/scripting/deckgl.ts 及Deck基类中落实方法说明当前实现依据pickObject与Deck.pickObject相同根据屏幕坐标拾取单个对象继承自DeckpickObjects与Deck.pickObjects相同按范围批量拾取对象继承自DecksetProps更新 props若 props 中含mapStyle且存在底图会先同步底图样式再更新 deckdeckgl.ts 中setProps重写getMapboxMap返回底图库的 Map 实例mapboxgl.Map或maplibregl.Map源码中return this._map this._map.getMap()finalize释放全部资源先释放底图再释放 deck 渲染资源deckgl.ts 中finalize重写其中getMapboxMap让用户可以在DeckGL之外直接操作原生底图对象例如添加自定义控件、监听底图事件。MapWrapper.getMap()的实现见 modules/core/src/scripting/map-wrapper.ts。六、Hello World 完整示例6.1 RFC 原始示例ArcLayerRFC 要求以一行 script 标签引入预打包版本script srchttps://some.cdn.domain/deck.gl-5.1.0.min.js/script其配套的 hello world 示例旧版 API 形态new DeckGL为全局构造器图层挂在DeckGL.ArcLayer命名空间下const data [ { pickup: [-122.42, 37.8], dropoff: [-122.48, 37.76] }, { pickup: [-122.43, 37.8], dropoff: [-122.42, 37.75] } ]; const deckgl new DeckGL({ container: document.getElementById(container), longitude: -122.45, latitude: 37.8, zoom: 11, pitch: 30, layers: [ new DeckGL.ArcLayer({ data, getSourcePosition: d d.pickup, getTargetPosition: d d.dropoff, getSourceColor: d [255, 128, 0], getTargetColor: d [0, 128, 255], strokeWidth: 5 }) ] });这里演示了脚本版的三个关键特征无需 importDeckGL是全局对象、无需构建浏览器直接执行、无需手动管理控制器状态longitude/latitude/zoom/pitch直接作为顶层 props 传入。6.2 当前版本示例ScatterplotLayerMapbox随实现演进API 形态调整为deck.DeckGL官方 docs/api-reference/core/deckgl.md 给出的用法如下new deck.DeckGL({ mapStyle: https://basemaps.cartocdn.com/gl/positron-nolabels-gl-style/style.json, initialViewState: { longitude: -122.45, latitude: 37.8, zoom: 12 }, controller: true, layers: [ new deck.ScatterplotLayer({ data: [ {position: [-122.45, 37.8], color: [255, 0, 0], radius: 100} ], getColor: d d.color, getRadius: d d.radius }) ] });引入脚本的方式Mapbox 版script srchttps://unpkg.com/deck.gllatest/dist.min.js/script !-- 如需底图再引入以下两项 -- script srchttps://api.mapbox.com/mapbox-gl-js/v3.2.0/mapbox-gl.js/script link hrefhttps://api.mapbox.com/mapbox-gl-js/v3.2.0/mapbox-gl.css relstylesheet / !-- 让地图全屏渲染 -- style body { width: 100vw; height: 100vh; margin: 0; } /style使用 MapLibre 时仅需替换底图相关三行docs/get-started/using-standalone.mdscript srchttps://unpkg.com/deck.gllatest/dist.min.js/script script srchttps://unpkg.com/maplibre-gl3.0.0/dist/maplibre-gl.js/script link hrefhttps://unpkg.com/maplibre-gl3.0.0/dist/maplibre-gl.css relstylesheet /6.3 仓库内可运行的完整页面GeoJson Arc 混合示例仓库中 examples/get-started/scripting/basic/index.html 提供了一个可整页复制运行的实战示例它用两个deck.GeoJsonLayer渲染国家边界与机场点位含pickable、autoHighlight、onClick交互再用一个deck.ArcLayer从伦敦向各机场绘制连线完整展示了脚本版的多图层、数据变换与事件处理能力const deckgl new deck.DeckGL({ container: container, initialViewState: { latitude: 51.47, longitude: 0.45, zoom: 4, bearing: 0, pitch: 30 }, controller: true, layers: [ new deck.GeoJsonLayer({ id: base-map, data: COUNTRIES, stroked: true, filled: true, lineWidthMinPixels: 2, opacity: 0.4, getLineColor: [60, 60, 60], getFillColor: [200, 200, 200] }), new deck.GeoJsonLayer({ id: airports, data: AIR_PORTS, pickable: true, autoHighlight: true, onClick: info info.object alert(${info.object.properties.name} (${info.object.properties.abbrev})) // ...其余样式参数 }), new deck.ArcLayer({ id: arcs, data: AIR_PORTS, dataTransform: d d.features.filter(f f.properties.scalerank 4), getSourcePosition: f [-0.4531566, 51.4709959], // 伦敦 getTargetPosition: f f.geometry.coordinates, getSourceColor: [0, 128, 200], getTargetColor: [200, 0, 80], getWidth: 1 }) ] });从该示例可观察到脚本接口的典型用法所有类与常量统一从deck.命名空间读取container可传字符串 idinitialViewState controller: true即可获得完整的平移缩放旋转交互无需任何打包配置。七、源码视角底图与 deck 是如何对齐的RFC 将隐藏状态管理复杂度列为 standalone 版的核心价值之一。当前实现通过 modules/core/src/scripting/map-wrapper.ts 中的MapWrapper类完成了这一职责其关键机制值得深入了解无状态封装MapWrapper把 mapbox-gl / maplibre-gl 的Map封装成无状态组件只接受MapPropsmapLib、container、mapStyle、viewState、width、height等由DeckGL单向驱动状态差异检测_update()对比新旧 props分别处理三类变化——mapStyle变化触发setStyle()、宽高变化触发resize()、latitude/longitude/zoom/pitch/bearing任一变化触发jumpTo()尺寸劫持_initialize()中通过Object.defineProperty重写底图容器的offsetWidth/clientWidth/offsetHeight/clientHeight取值器消除调用resize()与 DOM 更新之间的时序问题强制同步渲染redraw()会主动取消底图调度中的动画帧并立即执行_render()规避requestAnimationFrame带来的图层与底图渲染不同步问题驱动循环DeckGL._drawLayers()在每帧将最新视口推给MapWrapperdeckgl.ts因此用户只需维护initialViewState控制器、动画与底图更新全部自动完成。正是这套机制让新手零状态管理成为可能——这与 RFC 提出的设计目标完全一致。八、RFC 遗留问题及其在仓库中的落地方案RFC 末尾列出了若干待决问题结合当前仓库可以确认大部分问题的演进方向RFC 问题现状以当前仓库为准只发布 CDN minified 版还是同时发布 npm 模块两者兼有deck.gl作为 npm 包发布见 modules/main/package.jsonmain指向dist/index.cjs、module指向dist/index.js同时通过dist.min.js对外提供预打包脚本经unpkg.com/deck.gllatest/dist.min.js这类 CDN 分发核心包每次更新是否自动发布新 standalone 版本从package.json的build-bundle脚本ocular-bundle ./bundle.ts与prepublishOnly钩子发布前自动重建 bundle看预打包 bundle 由发布流程自动构建DeckGL类与打包配置需移植进 monorepo已落地脚本类位于 modules/core/src/scripting/deckgl.ts打包入口为 modules/main/bundle.ts由 modules/main/package.json 的build-bundle脚本驱动为避免依赖 React图层模块需改为从deck.gl/dist/core导入当前架构已通过 monorepo 模块化彻底解决core 与各图层包均为独立包如deck.gl/layers、deck.gl/aggregation-layersReact 仅是可选 peerDependencypeerDependenciesMeta中标记为optionalbundle 汇总时不依赖 Reactdeck 与 luma 已有调试用全局对象是否整合现状为三者并存deckdeck.gl 全部导出 DeckGL、lumaluma.gl 渲染引擎导出见 modules/core/src/scripting/lumagl.ts、loadersloaders.gl 数据加载导出由 modules/core/bundle/index.ts 统一注入全局另外值得注意的工程细节H3HexagonLayer的 H3 库依赖在 standalone bundle 中不打包webpack externals 配置因此使用 H3 相关图层时需要在 deck.gl 脚本标签之前额外引入script srchttps://unpkg.com/h3-js^4.0.0/script这一约束在 modules/main/bundle.ts 的_checkH3Lib校验逻辑中有明确说明。九、适用场景与使用建议综合 RFC 动机与当前实现standalone 脚本版最适用的场景包括快速原型与教学无需初始化工程、无需 npm install打开 HTML 即可验证图层效果代码分享与 issue 复现几十行代码即可构造最小可复现示例非常适合 Codepen、JSFiddle 等在线环境非 React 技术栈项目可直接嵌入任意 HTML/JS 应用也可配合 Vue、Angular 等框架以命令式方式使用数据科学笔记本环境Observable 等环境可结合require()引入底图库后通过map属性显式传入。同时需要明确边界standalone 版面向免构建、快速上手而大型生产应用若需要 tree-shaking 减小包体积、类型安全TypeScript 定义与深度定制仍建议走模块化安装路线即直接使用deck.gl/core、deck.gl/layers等 npm 包并通过构建工具集成。两种方式共享同一套Deck核心渲染管线能力一致只是分发形态与集成深度不同。十、延伸阅读脚本接口完整用法docs/get-started/using-standalone.mdDeckGL脚本类 API 参考docs/api-reference/core/deckgl.md核心Deck类脚本版继承自它docs/api-reference/core/deck.md脚本接口实现源码modules/core/src/scripting/deckgl.ts、modules/core/src/scripting/map-wrapper.ts预打包 bundle 汇总入口modules/main/bundle.ts可运行的完整 HTML 示例examples/get-started/scripting/basic/index.html本文的提案源头dev-docs/RFCs/v5.0/purejs-standalone-rfc.md【免费下载链接】deck.glWebGL2 powered visualization framework项目地址: https://gitcode.com/GitHub_Trending/de/deck.gl创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表