npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@3clear/basegis

v0.1.9

Published

BaseGIS map engine adapter and GIS layer utilities.

Readme

@3clear/basegis

@3clear/basegis 是 3clear 一张图项目抽出的 GIS 能力包,通过统一入口 BaseGIS 封装 Cesium / Leaflet 常用 API。业务页面可复用同一套地图逻辑,复杂图层通过 methods 控制器组合公共方法;三维专有能力的支持范围见能力支持说明。

当前包包含:

  • BaseGIS:初始化、引擎切换、视角与底图、地图截图导出、基础图形、Canvas 图标与扩散 Marker、GeoJSON、DEM、点击事件,以及统一风场、源解析传输、GPU 风场、三维体与剖面。
  • methods:多地图实时视角联动、独立线图层、台风路径、图片图层、网格图层、海量点、点位聚合、点位抽稀、等值线、风场等高级控制器。
  • layers:天地图、GeoServer 金字塔瓦片、WMS、WMTS 图层配置快捷构造器。
  • assets:站点、工厂、信息标记和台风中心 SVG 资源。
  • style.css:BaseGIS 自有图层、标注和截图框选样式,不内嵌 Leaflet 官方 CSS。

能力总览

以下按类型展示 @3clear/basegis 的主要业务能力;工具型辅助函数不单独作为能力卡展示。点击名称可跳转到下方详细说明,完整导入方式见出口。

快速开始

地图工具(2)

通用点位图层(5)

行政区划边界图层(1)

轨迹路径图层(2)

格点填色图层(2)

等值线图层(2)

三维渲染(不支持2维)

风场图层(2)

影像瓦片图层(4)

Assets 示例资源(4)

安装

npm install @3clear/basegis leaflet axios

d3-contour、pixi.js、leaflet-pixi-overlay 和 html2canvas 已随 BaseGIS 构建产物发布,业务项目不需要单独安装。其中 Pixi 相关代码只在首次使用 Leaflet 海量点能力时按需加载,html2canvas 只在首次调用 Leaflet 截图时按需加载。

在应用入口引入 BaseGIS 与自有样式:

import { BaseGIS } from '@3clear/basegis'
import '@3clear/basegis/style.css'

外部依赖版本以 package.json 为准:当前为 leaflet ^1.9.4、axios ^1.15.1。

当前限制:完整 BaseGIS 入口中的剖面工具仍在模块加载时访问 Cesium.Cartesian3,因此即使只创建 Leaflet 地图,也需在导入 BaseGIS 前加载下文的 Cesium 脚本,否则会报 Cesium is not defined。这是既有的引擎依赖问题,与本次 Leaflet CSS 共用处理无关;纯原生 Leaflet 不受此限制。

Leaflet JS 和 leaflet/dist/leaflet.css 都由宿主依赖提供。BaseGIS 保留对官方 CSS 的导入,因此上面的原有用法仍然有效;官方规则不再另行内嵌到包的 style.css 中。

如果项目同时使用原生 Leaflet,可以在应用入口统一引入:

import L from 'leaflet'
import 'leaflet/dist/leaflet.css'
import { BaseGIS } from '@3clear/basegis'
import '@3clear/basegis/style.css'

确保 BaseGIS 与业务代码解析到同一份安装的 Leaflet,宿主构建器即可复用同路径的 JS / CSS。不同地图使用各自容器;不需要挂载 window.L 或注册 Vue 插件,其他模块需要使用 L / BaseGIS 时仍按需 import。纯原生页面若不导入 BaseGIS JS,必须自行引入 leaflet/dist/leaflet.css,仅引入包的 style.css 不包含官方规则。

Cesium 不随 npm 包发布。使用 Cesium 时,宿主项目需自行加载 Cesium.js 和 Widgets/widgets.css,并保留 Workers、Assets 等完整静态目录;初始化前必须能访问 window.Cesium。config.engine.cesium.scriptUrl/cssUrl 不会自动注入脚本和样式。

例如,将完整 Cesium 资源放入 public/lib/Cesium 后,在 Vite 的 index.html 中、应用入口脚本之前添加:

<script>window.CESIUM_BASE_URL = '%BASE_URL%lib/Cesium/'</script>
<link rel="stylesheet" href="%BASE_URL%lib/Cesium/Widgets/widgets.css">
<script src="%BASE_URL%lib/Cesium/Cesium.js"></script>

使用 GeoTIFF 数据时,宿主还需提前提供 window.GeoTIFF。本文 /data/...、/mock/... 均为示例数据地址,不包含在 npm 包中,请替换为项目真实地址;部署在子路径时,应结合宿主的 import.meta.env.BASE_URL 生成静态资源 URL。

出口

// 主入口
import { BaseGIS } from '@3clear/basegis'

// 高级能力控制器
import {
  LineLayerController,
  MapViewLinkController,
  TyphoonPathController,
  ImageLayerController,
  toImageLayerArea,
  GridLayerController,
  PointLargeLayerController,
  PointClusterController,
  PointDensityController,
  ContourLayerController,
  RasterContourController,
  WindFieldMethods,
} from '@3clear/basegis/methods'

// 图层配置构造器
import {
  createTiandituLayer,
  createTiandituTileSource,
  createGeoserverPyramidLayer,
  createWmsLayer,
  createWmtsLayer,
} from '@3clear/basegis/layers'

// 示例资源
import {
  gisMarkerSample,
  gisFactoryMarker,
  gisInfoMarker,
  typhoonPathIcon,
} from '@3clear/basegis/assets'

快速开始

<template>
  <div id="map" class="map"></div>
</template>

<script setup>
import { onBeforeUnmount, onMounted } from 'vue'
import { BaseGIS } from '@3clear/basegis'
import '@3clear/basegis/style.css'

let mapCore = null

onMounted(() => {
  mapCore = new BaseGIS({
    // 可选 cesium / leaflet。不传时使用默认配置 active: 'cesium'。
    engineType: 'cesium',
    // 也可以传 container: HTMLElement。
    containerId: 'map',
    config: {
      // 地图 / 底图投影与无元数据栅格默认源投影分开配置。
      crs: 'EPSG:3857',
      sourceProjectionCrs: 'EPSG:3857',
      view: {
        // 可选 2d / 2.5d / 3d。
        defaultSceneMode: '3d',
        initialView: {
          center: [104, 35],
          // Cesium 使用 height,Leaflet 使用 zoom。
          height: 5000000,
          zoom: 5,
          // Cesium 默认保持垂直俯视。
          pitch: -90,
        },
      },
      basemap: {
        // 默认内置值:tianditu-imagery。
        defaultVisibleId: 'tianditu-imagery',
      },
    },
  })

  const result = mapCore.init()
  if (!result.success) {
    console.warn(result.message)
  }
})

onBeforeUnmount(() => {
  mapCore?.destroy()
})
</script>

<style scoped lang="scss">
.map {
  width: 100%;
  height: 100vh;
}
</style>

以下 API 示例默认 mapCore 已初始化成功;示例中的业务数据、图片和服务地址需由页面准备。组件卸载时先销毁控制器、移除页面监听,再调用 mapCore.destroy()。

返回值约定

操作方法通常返回统一结果对象;图片、GeoJSON、风场等异步加载方法应使用 await:

{
  success: true,
  message: 'operation message',
  data: {}
}

失败时:

{
  success: false,
  message: 'error message',
  code: 'NOT_INITIALIZED'
}

getEngineType()、getConfig()、getMapInstance() 等读取方法直接返回值;createMarkerIcon() 直接返回图标参数或 null。控制器的 getState() 也返回状态对象,不能一律按 result.data 读取。

地图初始化与运行时配置

BaseGIS 的初始化参数分为两类:需要长期保留的默认配置放在构造函数的 config 中;只想覆盖本次初始化时,传给 init(options)。地图已经创建后,setConfig() 只更新实例保存的配置,不会直接改变当前画面;初始化默认值通常需要重新 init() 才会生效。

| 配置入口 | 适用场景 | 是否写入运行时配置 | 是否立即重建地图 | | --- | --- | --- | --- | | new BaseGIS({ ... }) | 创建实例并设置默认引擎、容器和整套配置。 | 是 | 否,仍需调用 init()。 | | init(options) | 创建或重新创建地图,并单次覆盖容器、引擎、CRS、场景模式或初始视角。 | engineType 会写入;crs / sceneMode / initialView 不写入。 | 是 | | setConfig(config) | 修改实例保存的配置,供后续初始化或配置查询使用。 | 是 | 否 |

构造参数

const mapCore = new BaseGIS({
  engineType: 'cesium',
  containerId: 'map',
  config: {
    crs: 'EPSG:3857',
    sourceProjectionCrs: 'EPSG:3857',
    view: {
      defaultSceneMode: '3d',
      initialView: {
        center: [104, 35],
        height: 5000000,
        zoom: 5,
        heading: 0,
        pitch: -90,
        roll: 0,
      },
    },
  },
})

| 参数 | 类型 | 默认值 | 说明 | | --- | --- | --- | --- | | engineType | 'cesium' \| 'leaflet' | config.engine.active,内置为 cesium | 默认引擎。该参数最终覆盖 config.engine.active。 | | container | HTMLElement \| string | - | 地图容器 DOM,也兼容传容器 id 字符串。 | | containerId | string | - | 地图容器 id。与 container 二选一即可。 | | config | Object | 内置配置 | 推荐的配置入口,与内置配置做深合并。 | | crs / sourceProjectionCrs | string | 见下文 | 分别表示地图 / 底图投影和无元数据栅格的默认源投影,支持 EPSG:4326 / EPSG:3857。 | | engine / view / basemap / dem / sourceTransport | Object | - | 兼容直接写在构造参数顶层;crs / sourceProjectionCrs 也可如此传入。推荐统一放入 config,同名时 config 中的值优先。 |

init(options) 参数与优先级

const result = mapCore.init({
  // 都是选填;构造时已经设置过的内容不需要重复传。
  containerId: 'map',
  engineType: 'cesium',
  crs: 'EPSG:3857',
  sceneMode: '3d',
  initialView: {
    center: [104, 35],
    height: 5000000,
    zoom: 5,
    pitch: -90,
  },
})

if (!result.success) {
  console.warn(result.message)
}

| 参数 | 类型 | 说明 | | --- | --- | --- | | container | HTMLElement \| string | 本次使用的容器 DOM 或容器 id,优先级最高。 | | containerId | string | 本次使用的容器 id。 | | engineType | 'cesium' \| 'leaflet' | 本次使用的引擎,同时更新实例保存的 engine.active。 | | crs | 'EPSG:4326' \| 'EPSG:3857' | 本次创建地图使用的 CRS;只覆盖本次初始化,不写回 config.crs。 | | sceneMode | '2d' \| '2.5d' \| '3d' | 本次初始化的场景模式;Leaflet 只支持 2d。不会写回 config.view.defaultSceneMode。 | | initialView | Object | 本次初始化的视角。不会写回 config.view.initialView。 |

init({ config: ... }) 不是有效写法;init() 不会合并 config。持久配置必须在构造函数中传入,或先调用 setConfig()。

各参数的实际取值顺序如下,左侧优先级更高:

| 项目 | 取值优先级 | | --- | --- | | 容器 | init.container → init.containerId → 构造函数 container → 构造函数 containerId | | 引擎 | init.engineType → 实例当前引擎(由构造函数 engineType 或 config.engine.active 得到)→ cesium | | 地图 CRS | init.crs → config.crs → 旧版引擎默认(Leaflet EPSG:4326,Cesium EPSG:3857) | | 场景模式 | Cesium:init.sceneMode → config.view.defaultSceneMode → 3d;Leaflet 始终为 2d | | 初始视角 | init.initialView → config.view.initialView → 引擎内置安全视角 |

重复调用 init() 时会先销毁旧 adapter,再创建新地图;BaseGIS 托管图层会异步恢复。init() 本身同步返回初始化结果,后续逻辑依赖图层恢复时还需等待:

const result = mapCore.init()
if (result.success) {
  const restore = await mapCore.whenReady()
  console.log(restore.restored, restore.failed)
}

完整配置分组

config 顶层包含两个 CRS 值和以下五个配置分组。页面不要直接依赖包内部的 src/gis/config 文件;需要查看当前实例最终合并后的配置时,使用 mapCore.getConfig()。

| 配置项 / 组 | 用途 | 主要生效时机 | | --- | --- | --- | | crs | 地图平面投影与底图瓦片矩阵。 | init() / 重新 init() | | sourceProjectionCrs | 无 CRS 元数据栅格的默认源投影。 | 后续创建或更新栅格图层时 | | engine | 默认引擎、引擎接入元数据及 Cesium 渲染质量。 | init() / 重新 init() | | view | 默认场景模式和初始视角。 | init() / 重新 init() | | basemap | 初始底图、可切换底图列表及内置服务元数据。 | init();列表也供 setBasemapById() 查询 | | dem | Cesium 默认地形及可切换地形列表。 | Cesium init();列表也供 loadDEMById() 查询 | | sourceTransport | 源解析传输图层的实例级默认视觉参数。 | 创建 adapter 时锁定;setConfig() 后需重新 init(),新 adapter 创建图层时才会读取 |

crs 与 sourceProjectionCrs

| 配置项 | 内置默认值 | 说明 | | --- | --- | --- | | crs | '' | 地图平面和底图瓦片矩阵;空值保留旧版引擎默认,Leaflet 为 EPSG:4326,Cesium 为 EPSG:3857。 | | sourceProjectionCrs | 'EPSG:4326' | PNG / JPG / 灰度图 / 数值网格不携带 CRS 元数据时的默认源投影。 |

两个值独立:修改底图 crs 不会重新解释栅格数据,修改 sourceProjectionCrs 也不会改变底图矩阵。area、视角以及点线面业务坐标始终使用 WGS84 经纬度。Cesium 中 crs 控制 2D / Columbus 平面投影和内置底图矩阵,不改变 3D 地球的 WGS84 坐标。

栅格源投影的取值顺序是:单个数据源的 sourceProjectionCrs(兼容旧名 sourceProjection)→ GeoTIFF 可识别 GeoKey → BaseGIS sourceProjectionCrs → 内置 EPSG:4326。GeoTIFF 已声明但当前不支持的 CRS 会返回错误,不会被全局默认值覆盖。修改 crs 后必须重新 init();修改 sourceProjectionCrs 只影响之后新建或重新加载且没有显式投影的栅格,不会自动重解释已加载数据。

engine 引擎配置

| 配置项 | 内置默认值 | 说明 | | --- | --- | --- | | engine.active | 'cesium' | 默认引擎;构造参数 engineType 或 init({ engineType }) 的优先级更高。 | | engine.cesium.sourceType | 'local-script' | Cesium 接入方式说明字段。 | | engine.cesium.scriptUrl | '/lib/Cesium/Cesium.js' | Cesium 脚本地址说明字段;BaseGIS 不会自动加载该脚本。 | | engine.cesium.cssUrl | '/lib/Cesium/Widgets/widgets.css' | Cesium 样式地址说明字段;BaseGIS 不会自动加载该样式。 | | engine.cesium.renderQuality.maximumDevicePixelRatio | 2 | Cesium 最大设备像素比,实际值限制在 1~3;越高越清晰,也越耗 GPU。 | | engine.cesium.renderQuality.fxaa | true | 是否启用 Cesium FXAA。 | | engine.cesium.renderQuality.msaaSamples | 4 | Cesium MSAA 采样数,取整并限制在 1~8。 | | engine.leaflet.sourceType | 'npm' | Leaflet 接入方式说明字段。 | | engine.leaflet.packageName | 'leaflet' | Leaflet 依赖包名说明字段。 |

scriptUrl / cssUrl 只是接入元数据。Cesium 资源的实际加载方法见安装。渲染质量在创建 Cesium Viewer 时读取,修改后需要重新 init()。

view 视角配置

| 配置项 | 内置默认值 | Cesium | Leaflet | 说明 | | --- | --- | --- | --- | --- | | view.defaultSceneMode | '3d' | 使用 | 只接受 2d | 默认场景,可选 2d / 2.5d / 3d。 | | view.initialView.center | [121.4737, 31.2304] | 使用 | 使用 | [经度, 纬度]。 | | view.initialView.height | 1800000 | 使用 | 忽略 | Cesium 相机高度,单位米。 | | view.initialView.zoom | 7 | 忽略 | 使用 | Leaflet 缩放级别。 | | view.initialView.heading | 0 | 使用 | 忽略 | Cesium 航向角,单位度。 | | view.initialView.pitch | -90 | 使用 | 忽略 | Cesium 俯仰角,单位度;-90 表示垂直俯视。 | | view.initialView.roll | 0 | 使用 | 忽略 | Cesium 翻滚角,单位度。 |

basemap 底图配置

| 配置项 | 内置默认值 | 说明 | | --- | --- | --- | | basemap.defaultVisibleId | 'tianditu-imagery' | 初始化时从 basemap.list 选择的底图 id。 | | basemap.defaultAnnotationId | 'tianditu-vector-label' | 当前为保留字段,初始化流程尚未读取;注记应通过所选底图项的 annotationResourceKey 配置,天地图也会按底图资源自动推断注记。 | | basemap.annotationOnTop | false | 设为 true 后,底图注记显示在图片图层上方;双引擎的图片更新、底图切换和引擎恢复均自动维持顺序。 | | basemap.list | 内置天地图、WMS、WMTS 示例列表 | 底图资源数组;完整默认项和字段见下方默认底图配置。外部传入数组会整体替换内置数组。 | | basemap.providers | 内置天地图 provider | 内置服务的地址、子域名、token 池及资源映射。当前适配器读取包内 provider,构造参数或 setConfig() 中的覆盖值尚不会生效;自定义服务请在 basemap.list 中配置 URL。 |

把地名、边界等瓦片注记显示在天气图片上方:

const mapCore = new BaseGIS({
  containerId: 'map',
  config: {
    basemap: {
      defaultVisibleId: 'tianditu-imagery',
      annotationOnTop: true,
    },
  },
})

Leaflet 将注记放到独立的 440 层,位于图片与等值线、Marker 之间,且不拦截鼠标交互。Cesium 在影像集合变化时将当前注记置顶;开启此项后,区域灰度图也使用 Canvas 着色后的影像管线,避免 GroundPrimitive 覆盖整个影像栈。该设置只控制底图瓦片注记与图片的关系,不会将注记抬到三维物体或后处理效果之上。配置在 init() 时读取;修改后需重新 init(),单独 setConfig() 不立即改变当前地图。

离线回归页面:启动开发服务后访问 /lgmap/scripts/test-basemap-annotations.html,使用合成瓦片和真实截图像素验证开关、图片替换、底图切换、引擎恢复及销毁清理。

dem 地形配置

| 配置项 | 内置默认值 | 说明 | | --- | --- | --- | | dem.defaultEnabled | true | Cesium 初始化时是否加载默认 DEM;false 时跳过。 | | dem.defaultVisibleId | 'ellipsoid-flat' | 默认 DEM id,必须能在 dem.list 中找到、visible !== false 且支持 Cesium,否则初始化失败。 | | dem.list | 平面地形、Cesium World Terrain、天地图 DEM 占位项 | DEM 资源数组;外部传入时整体替换。列表项常用字段为 id / name / sourceType / factory / url / visible / engineSupport / options,详细用法见DEM 地形。 |

Leaflet 不加载 DEM。cesium-world-terrain 需要 Cesium Ion 能力;tianditu-dem 是待补真实服务地址的占位项。

常用地图初始化配置示例

下面示例把真正参与地图创建的常用配置集中写在一起。未传的字段继续使用上表中的内置默认值:

const mapCore = new BaseGIS({
  containerId: 'map',
  config: {
    // 地图瓦片与无元数据栅格的默认投影分开管理。
    crs: 'EPSG:3857',
    sourceProjectionCrs: 'EPSG:3857',
    engine: {
      active: 'cesium',
      cesium: {
        renderQuality: {
          maximumDevicePixelRatio: 2,
          fxaa: true,
          msaaSamples: 4,
        },
      },
    },
    view: {
      defaultSceneMode: '3d',
      initialView: {
        center: [104, 35],
        height: 5000000,
        zoom: 5,
        heading: 0,
        pitch: -90,
        roll: 0,
      },
    },
    basemap: {
      defaultVisibleId: 'tianditu-imagery',
    },
    dem: {
      defaultEnabled: true,
      defaultVisibleId: 'ellipsoid-flat',
    },
  },
})

const result = mapCore.init()
if (!result.success) {
  console.warn(result.message)
}

sourceTransport 源解析传输默认配置

这一组不是地图容器或相机初始化参数,而是 Cesium 源解析传输图层的实例级默认值。

| 配置项 | 内置默认值 | 说明 | | --- | --- | --- | | sourceTransport.visible | true | 新建图层默认是否显示。 | | sourceTransport.running | true | 新建图层默认是否播放烟羽动画。 | | sourceTransport.colors | 内置 7 色数组 | 多来源默认色板。 | | sourceTransport.path | 内置对象 | 弧线路径分段、高度与弯曲参数。 | | sourceTransport.line | 内置对象 | 线宽、透明度、辉光、收尖和命中宽度。 | | sourceTransport.smoke | 内置对象 | 烟羽数量、大小、透明度、扩散和速度。 | | sourceTransport.sourceNode | 内置对象 | 来源节点大小与标签数量。 | | sourceTransport.targetNode | 内置对象 | 目标节点颜色与环半径。 | | sourceTransport.volume | 内置对象 | 目标体云开关、网格尺寸、渲染参数及色带。 | | sourceTransport.interaction | 内置对象 | 交互开关、命中容差和鼠标样式。 | | sourceTransport.fog | 内置对象 | 雾效开关与密度。 | | sourceTransport.camera | 内置对象 | 定位图层时的俯仰角、高度和动画时长。 |

单个图层传入的同名参数优先于这里的实例默认值。

配置合并规则

构造函数和 setConfig() 使用同一套合并规则:

| 数据类型 | 合并方式 | | --- | --- | | 普通对象 | 按层级递归合并,只传一个叶子字段不会删除同组其他字段。 | | 数组 | 整体替换,不会追加;basemap.list、dem.list、sourceTransport.colors 都遵循此规则。 | | 基本类型、函数及其他值 | 使用新值替换旧值。 | | 未传字段 | 保留当前配置中的值。 |

配置会被克隆后保存,不会直接修改包内默认配置。getConfig() 返回当前实例持有的配置对象引用,建议只读;修改配置统一调用 setConfig()。

例如,只覆盖 Cesium 像素比不会丢失 fxaa 和 msaaSamples:

mapCore.setConfig({
  engine: {
    cesium: {
      renderQuality: {
        maximumDevicePixelRatio: 1.5,
      },
    },
  },
})

如果要在现有底图列表后追加一项,必须自行保留原数组:

const currentConfig = mapCore.getConfig()

mapCore.setConfig({
  basemap: {
    list: [
      ...currentConfig.basemap.list,
      {
        id: 'custom-xyz',
        name: '自定义 XYZ',
        category: 'basemap',
        type: 'xyz',
        provider: 'custom',
        url: 'https://example.com/tiles/{z}/{x}/{y}.png',
        engineSupport: ['cesium', 'leaflet'],
      },
    ],
  },
})

setConfig() 怎么用

setConfig(overrideConfig) 是同步方法,没有统一结果对象或其他返回值。它只更新 BaseGIS 实例保存的配置,不会把新配置推送给已经创建的 adapter,也不会自动改变当前场景、视角、底图、DEM 或渲染质量。crs / sourceProjectionCrs 会归一化为 BaseGIS 支持的名称;修改 crs 后需重新 init(),修改 sourceProjectionCrs 只作为后续新数据的回退值。engine.active 是另一个需要特别注意的字段:它会同步实例记录的引擎类型,但不会真正替换当前底层地图。

需要让整套初始化配置生效时,直接再次 init(),不要先调用 destroy();否则托管图层快照会被清空:

mapCore.setConfig({
  engine: {
    cesium: {
      renderQuality: {
        maximumDevicePixelRatio: 1.5,
        fxaa: true,
        msaaSamples: 4,
      },
    },
  },
  view: {
    defaultSceneMode: '2d',
    initialView: {
      center: [116.4, 39.9],
      height: 1800000,
      zoom: 7,
      pitch: -90,
    },
  },
})

const result = mapCore.init()
if (result.success) {
  await mapCore.whenReady()
}

如果目标只是立即操作当前地图,不要用 setConfig() + init() 代替已有的实时 API:

| 目标 | 推荐 API | 是否重建地图 | | --- | --- | --- | | 切换 Cesium / Leaflet | await mapCore.setEngine(engineType) | 是,并自动恢复托管图层 | | 切换当前场景模式 | mapCore.setSceneMode({ mode }) | 否 | | 移动当前视角 | mapCore.setInitialView(view) | 否 | | 切换当前底图 | mapCore.setBasemapById(id) 或 mapCore.setBasemap(payload) | 否 | | 切换当前 DEM | mapCore.loadDEMById(id)、mapCore.loadDefaultDEM() 或 mapCore.loadDEM(payload) | 否 | | 修改当前或新建源解析传输层 | mapCore.updateSourceTransportLayer(payload) 或 mapCore.upsertSourceTransportLayer(payload) | 否 | | 修改 Cesium 渲染质量或整套初始化默认值 | setConfig() 后重新 init() | 是 |

特别注意:不要用 setConfig({ engine: { active: 'leaflet' } }) 切换已经显示的地图;应直接调用 setEngine('leaflet')。前者会让 getEngineType() 变成 leaflet,但底层仍可能是 Cesium,随后调用相同目标的 setEngine('leaflet') 还会被当作“已经是当前引擎”而跳过。若已经这样修改,应调用 init() 重建并校正地图实例。

默认底图配置

不传 config.basemap 时,内置默认配置如下:

basemap: {
  defaultVisibleId: 'tianditu-imagery',
  // 当前为保留字段,初始化时不会读取。
  defaultAnnotationId: 'tianditu-vector-label',
  annotationOnTop: false,
}

默认底图列表:

| id | 名称 | category | enabled | type | provider | resourceKey | 默认用途 | 引擎支持 | | --- | --- | --- | --- | --- | --- | --- | --- | --- | | tianditu-vector | 天地图矢量底图 | basemap | true | wmts | tianditu | vector | 可作为 defaultVisibleId | Cesium / Leaflet | | tianditu-imagery | 天地图影像底图 | basemap | true | wmts | tianditu | imagery | 内置 defaultVisibleId | Cesium / Leaflet | | tianditu-terrain | 天地图地形底图 | basemap | true | wmts | tianditu | terrain | 可作为 defaultVisibleId | Cesium / Leaflet | | tianditu-vector-label | 天地图矢量注记 | annotation | true | wmts | tianditu | vectorLabel | 可作为底图的 annotationResourceKey | Cesium / Leaflet | | tianditu-terrain-label | 天地图地形注记 | annotation | true | wmts | tianditu | terrainLabel | 可作为底图的 annotationResourceKey | Cesium / Leaflet |

说明:

  • defaultVisibleId 应指向 category: 'basemap' 的底图。
  • defaultVisibleId 找不到可用项时,会回退到 basemap.list 中第一个 enabled !== false、分类和引擎均匹配的底图;仍找不到时使用内置天地图矢量兜底配置。
  • defaultAnnotationId 当前只是保留字段,不参与初始化。要指定注记,给底图项设置 annotationResourceKey;天地图矢量、影像和地形底图未显式设置时,也会分别推断对应注记资源。
  • tianditu-terrain 是天地图地形底图瓦片,不是 Cesium 的 DEM 高程地形;如果要控制 Cesium terrainProvider,请看后文 DEM。
  • geoserver-wmts-sample 和 geoserver-wms-sample 默认 enabled: false,只是配置格式示例;如果要作为默认底图,需要替换真实服务地址并改为 enabled: true。
  • 天地图 provider 内置资源还包括 imageryLabel;默认 basemap.list 没有单独注册影像注记 id,但 resourceKey: 'imagery' 会自动推断使用 imageryLabel 注记。
  • 内置天地图会根据地图 crs 选择 _c 或 _w 瓦片矩阵;自定义 XYZ / WMTS / WMS 的 URL 和矩阵必须由业务保证与地图 crs 一致。地图已创建后不能通过普通底图切换改变 CRS,必须修改配置并重新 init()。

底图切换

底图可以来自 config.basemap.list,也可以直接传配置对象。当前适配层支持:

  • 天地图:provider: 'tianditu' 或传 resourceKey
  • URL 模板瓦片:type: 'wmts' / 'xyz' / 'tile'
  • WMS:type: 'wms'

按配置 id 切换:

const result = mapCore.setBasemapById('tianditu-imagery')
if (!result.success) {
  console.warn(result.message)
}

直接传底图配置:


mapCore.setBasemap({
  id: 'custom-xyz',
  name: '自定义 XYZ',
  category: 'basemap',
  type: 'xyz',
  provider: 'custom',
  url: 'https://example.com/tiles/{z}/{x}/{y}.png',
  minZoom: 0,
  maxZoom: 18,
  subdomains: ['a', 'b', 'c'],
})

mapCore.setBasemap({
  id: 'custom-wms',
  name: '自定义 WMS',
  category: 'basemap',
  type: 'wms',
  provider: 'custom',
  serviceUrl: 'https://example.com/geoserver/wms',
  layers: 'workspace:layer',
  parameters: {
    transparent: true,
    format: 'image/png',
    version: '1.1.1',
  },
})

方法说明:

| 方法 | 参数 | 说明 | | --- | --- | --- | | setBasemapById(id) | 底图 id | 从 config.basemap.list 查找底图并切换。会校验 category / engineSupport / enabled。 | | setBasemap(payload) | 底图配置对象 | 直接切换到底图配置。 |

常用底图参数:

| 参数 | 是否必填 | 说明 | | --- | --- | --- | | id | 建议必填 | 底图唯一 id。 | | name | 选填 | 底图名称。 | | category | 建议传 basemap | setBasemapById 会拒绝非 basemap 分类。 | | type | 自定义服务必填 | wmts、xyz、tile、wms。 | | provider | 选填 | 天地图传 tianditu,自定义服务传 custom。 | | resourceKey | 天地图必填 | vector、imagery、terrain 等。 | | annotationResourceKey | 选填 | 天地图注记资源,如 vectorLabel、imageryLabel。 | | url | URL 模板必填 | wmts/xyz/tile 使用,支持 {z}/{x}/{y} 模板。 | | serviceUrl | WMS 必填 | WMS 服务地址;也可用 url。 | | layers | WMS 必填 | WMS 图层名。 | | parameters | 选填 | WMS 附加参数。 | | engineSupport | 选填 | 支持的引擎列表,如 ['cesium', 'leaflet']。 |

图层配置构造器

layers 出口提供四个快捷构造器,只负责生成标准图层配置,不会直接操作地图。构造结果可以放入 config.basemap.list,也可以传给 setBasemap()。

import { BaseGIS } from '@3clear/basegis'
import {
  createGeoserverPyramidLayer,
  createTiandituLayer,
  createWmsLayer,
  createWmtsLayer,
} from '@3clear/basegis/layers'

const basemapList = [
  createTiandituLayer({
    id: 'tianditu-imagery',
    name: '天地图影像',
    category: 'basemap',
    resourceKey: 'imagery',
    annotationResourceKey: 'imageryLabel',
  }),
  createGeoserverPyramidLayer({
    id: 'geoserver-pyramid',
    name: 'GeoServer 金字塔瓦片',
    category: 'basemap',
    url: 'https://example.com/tiles/{z}/{x}/{y}.png',
  }),
  createWmsLayer({
    id: 'weather-wms',
    name: '气象 WMS',
    category: 'basemap',
    serviceUrl: 'https://example.com/geoserver/wms',
    layers: 'workspace:weather',
    parameters: {
      transparent: true,
      format: 'image/png',
    },
  }),
  createWmtsLayer({
    id: 'weather-wmts',
    name: '气象 WMTS',
    category: 'basemap',
    engineSupport: ['cesium'],
    url: 'https://example.com/geoserver/gwc/service/wmts?' +
      'SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=workspace:weather&' +
      'STYLE=default&TILEMATRIXSET=EPSG:3857&FORMAT=image/png&' +
      'TILEMATRIX=EPSG:3857:{z}&TILEROW={y}&TILECOL={x}',
  }),
]

const mapCore = new BaseGIS({
  containerId: 'map',
  config: {
    basemap: {
      list: basemapList,
      defaultVisibleId: 'tianditu-imagery',
    },
  },
})

四个构造器都会保留额外传入字段,便于继续配置 engineSupport、缩放级别、注记资源或服务参数。

createWmtsLayer() 只生成配置,不会根据 layer / tileMatrixSet 自动拼接请求。自定义 WMTS 需要完整的 GetTile URL 模板,矩阵标识应按服务实际配置填写;XYZ 瓦片同样使用包含 {z}/{x}/{y} 的 URL。

模板瓦片不会自动重投影。上面的 EPSG:3857 WMTS 示例限定用于 Cesium;当前 Leaflet 使用 EPSG:4326,自定义瓦片需匹配地图的坐标系和瓦片矩阵。

layers 还导出辅助函数 createTiandituTileSource(resourceKey = 'imagery'),返回 { url, subdomains },资源不可用时返回 null。它供需要直接操作引擎的特殊页面使用,普通页面仍优先调用 createTiandituLayer() 和 BaseGIS。

BaseGIS 基础能力

这一节列的是 BaseGIS 主入口直接提供的基础能力。业务页面优先调用这些方法;图片图层、网格图层、海量点、点位聚合、点位抽稀、等值线、风场等更复杂能力,建议使用后文 methods 中对应的 Controller。

1. 生命周期与实例

BaseGIS 负责地图实例的初始化、状态读取、尺寸刷新和销毁。构造参数、完整配置项、参数优先级及 setConfig() 的生效规则见地图初始化与运行时配置。

const mapCore = new BaseGIS({
  engineType: 'cesium',
  containerId: 'map',
})

const initResult = mapCore.init()
if (!initResult.success) {
  console.warn(initResult.message)
}

const engineType = mapCore.getEngineType()
const config = mapCore.getConfig() // 只读使用,不要直接修改。
const mapInstance = mapCore.getMapInstance()

mapCore.resize()
mapCore.destroy()

方法说明:

| 方法 | 参数 | 说明 | | --- | --- | --- | | init(options) | { container, containerId, engineType, sceneMode, initialView } | 初始化地图。重复调用会重建地图并异步恢复 BaseGIS 托管图层。 | | whenReady() | 无 | 等待最近一次 init() 触发的托管图层恢复完成。 | | destroy() | 无 | 销毁当前地图实例和 adapter,并清空托管图层快照。 | | setConfig(config) | Object | 合并实例配置,无返回值且不自动重建地图;查看完整规则。 | | getEngineType() | 无 | 返回当前引擎类型。 | | getConfig() | 无 | 返回当前配置对象引用,建议只读。 | | getMapInstance() | 无 | 返回底层地图实例:Cesium viewer 或 Leaflet map。 | | getMapContainer() | 无 | 返回统一结果,data.container 为地图容器 DOM。 | | resize() | 无 | 在容器尺寸改变、隐藏面板重新显示后刷新地图尺寸。 |

2. 切换引擎

BaseGIS 支持 cesium 和 leaflet 两种引擎。调用 setEngine() 可以在运行时切换引擎、保留当前视野,并恢复 BaseGIS 托管图层。

| 方法 | 参数 | 说明 | | --- | --- | --- | | setEngine(engineType, options) | 引擎类型、初始化参数 | 未初始化时记录默认引擎;已初始化时自动切换、保留视野并恢复托管图层。 | | switchEngine(engineType, options) | 引擎类型、初始化参数 | setEngine() 的兼容别名。 |

目标引擎与当前引擎相同时,setEngine() 会直接返回,不会应用 options.sceneMode / initialView / container。同一引擎下调整场景或视角应调用 setSceneMode()、setInitialView();需要重建地图时直接调用 init()。

发生实际切换时,setEngine() 会把目标场景模式,以及显式传入或从当前地图保留的视角写回 config.view,供之后再次初始化使用。

推荐写法

页面上做 Cesium / Leaflet 切换时,直接调用 setEngine()。它会保留当前视野、重建目标引擎,并等待托管图层自动恢复。

async function changeEngine(engineType) {
  if (!mapCore || mapCore.getEngineType() === engineType) {
    return
  }

  const result = await mapCore.setEngine(engineType)

  if (!result.success) {
    console.warn(result.message)
    return
  }
}

直接重复调用 init({ engineType }) 也会自动开始恢复;如果后续逻辑依赖恢复完成,需要再等待 whenReady():

const result = mapCore.init({
  engineType: 'leaflet',
  containerId: 'map',
})

if (result.success) {
  await mapCore.whenReady()
}

switchEngine() 作为兼容别名保留,行为与 setEngine() 一致。

切换后的图层处理

引擎切换不是把 Cesium 图层对象“搬到” Leaflet,也不是把 Leaflet 图层对象“搬到” Cesium。BaseGIS 会保存托管图层的业务参数,并在新 adapter 中重新创建图层。

  • 自动恢复范围包括图片、网格、海量点、点位聚合、点位抽稀、独立线、源解析传输、台风路径、等值线、统一风场和三维体图层。
  • 图层最新的数据参数、显隐、清空、删除、海量点删除和高亮状态会同步到 BaseGIS 快照。
  • 快照只保存业务参数引用,不复制大数组,不保存任何底层引擎对象。
  • 三维体、源解析传输切到 Leaflet 时会返回不支持结果,但快照仍保留,切回 Cesium 后会继续恢复。
  • Cesium 专有能力在 Leaflet 下不可用,例如 DEM、三维体渲染、三维切片/剖面渲染。
  • 基础绘制对象、GeoJSON、点击/视图监听、GPU 专用风场、独立 WindFieldMethods、剖面图层和页面直接创建的底层引擎对象不在托管范围内,需要业务重新加载或绑定。

切换结果中可以查看恢复明细:

const result = await mapCore.setEngine('leaflet')
console.log(result.data?.restore?.restored)
console.log(result.data?.restore?.failed)

result.success 表示引擎初始化/切换是否成功,不保证每个图层都恢复成功;应同时检查 data.restore.failed。不要在切换前先调用 destroy(),它会清空托管快照。

3. 视角控制与场景模式

视角控制分为缩放、重置视角、设置初始视角、场景模式切换、视图状态读取和视图变化监听。

// 放大 / 缩小。
// Cesium 可传 { distance },Leaflet 可传 { step }。
mapCore.zoomIn()
mapCore.zoomOut()
mapCore.zoomIn({ distance: 300000 })
mapCore.zoomOut({ step: 1 })

// 回到配置中的 initialView,也可以传入目标视角覆盖。
mapCore.resetView()
mapCore.resetView({
  center: [104, 35],
  height: 3000000,
  zoom: 5,
  pitch: -90,
})

// 设置视角。center / position 均为 [经度, 纬度]。
mapCore.setInitialView({
  center: [104, 35],
  // Cesium 使用 height。
  height: 3000000,
  // Leaflet 使用 zoom。
  zoom: 5,
  // Cesium 使用 heading / pitch / roll,单位是度。
  heading: 0,
  pitch: -90,
  roll: 0,
})

// 场景模式。Cesium 支持 2d / 2.5d / 3d;Leaflet 只支持 2d。
mapCore.setSceneMode('3d')
mapCore.setSceneMode({
  mode: '2d',
  // Cesium morph 动画时长,单位秒。
  duration: 0.4,
  // Cesium 场景切换后是否尽量恢复原视野,默认 true。
  preserveView: true,
})
mapCore.getSceneMode()

// 获取当前视图边界。
const boundsResult = mapCore.getViewBounds()
// boundsResult.data: { west, south, east, north }

// 获取当前视图状态。
const viewStateResult = mapCore.getViewState()
// Cesium 通常包含 center / bounds / height / heading / pitch / roll / engineType。
// Leaflet 通常包含 center / bounds / zoom / engineType。

// 让地图适配指定经纬度范围,可用于多地图首次统一范围。
mapCore.fitViewBounds({
  bounds: { west: 73, south: 18, east: 135, north: 54 },
  animate: false,
  padding: 0,
})

// 经纬度转地图容器像素坐标,常用于自定义 HTML 浮层定位。
const pointResult = mapCore.projectToContainerPoint({
  longitude: 104,
  latitude: 35,
  height: 0,
})
// pointResult.data: { x, y }

视图变化监听:

const viewListener = mapCore.onViewChange({
  // Cesium: camera.moveStart / morphStart;Leaflet: movestart / zoomstart。
  onStart() {},

  // Cesium: camera.changed;Leaflet: move / zoom / resize。
  // 缩放过程中要实时刷新点位样式时,优先用 onChange。
  onChange() {},

  // Cesium 交互期间逐渲染帧检测相机变化;适合多地图实时联动。
  // 默认 false,普通业务监听无需开启。
  continuous: true,

  // Cesium: camera.moveEnd / morphComplete;Leaflet: moveend / zoomend / resize。
  onEnd() {},

  // Cesium onEnd 延迟,默认 120ms。
  endDelay: 120,
})

// 组件卸载时移除监听。
viewListener.data?.off?.()

方法说明:

| 方法 | 参数 | 说明 | | --- | --- | --- | | zoomIn(payload) | Cesium { distance };Leaflet { step } | 放大地图。 | | zoomOut(payload) | Cesium { distance };Leaflet { step } | 缩小地图。 | | resetView(payload) | 视角对象,可选 | 回到初始视角或传入的目标视角。 | | setInitialView(payload) | { center, height, zoom, heading, pitch, roll } | 设置当前视角。 | | setSceneMode(payload) | '2d'/'2.5d'/'3d' 或 { mode, duration, preserveView } | 切换场景模式。 | | getSceneMode() | 无 | 获取当前场景模式。 | | getViewBounds() | 无 | 获取当前视图经纬度边界。 | | getViewState(payload) | 可选 {includeBounds:false} | 获取当前视图状态;实时同引擎联动可关闭较重的范围采样。 | | fitViewBounds(payload) | {bounds:{west,south,east,north},animate?,padding?,duration?} | 适配指定经纬度范围;duration 仅用于 Cesium 动画。 | | onViewChange(payload) | { onStart, onChange, onEnd, endDelay, continuous? } | 监听视图变化,返回 { off };Cesium 开启 continuous 后交互期间逐帧检测。 | | projectToContainerPoint(payload) | { longitude, latitude, height } | 经纬度投影到地图容器像素坐标。 |

4. 地图截图与导出

screenshot() 用于导出当前 Cesium 或 Leaflet 地图,两个引擎使用完全相同的调用方式、参数和结果对象。默认截取当前可视范围(地图视口)并下载 PNG,不会自动拼接视口外尚未渲染的地图内容;只截取地图内容,不包含页面工具栏、弹窗等地图容器外的 DOM 浮层。

框选遮罩样式包含在 @3clear/basegis/style.css 中,使用 npm 包时应按安装章节导入该样式文件。

在线示例:地图截图与 PNG 导出。

直接下载 PNG

默认 download: true,页面不需要自己创建下载链接或处理 Blob。fileName 可指定文件名;不传时使用前缀和时间戳自动命名。

// 截取当前可视范围并直接下载。
const result = await mapCore.screenshot({ fileName: 'weather-map.png' })
if (!result.success) {
  console.warn('截图导出失败', result.code, result.message)
}

// 左键拖拽框选区域,松开后下载;右键或 Esc 取消。
const selectResult = await mapCore.screenshot({
  mode: 'select',
  namePrefix: 'map-select',
})
if (!selectResult.success && selectResult.code !== 'CANCELLED') {
  console.warn('框选导出失败', selectResult.message)
}

按范围裁剪导出

// 按当前视野中的经纬度范围裁剪。
await mapCore.screenshot({
  namePrefix: 'east-china',
  bounds: { west: 115, south: 25, east: 123, north: 36 },
})

// 按相对当前地图视口左上角的 CSS 像素区域裁剪。
await mapCore.screenshot({
  rect: { left: 120, top: 80, width: 640, height: 360 },
})

获取 Blob,不自动下载

const captureResult = await mapCore.screenshot({
  download: false,
  fileName: 'weather-map.png',
})
if (captureResult.success) {
  const { blob, fileName, width, height } = captureResult.data
  // 页面可将 blob 交给自己的预览或上传逻辑,BaseGIS 不会自动上传。
  console.log(blob, fileName, width, height)
}

方法与参数

| 方法 | 参数 | 说明 | | --- | --- | --- | | screenshot(payload) | { mode?, download?, fileName?, namePrefix?, bounds?, area?, rect?, screenRect? } | 截取 Cesium / Leaflet 地图;mode: 'select' 进入交互框选,download 默认为 true。 | | cancelScreenshotSelection(reason?) | 可选取消原因字符串 | 主动取消正在进行的框选;返回布尔值,表示是否取消了现有框选。 |

| 参数 | 默认值 | 说明 | | --- | --- | --- | | mode | 省略 | 默认直接截图;'select' 进入鼠标框选,也可简写为 screenshot('select')。 | | download | true | 自动触发浏览器下载;传 false 只生成截图结果。 | | fileName | 自动生成 | 优先于 namePrefix;未以 .png 结尾时自动追加扩展名。当前仅导出 PNG。 | | namePrefix | map-screenshot | 自动文件名前缀;未指定名称的框选截图默认使用 map-select。 | | bounds / area | 当前视口 | 经纬度范围别名,支持 { west, south, east, north } 或 { startLon, startLat, endLon, endLat }。 | | rect / screenRect | 当前视口 | 屏幕区域别名,支持 { left, top, width, height },也可用 x / y 代替 left / top;单位为相对地图视口左上角的 CSS 像素。 |

取消框选时,原 screenshot() Promise 返回 success: false、code: 'CANCELLED' 和 data.cancelled: true;页面通常无需按错误弹窗处理。

成功结果的 data 包含 blob、width、height、mimeType、fileName、downloaded、screenRect 和 pixelRect。Cesium 读取 WebGL 场景画布;Leaflet 在首次调用时按需加载 DOM 渲染器,合成瓦片、SVG、Canvas 和 DOM Marker,并排除 Leaflet 自带控件。跨域地图资源需要服务端允许 CORS,否则对应资源可能缺失或截图返回 FAILED。为保证 WebGL 截图可靠,Cesium 初始化时会保留 drawing buffer;在超高分辨率大屏上会增加一定显存占用。

width / height / pixelRect 使用导出图片的实际像素,可能与 CSS 像素不同;downloaded: true 仅表示已触发下载,不代表浏览器已确认文件保存到磁盘。导出范围始终限制在当前视口内,不是整页长截图,也不支持自动加载并拼接屏幕外瓦片。

5. 绘制点、线、面、文字和 Marker

这些方法用于轻量绘制和样例验证。大量点位请优先使用后文的 PointLargeLayerController、PointClusterController、PointDensityController 等控制器。

点:

mapCore.drawPoint({
  id: 'point-1',
  name: '点位',
  // 必填建议:[经度, 纬度]。
  position: [104, 35],
  height: 0,
  // Cesium 使用 pixelSize;Leaflet 使用 radius。
  pixelSize: 10,
  radius: 7,
  color: '#ff4d4f',
})

线:

mapCore.drawLine({
  id: 'line-1',
  name: '连线',
  positions: [
    [103, 34],
    [105, 36],
  ],
  width: 3,
  color: '#1677ff',
})

面:

mapCore.drawPolygon({
  id: 'polygon-1',
  name: '区域',
  positions: [
    [102, 33],
    [106, 33],
    [106, 36],
    [102, 36],
  ],
  // Cesium 使用 fillColor;Leaflet 主要使用 color / fillOpacity。
  fillColor: 'rgba(22, 119, 255, 0.25)',
  color: '#1677ff',
  outlineWidth: 2,
  fillOpacity: 0.35,
  // Cesium 默认贴地;显式传 height 时按非贴地面绘制。
  height: 0,
})

文字:

mapCore.drawText({
  id: 'text-1',
  name: '文字',
  position: [104, 35],
  text: '示例文字',
  font: '16px Microsoft YaHei',
  color: '#0f2d4d',
  backgroundColor: 'rgba(255,255,255,0.7)',
  // 默认 center/bottom,也可以传 left/top/right/bottom。
  textAnchor: {
    horizontal: 'center',
    vertical: 'bottom',
  },
  textOffset: [0, 0],
})

图片 Marker:

mapCore.addMarker({
  id: 'marker-1',
  name: '站点',
  position: [104, 35],
  iconUrl: '/marker.png',
  iconSize: [32, 32],
  // 也支持 iconWidth / iconHeight。
  iconAnchor: [16, 32],
  iconOffset: [0, 0],
  label: '站点名称',
})

Canvas 数据图标与扩散效果

mapCore.createMarkerIcon(options, data) 支持圆点、“数值 + 名称”、气象风向、“图片 + 名称”和“图片 + 数值 + 名称”五种 Canvas 样式。圆点用法:

const station = {
  id: 'station-1',
  name: '示例站点',
  position: [104, 35],
  value: 28.6,
  status: 'normal',
  windDirection: 90,
  windSpeed: 6,
}

const markerIcon = mapCore.createMarkerIcon({
  type: 'dot',
  size: 18,
  color: '#64748b',
  getColor(data) {
    if (data.status === 'normal') return '#00e600'
    if (data.status === 'warning') return '#a67824'
    return '#6b7280'
  },
}, station)

mapCore.addMarker({
  id: station.id,
  name: station.name,
  position: station.position,
  data: station,
  ...markerIcon,
})

“数值 + 名称”用法:

const markerIcon = mapCore.createMarkerIcon({
  type: 'value-label',
  value: station.value,
  label: station.name,
  showLabel: station.showName !== false,
  color: '#64748b',
  getColor(data) {
    if (data.status === 'normal') return '#00e600'
    if (data.status === 'warning') return '#a67824'
    return '#6b7280'
  },
}, station)

mapCore.addMarker({
  id: station.id,
  name: station.name,
  position: station.position,
  data: station,
  ...markerIcon,
})

气象风向用法:

const markerIcon = mapCore.createMarkerIcon({
  type: 'wind',
  direction: station.windDirection,
  label: station.name,
  showLabel: station.showName !== false,
  color: '#64748b',
  getColor(data) {
    if (data.windSpeed >= 17.2) return '#e5484d'
    if (data.windSpeed >= 10.8) return '#f59e0b'
    if (data.windSpeed >= 5.5) return '#2f80ed'
    return '#00e600'
  },
}, station)

mapCore.addMarker({
  id: station.id,
  position: station.position,
  data: station,
  ...markerIcon,
})

“图片 + 名称”用法:

import { gisInfoMarker } from '@3clear/basegis/assets'

const stationImage = new Image()
// 跨域图片需由服务端允许 CORS,并在设置 src 前配置 crossOrigin。
stationImage.src = gisInfoMarker
await stationImage.decode()

const markerIcon = mapCore.createMarkerIcon({
  type: 'image-label',
  image: stationImage,
  imageSize: [20, 20],
  label: station.name,
  showLabel: station.showName !== false,
}, station)

mapCore.addMarker({
  id: station.id,
  position: station.position,
  data: station,
  ...markerIcon,
})

“图片 + 数值 + 名称”用法:

import { gisFactoryMarker } from '@3clear/basegis/assets'

const company = { id: 'factory-1', name: '示例企业', emissionValue: 12.5 }
const factoryImage = new Image()
factoryImage.src = gisFactoryMarker
await factoryImage.decode()

const markerIcon = mapCore.createMarkerIcon({
  type: 'image-value-label',
  image: factoryImage,
  imageSize: [14, 14],
  value: company.emissionValue,
  label: company.name,
  showValue: company.showValue !== false,
  showLabel: company.showName !== false,
}, company)

mapCore.addMarker({
  id: company.id,
  position: [104.2, 35.1],
  data: company,
  ...markerIcon,
})

getColor(data) 同步接收 createMarkerIcon 第二个参数传入的原始数据并返回 CSS 颜色。回调异常、返回非法颜色或空值时使用 options.color,再无有效静态颜色时使用默认灰色。圆点 size 默认 18px,允许 4~96px,并使用中心锚点。value-label 的 value 位于上方彩色色块,label 位于下方白色名称块;showLabel: false 时只显示数值块,图标宽高和锚点会自动更新。wind 的 direction 使用角度,0 指向正上方(北)、90 指向右侧(东),按顺时针方向增加;label 位于下方白色名称块,showLabel: false 时可隐藏,风速颜色分级完全由业务回调决定。image-label 的 image 接收已加载的 CanvasImageSource,imageSize 控制图片尺寸;URL 图片应先加载一次再传入,以保持抽稀回调同步。image-value-label 在同一规则上增加右侧 value 和蓝色圆角色块;showValue: false 时不绘制数值底板,只保留图片本身,showLabel: false 可独立隐藏名称。两者都隐藏时得到纯图片图标,画布尺寸和锚点会按照 imageSize 自动收缩。该类型使用整数锚点减少低 DPR 下的文字模糊。返回的 iconUrl/iconSize/iconAnchor 可用于普通 Marker、点位抽稀及其他图片点位能力。

Cesium / Leaflet 双引擎扩散 Marker:

mapCore.addMarker({
  id: 'alarm-station',
  name: '告警站点',
  position: [121.48, 31.23],
  data: station,
  iconUrl: '/marker.png',
  iconSize: [34, 40],
  pulse: {
    color: '#22d3ee',
    size: 88,
    duration: 2,
    ringCount: 2,
    ringWidth: 2,
    ringOpacity: 0.72,
  },
  clampToGround: true,
  onClick({ data }) {
    console.log(data)
  },
})

pulse 只是图标下方的效果层,不会生成中心点。pulse.size 是最大扩散直径(像素),ringWidth 是独立的屏幕像素线宽,ringOpacity 是圆环不透明度;duration 是单个圆环的周期(秒),ringCount 支持 1~3。页面不需要判断当前引擎;Leaflet 使用 SVG 动画,Cesium 使用 Billboard 缩放动画,两端保持相同的半径、线宽、透明度和相位变化曲线。只传 pulse 时仅显示扩散环;与 iconUrl 同时传入时,图标显示在扩散环上层。

使用 SVG 资源

assets 导出的资源均为可直接用于 iconUrl 的 SVG URL;传给 Canvas 图标的 image 时则需要先加载为图片对象。

| 导出 | 用途 | | --- | --- | | gisMarkerSample | 基础 Marker 示例。 | | gisFactoryMarker | 工厂标记,适合企业排放数据。 | | gisInfoMarker | 信息标记,适合站点名称与数值。 | | typhoonPathIcon | 台风路径默认中心图标。 |

import { gisMarkerSample } from '@3clear/basegis/assets'

mapCore.addMarker({
  id: 'marker-sample',
  name: '示例站点',
  position: [104, 35],
  iconUrl: gisMarkerSample,
  iconSize: [42, 50],
  iconAnchor: [21, 50],
})

清理图形:

mapCore.removeGraphic({ id: 'marker-1' })
mapCore.removeGraphic('marker-1')
mapCore.clearGraphics()

方法说明:

| 方法 | 参数 | 说明 | | --- | --- | --- | | drawPoint(payload) | 点配置 | 绘制点。 | | drawLine(payload) | 线配置 | 绘制线。 | | drawPolygon(payload) | 面配置 | 绘制面。 | | drawText(payload) | 文字配置 | 绘制文字。 | | createMarkerIcon(options, data) | 图标配置、原始数据 | 直接返回 iconUrl/iconSize/iconAnchor;未知 type 返回 null。 | | addMarker(payload) | Marker 配置 | 绘制图片或 pulse 扩散 Marker;未传图片或扩散参数时,Cesium 使用点、Leaflet 使用默认 Marker。 | | removeGraphic(payload) | 图形 id 或 { id } | 删除指定图形。 | | clearGraphics() | 无 | 清空通过基础绘制方法创建的图形。 |

6. GeoJSON 图层

upsertGeoJsonLayer() 用同一个 layerId 创建或替换 GeoJSON 点、线、面图层,两个引擎共用数据与样式参数。图层基础样式使用 style,按要素覆盖的完整样式由 styleCallback(feature, index) 返回。坐标按 GeoJSON 顺序传入 [经度, 纬度, 可选高度]。

const result = await mapCore.upsertGeoJsonLayer({
  layerId: 'region-boundaries',
  data: {
    type: 'FeatureCollection',
    features: [{
      type: 'Feature',
      id: 'region-1',
      properties: {
        name: '示例区域',
      },
      geometry: {
        type: 'Polygon',
        coordinates: [[[103, 34], [105, 34], [105, 36], [103, 36], [103, 34]]],
      },
    }],
  },
  styleCallback(feature) {
    return {
      color: '#36d3ff',
      weight: 3,
      opacity: 1,
      dashArray: '8 4',
      fillColor: '#1677ff',
      fillOpacity: 0.4,
    }
  },
  onClick({ feature, properties }) {
    console.log(properties.name, feature)
  },
})

if (result.success && result.data.bounds) {
  mapCore.fitViewBounds({ bounds: result.data.bounds, animate: false })
}

| 参数 | 说明 | | --- | --- | | layerId | 必填,图层唯一 id。 | | data | 必填;支持 FeatureCollection、Feature、Geometry、Feature 数组、JSON 字符串或 URL。也兼容 geojson / geoJson / source / url。 | | fetchOptions | 使用 URL 时传给 Fetch 的请求参数。业务接口通常由宿主 api/modules 获取后再传入 data。 | | style | 统一样式:color / weight / opacity / dashArray / fillColor / fillOpacity / stroke / fill;Leaflet 圆点大小用 radius,Cesium 标记大小用 markerSize。 | | styleCallback(feature, index) | 按数据返回样式覆盖;线、面支持全部 style 字段,点还支持 radius / markerSize;异常时使用基础样式。 | | onClick(event) | 返回 layerId / feature / properties / data / event / target / engineType;data 为原始 Feature。 | | visible | 默认 true。 | | clampToGround | Cesium 是否贴地,默认 true。 |

mapCore.hideGeoJsonLayer({ layerId: 'region-boundaries' })
mapCore.showGeoJsonLayer({ layerId: 'region-boundaries' })
const stateResult = mapCore.getGeoJsonLayerState({ layerId: 'region-boundaries' })
console.log(stateResult.data) // layerId / layerType / visible / featureCount / bounds

mapCore.clearGeoJsonLayer({ layerId: 'region-boundaries' }) // 清空要素,保留图层。
mapCore.removeGeoJsonLayer({ layerId: 'region-boundaries' }) // 删除图层。

styleCallback 可直接返回完整样式;需要按要素变化时,在回调中读取 feature.properties 后决定返回值即可。opacity: 0、fillOpacity: 0、stroke: false、fill: false 都会按原值保留。两个引擎都会渲染虚线,但 dashArray 的具体节奏是近似效果。

上述管理方法也可直接传 id 字符串;方法名兼容大写 GeoJSON,例如 upsertGeoJSONLayer()。更新时需重新提供完整数据和样式。GeoJSON 当前不在自动恢复清单中,切换引擎后需重新调用 upsertGeoJsonLayer()。

7. DEM 地形

仅 Cesium 支持。默认使用 ellipsoid-flat 椭球地形;tianditu-terrain 是底图瓦片,不会提供高程。当前 DEM 接口支持椭球和 Cesium World Terrain,配置中的 tianditu-dem 仍是占位项,不能作为已实现地形源使用。

// 使用 World Terrain 前,宿主需准备 Cesium Ion 等所需凭据与网络访问。
const result = mapCore.loadDEMById('cesium-world-terrain')
if (!result.success) {
  console.warn(result.message)
} else if (result.data.loading) {
  // 某些 Cesium 版本异步加载地形;调用返回成功不等于地形已经就绪。
  const provider = await result.data.readyPromise
  if (!provider) console.warn('World Terrain 加载失败')
}

mapCore.setTerrainExaggeration({ factor: 2 })
console.log(mapCore.getDEMState().data)

| 方法 | 说明 | | --- | --- | | loadDEMById(id) | 从 config.dem.list 查找地形配置,常用 ellipsoid-flat / cesium-world-terrain。 | | loadDEM(payload) | 直接传配置;支持 { id, sourceType: 'ellipsoid-flat' } 或 { id, sourceType: 'cesium-official', factory: 'worldTerrain' }。 | | loadDefaultDEM() | 按当前 config.dem 加载默认地形。 | | getDEMState() | data 返回 { id, enabled, exaggeration };enabled 按 id !== 'ellipsoid-flat' 判断,不代表异步地形已就绪。 | | setTerrainExaggeration(payload) | 传数字或 { factor },范围 1~10。 |

恢复平面地形可调用 mapCore.loadDEMById('ellipsoid-flat')。Leaflet 不提供 DEM;调用失败时应检查 success / code / message,不要直接假定结果包含地形状态。

8. 点击事件

onClick 注册地图点击事件;offClick 移除当前点击监听。当前每个 adapter 只保留一个基础点击监听,重复调用 onClick 会先移除旧监听。

mapCore.onClick({
  callback(event) {
    console.log(event)
  },
})

mapCore.offClick()

Cesium 点击空地时的事件结构:

{
  clickType: 'coordinate',
  engineType: 'cesium',
  coordinates: {
    longitude: 104,
    latitude: 35,
    height: 0,
  },
}

Cesium 点击 Entity 时的事件结构:

{
  clickType: 'entity',
  engineType: 'cesium',
  coordinates: {
    longitude: 104,
    latitude: 35,
    height: 0,
  },
  target: {
    id: 'point-1',
    name: '点位',
    entityType: 'entity',
  },
}

Leaflet 当前返回坐标点击:

{
  clickType: 'coordinate',
  engineType: 'leaflet',
  coordinates: {
    longitude: 104,
    latitude: 35,
    height: 0,
  },
}

说明:

  • 基础 onClick 适合地图空白点击、简单 Entity 点击。
  • 海量点、点位聚合、点位抽稀等图层自己的点击事件,应使用对应 Controller 的点击回调参数。

多地图联动(双屏联动)

MapViewLinkController 注册多个已经初始化的 BaseGIS,并实时同步拖动、缩放和视角。每个地图仍可独立加载不同模式、时次和图层;控制器只负责视角,不创建地图,也不会在 unregisterMap()、clear() 或 destroy() 时销毁 BaseGIS。

在线示例:查看分屏布局中的页面地图联动。布局可混合地图、图表和表格,地图实例与联动由页面管理。

import { BaseGIS } from '@3clear/basegis'
import { MapViewLinkController } from '@3clear/basegis/methods'

const mapA = new BaseGIS({
  engineType: 'leaflet',
  containerId: 'map-a',
})
const mapB = new BaseGIS({
  engineType: 'leaflet',
  containerId: 'map-b',
})
mapA.init()
mapB.init()

const viewLinks = new MapViewLinkController({
  enabled: true,
  realtime: true,
  mode: 'all',       // all | leader | group
  strategy: 'auto',  // auto | view | bounds
  leaderId: 'map-a',
  syncInterval: 32, // 实时同步间隔,约 30fps
})

viewLinks.registerMap('map-a', mapA, { group: 'forecast' })
viewLinks.registerMap('map-b', mapB, { group: 'forecast' })

// 获取 BaseGIS、底层地图实例和全部 id -> BaseGIS 映射。
const registeredMapA = viewLinks.getMap('map-a')
const leafletMapA = viewLinks.getNativeMap('map-a')
const allMaps = viewLinks.getMaps()

// 以 map-a 为操作源放大,并实时同步其他地图。
viewLinks.zoomIn({ mapId: 'map-a', step: 1 })

// 程序化控制全部注册地图。
viewLinks.setView({ center: [104, 34], zoom: 5, height: 5000000 })
viewLinks.fitBounds({ bounds: { west: 73, south: 18, east: 135, north: 54 } })

// 页面卸载:控制器先解绑,地图仍由页面自己销毁。
viewLinks.destroy()
mapA.destroy()
mapB.destroy()

构造参数:

| 参数 | 类型 | 默认值 | 说明 | | --- | --- | --- | --- | | enabled | Boolean | true | 是否开启联动。 | | realtime | Boolean | true | true 按动画帧同步移动/缩放;false 只在操作结束时同步。 | | mode | String | 'all' | all 任意图控制;leader 仅主图;group 仅同组地图。 | | strategy | String | 'auto' | auto 自动选择;view 优先中心和层级/高度;bounds 使用视图范围。 | | leaderId | String | '' | 主图 id;空值会使用首个注册地图。 | | syncInterval | Number | 32 | 实时同步的最小间隔,单位 ms;默认约 30fps,降低多 Cesium 实例同时渲染的压力。 | | suppressionMs | Number | 220 | 被同步地图的事件抑制时长,避免反向循环。 | | endDelay | Number | 80 | Cesium 操作结束事件延迟,单位 ms。 | | onStateChange | Function | null | 注册、模式、主图和操作结束后的回调,参数为 { reason, state }。 |

联动与实例方法:

| 方法 | 参数 | 返回 / 说明 | | --- | --- | --- | | registerMap(id,mapCore,options) | options:{group?,enabled?,replace?} | 注册已初始化的 BaseGIS 并绑定实时视图监听。 | | unregisterMap(id) | 地图 id | 解除监听和注册,不销毁 BaseGIS。 | | refreshMap(id) | 地图 id | BaseGIS.setEngine() 后重新绑定新 adapter 的监听。 | | getMap(id) | 地图 id | 返回 BaseGIS 或 null。 | | getNativeMap(id) | 地图 id | 返回 Cesium Viewer / Leaflet Map 或 null。 | | getMaps() | 无 | 返回新的 Map<id, BaseGIS>,修改它不会改变控制器注册表。 | | getMapIds() / hasMap(id) | 可选 id | 查询注册状态。 | | forEachMap(callback) | (mapCore,id,entry) | 遍历已注册 BaseGIS。 | | getLeaderMap() / getActiveMap() | 无 | 获取主图或最近操作地图。 | | setLeader(id) | 地图 id | 设置主图。 | | setMode(mode) | all/leader/group | 更新联动模式。 | | setStrategy(strategy) | auto/view/bounds | 更新视角映射策略。 | | setMapGroup(id,group) | 地图 id、组名 | 更新地图所在联动组。 | | setMapEnabled(id,enabled) | 地图 id、布尔值 | 单独启停某张地图的联动。 | | setEnabled(enabled) / pause() / resume() | 可选布尔值 | 整体启停联动。 | | setRealtime(realtime) | 布尔值 | 切换实时或操作结束后同步。 | | syncFrom(id,options) | 地图 id、force/strategy 等 | 立即把指定地图视角同步给目标地图。 |

统一视角操作:

| 方法 | 参数 | 说明 | | --- | --- | --- | | zoomIn(payload) | {mapId?,step?,distance?} | 按显式 mapId、最近活动地图、主图的顺序选取操作源,再按联动规则同步。 | | zoomOut(payload) | 同上 | 缩小并同步。 | | setView(payload) | center,zoom,height,heading,pitch,roll | 设置全部注册地图视角。 | | fitBounds(payload) | {bounds,animate?,padding?,duration?} | 让全部地图适配相同范围。 | | resetView(payload) | 可选视角 | 重置全部地图。 | | resizeAll(payload) | 可选参数 | 刷新全部地图容器尺寸。 | | getState() | 无 | 返回模式、主图、注册地图、最近同步来源等状态。 | | clear() / destroy() | 无 | 解绑全部监听并释放引用,不销毁 BaseGIS。 |

setView / fitBounds / resetView / resizeAll 始终作用于所有注册地图,不受联动分组或暂停状态限制。

同为 Leaflet 时会同步 center + zoom;同为 Cesium 时会直接同步相机经纬度、height + heading/pitch/roll;两种视图模型无法直接对应时,auto 才会计算并使用 bounds。Cesium 交互期间会逐帧检测相机变化,再按 syncInterval 合并为最新状态写入目标地图,避免目标地图追赶稀疏跳点,也避免四五个 Cesium 实例每帧重复计算完整视域。一次拖动期间会锁定唯一交互源,目标地图的程序化相机事件不会反向接管并形成反馈循环。

BaseGIS 切换引擎会重建 adapter,原视图监听随旧 adapter 销毁。切换完成后调用 viewLinks.refreshMap(id);控制器不会劫持或改写 BaseGIS.setEngine()。

LineLayerController

独立管理一组折线,支持整体更新、显隐、清空、销毁和引擎切换恢复。每条线必须提供唯一 id 和至少两个 [longitude, latitude, height?] 坐标点;同一控制器同一时刻只播放一条线的逐步出线动画。

逐顶点色专题线与时间裁剪

lines[].colors 是六位 HEX 数组,长度必须与 positions 完全一致,颜色沿每两个相邻顶点连续插值,优先于 style.color:

import { LineLayerController } from '@3clear/basegis/methods'

const lineLayer = new LineLayerController({ mapCore, layerId: 'sampling-tracks' })
const startTime = Date.parse('2026-08-28T08:00:00+08:00')
await lineLayer.load({
  lines: [{
    id: 'sampling-track',
    positions: [[113.30, 22.60], [113.31, 22.61]],
    colors: ['#00FF00', '#FF3B30'],
    times: [startTime, startTime + 60000],
  }],
  style: { width: 5, opacity: 1, clampToGround: false },
  animation: { enabled: false },
  currentTime: startTime,
})

lineLayer.setTime(startTime + 30000) // 显示前 30 秒已走过的路线。
lineLayer.setTime(null) // 恢复完整路线。

需要行驶回放时,为各条线附加 times: [起点毫秒时间戳, 终点毫秒时间戳, ...],长度与坐标相同且严格递增。load 可设置 currentTime,加载后调用 lineLayer.setTime(time) 裁掉未来部分;setTime(null) 恢复完整路线。不带 times 的线不参与裁剪。成功返回 { success: true, data: { layerId, currentTime } },非法时间返回友好失败结果。

Cesium 使用一个批量 Primitive 做顶点色插值,时间用相对秒数存入顶点,回放每帧仅改材质参数。Leaflet 使用共享 Canvas 重绘已走过的线段,不重新投影或创建图层。这是实线专题叠加,不能与虚线、流动、单线 reveal 或贴地混用;Cesium 关闭深度测试,带时间的采样按直线连接,不用于地形遮挡/贴合,位置必须不同。数据/配色更新仍为全量替换,显隐和引擎切换保留时间。浓度映射、分车/断线、时钟和小车属于业务层;参考项目 /test-page-43。

实线、虚线与纯色

import { LineLayerController } from '@3clear/basegis/methods'

const lineLayer = new LineLayerController({
  mapCore,
  layerId: 'flight-route',
  style: {
    color: '#00d8ff',
    width: 4,
    opacity: 0.9,
    pattern: 'dashed', // solid | dashed
    dashLength: 14,
    gapLength: 8,
  },
})

await lineLayer.load({
  lines: [{
    id: 'route-1',
    positions: [
      [116.4, 39.9],
      [117.8, 37.5],
      [121.5, 31.2],
    ],
  }],
})

单条线的 style 可以覆盖控制器的顶层默认样式。

固定渐变与流动渐变

style.color 可以是 CSS 颜色字符串,也可以是渐变配置。stops 的 offset 按 0~1 升序排列;配置 flow 后渐变会沿线路循环流动。

const gradientStyle = {
  width: 5,
  pattern: 'solid',
  color: {
    type: 'gradient',
    stops: [
      { offset: 0, color: '#00e5ff' },
      { offset: 0.5, color: '#2563eb' },
      { offset: 1, color: '#a855f7' },
    ],
    flow: {
      enabled: true,
      durationMs: 2400,
      direction: 'forward', // forward | reverse
    },
  },
}

渐变与虚线可以同时配置。Cesium 和 Leaflet 的底层绘制机制不同,虚线端点和颜色交界处可能有轻微视觉差异。

飞机引领的逐步出线

飞机不是单独的类,而是通用 animation.icon 配置。省略 icon 时只播放线路逐步出现。

// BaseGIS 不内置飞机图片,替换成业务项目自己的资源地址。
const planeIconUrl = '/your-app/plane.svg'

const flightLine = new LineLayerController({
  mapCore,
  layerId: 'flight-route',
  style: gradientStyle,
  animation: {
    enabled: true,
    lineId: 'route-1',
    mode: 'reveal',
    durationMs: 12000,
    autoplay: true,
    loop: true,
    icon: {
      url: planeIconUrl,
      size: [36, 36],
      rotateToPath: true,
      rotationOffsetDeg: 0,
    },
  },
})

await flightLine.load({
  lines: [{
    id: 'route-1',
    positions: [
      [116.4, 39.9],
      [117.8, 37.5],
      [121.5, 31.2],
    ],
  }],
})

flightLine.pauseAnimation()
flightLine.playAnimation()
flightLine.restartAnimation()

动画按照各段实际地理距离插值。hide() 暂停帧更新并记录播放状态,show() 恢复隐藏前正在运行的动画;clear() 和 destroy() 会取消动画。切换引擎会恢复播放/暂停意图,但不会保存逐帧进度,动画从起点重新计算。

参数

| 参数 | 默认值 | 说明 | | --- | --- | --- | | layerId | line-default | 独立线图层 id。 | | lines | [] | 折线数组,每项包含唯一 id 和至少两个 positions 坐标。 | | lines[].colors | - | 与坐标等长的六位 HEX 数组,优先于 style.color;用于实线专题叠加。 | | lines[].times | - | 与坐标等长、严格递增的有限毫秒时间戳;必须与 colors 配合。 | | currentTime | null | 路线时间裁剪位置;null 显示全部。 | | visible | true | 初始是否可见。 | | style.color | #2f80ff | 纯色字符串或渐变对象。 | | style.width / style.opacity | 3 / 1 | 线宽和透明度。 | | style.pattern | solid | solid 或 dashed。 | | style.dashLength / gapLength | 12 / 8 | 虚线实段和间隔长度。 | | animation.enabled | false | 是否启用逐步出线。 | | animation.lineId | 单线时自动选择 | 多条线启用动画时必填。 | | animation.durationMs | 10000 | 从起点到终点的时长。 | | animation.autoplay / loop | true / false | 自动播放与循环。 | | animation.icon | - | 可选的飞机、车辆或船舶图标配置。 |

方法

| 方法 | 说明 | | --- | --- | | mount(mapCore) | 后挂载 BaseGIS。 | | load(payload, options?) / update(payload) | 加载或更新线、样式和动画。 | | setTime(currentTime) | 更新路线时间裁剪;传 null 恢复完整路线,不重建全部线数据。 | | show() / hide() / toggle() | 控制显隐。 | | playAnimation() / pauseAnimation() / restartAnimation() | 控制沿线动画。 | | clear() | 清空线和动画,保留控制器。 | | refreshState() / getState() | 获取线数量、点数和动画状态。 | | destroy() | 删除图层、动画和引擎恢复快照。 |

页面卸载时先执行 lineLayer.destroy(),再执行 mapCore.destroy()。

在线示例:查看 LineLayerController 双引擎应用 Demo。

TyphoonPathController

把已经整理好的台风实况和预报数据渲染为独立专题图层,统一支持 Cesium / Leaflet。控制器负责实况路径、强度着色节点、生命周期标签、移动中心、当前点 7/10/12 级四象限风圈、多机构预报、不确定性圆和播放定位。

BaseGIS 不请求台风接口,也不推算强度、风圈、预报或预警等级。分页筛选、接口字段转换、ECharts 和业务面板仍由应用层负责。24/48 小时警戒线属于普通业务折线,推荐与 LineLayerController 组合使用。

最小用法

import { TyphoonPathController } from '@3clear/