lwx-wi-map

基于 OpenLayers 的城市防洪排涝基础地图组件(图层、属性面板、曲线、时间轴)
1,564
Install
npm install lwx-wi-map
Latest Version:0.10.0
Vue:3
License:MIT
Last Updated:Oct 21, 2026
Links: npm
Maintainer: gersonwu

lwx-wi-map

基于 OpenLayers 的城市防洪排涝基础地图组件:底图切换、MVT/WMS 业务图层、图例分级渲染、属性面板、过程曲线、时间轴播放、要素高亮与 3D 透视。

核心设计目标:

  • 逻辑与界面分离:所有地图逻辑在 MapController / useMapViewer 中,内置 UI 只是可选的壳。
  • 可定制主题:一套 --wi-map-* CSS 变量,传一个主题色即可派生全套;内置深/浅两套。
  • 可按需取用 UI:每块内置 UI 可用 showXxx 关闭,或用具名插槽整体替换;也可以完全不要 UI,只拿逻辑。

架构与设计说明见 ARCHITECTURE.md;可运行示例见 example/。


安装与初始化

pnpm add lwx-wi-map

无论用不用内置 UI,都必须先在应用启动时注入宿主运行时依赖:

import { configureMapApi } from 'lwx-wi-map'; // 纯逻辑用 'lwx-wi-map/core'

configureMapApi({
  http,                       // 宿主 HTTP 客户端(需实现 get/post)
  getWisession: () => token,  // 用于给瓦片 URL 追加鉴权参数,可选
  baseUrl: MAIN_URL,          // 业务服务基地址,用于解析相对瓦片地址
  // 以下可选,用于解耦宿主 iconfont
  iconFontFamily: 'ywifont',
  getIconGlyph: (name) => '\ue67e', // 图标名 → 字体字形字符
});

内置 UI 入口依赖 element-plus(peerDependency),且不打包 EP 样式,宿主需全局引入 Element Plus 样式。逻辑入口 lwx-wi-map/core 不依赖 Element Plus / ECharts。

业务图层 draw_style.logo 用的 ywifont 字形已随包内置(src/styles/ywiconfont,woff2 内联进 style.css),宿主无需自备该字体;只走 lwx-wi-map/core 时不含该 CSS,需自行引入,或用 configureMapApi 的 iconFontFamily / getIconGlyph 指向宿主自己的图标字体。

ol / ol-ext / echarts 均为 peerDependency,需宿主自行安装。echarts 标记为可选:仅在使用 MapChartPanel / ChartDialog 或横 / 纵断面分析面板时才需要;只用地图或 useMapViewer 时可不安装。

ol 需 ≥ 10.7.0:MVT 图层默认使用 WebGLVectorTileLayer(10.4.0 起提供),图例分档依赖 flat style 的 else 规则语义(10.7.0 起 WebGL 渲染器才按「前面规则都未命中」处理,低版本会把末档颜色覆盖到所有要素上)。


用法一:完整组件(内置 UI)

<script setup lang="ts">
import { MapView } from 'lwx-wi-map';
import 'lwx-wi-map/style.css';

function onReady(map) {
  // 拿到原生 ol Map 实例,可自行叠加 overlay / interaction
}
</script>

<template>
  <MapView
    group="FLOOD"
    :time="currentTime"
    :time-layer-ids="['flood_contour_mvt']"
    theme-color="#328fff"
    theme="dark"
    @map-ready="onReady"
    @feature-click="(feature, layerName) => {}"
    @time-rendered="() => {}"
  />
</template>

Props

名称 类型 默认值 说明
layers LayerItem[] — 外部直接传图层配置;传入后不再按 group 拉取
extent number[] — 显示范围 [minx, miny, maxx, maxy]
group string '' 业务图层分组,自动调用 /busigis/getLayerListByGroup
layerTheme string '' 图层主题(全局配置 ui.layer_theme_config 中的主题名,如「实时仿真」),优先于 group:按主题图层 id 调 /busigis/getLayerListById;主题内按 group_type 形成两层图层树,最终显示图层以接口返回为准
time string '' 外部时间
timeLayerIds string[] — 播放优化:仅这些图层随 time 刷新,其余只加载一次
center [number, number] [104, 35.5] 初始中心 [lng, lat]
zoom number 4.5 初始缩放
base BaseMapKey 'vec' 初始底图类型
stylePlugins LayerStylePlugin[] — 图层样式插件,命中即接管该图层渲染
highlightUrl string — 查询高亮数据接口(如 busigis/getBusiHighLightPdb?query_id=xxx),地图初始化后自动拉取(protobuf),按返回的 otype:oname 命中业务要素并修改其高亮样式
highlightQueryId string — 查询高亮查询 id(highlightUrl 缺省时拼为 /busigis/getBusiHighLightPdb?query_id=)
layerPanelWidth number 300 图层控制面板宽度(px)
propChartTarget 'dialog' | 'bottom' 'dialog' 属性面板曲线打开方式:dialog 弹窗查看;bottom 抛出 prop-chart-open 由外部底部曲线面板显示(选中带默认曲线即属性配置 sections.chart 非空的要素时也会自动抛出)
propPanelWidth number 300 属性面板宽度(px)
showControls boolean true 图层控制面板 + 工具栏图层按钮
showGroupInput boolean false 图层控制面板中的 group 切换输入框
showPropPanel boolean true 属性面板 + 工具栏属性按钮
showHighlightButton boolean false 工具栏高亮按钮
show3DButton boolean true 工具栏 3D 按钮
showFullscreenButton boolean true 工具栏全屏切换按钮(CSS 全屏,iframe 内可用,ESC 退出)
showClearMarksButton boolean true 工具栏清除临时标记按钮(清除查询高亮与业务高亮状态)
showBaseSwitcher boolean true 图层面板中的底图切换器
showTimeSlider boolean false 底部时间条
autoOpenPropPanel boolean true 选中要素后自动展开属性面板
themeColor string — 主题色(推荐 #RRGGBB,自动派生 hover/active/soft/glow)
theme 'dark' | 'light' 'dark' 主题模式

Emits

事件 参数 说明
map-ready (map) OL 实例初始化完成
feature-click (feature, layerName?) 点击要素(原始 OL Feature;取消选中时 feature 为 null)
selection-change (selection) 业务选中变化,{ otype, oname } 或 null(点击与程序化选中都会触发)
update:time (time) 时间变化(可用 v-model:time)
time-rendered (time) 随 time 刷新的图层本帧瓦片加载 + 渲染完成
fullscreen-change (fullscreen) 全屏状态变化
right-panel-change (width) 右侧面板占位宽度变化(供底部停靠区让位)
prop-chart-open (payload: { url, title }) propChartTarget = 'bottom' 时抛出:点击属性面板曲线按钮,或选中带默认曲线(属性配置 sections.chart 非空)的要素,外部据此打开/切换底部曲线面板

插槽(选择性替换内置 UI)

所有插槽均作用域下发控制器状态;不传时使用内置 UI。

插槽 作用域 说明
default { map, controller } 地图覆盖层
toolbar { is3D, toggle3D, isHighlighted, triggerHighlight, showLayerList, toggleLayerList, propPanelVisible, togglePropPanel } 右侧工具条
layerPanel { layers, visibleIds, setVisibleIds, group, changeGroup, loading, base, setBase, setLayerOpacity } 图层面板
propPanel { selection, feature, time, config, close } 属性面板
timeSlider { time, setTime } 时间条

用 #layerPanel / #propPanel 替换内置面板时,请把 layerPanelWidth / propPanelWidth 设为你自定义面板的实际宽度,right-panel-change 才能给底部停靠区正确的让位宽度。

插槽内容由父组件作用域编译,若在其中用 JS 读取主题(而非仅靠 CSS 变量级联),需从插槽作用域获取,或自行传入 themeColor / theme。

示例:只想要地图 + 自己的工具条,不要图层/属性面板:

<MapView
  group="FLOOD"
  :show-controls="false"
  :show-prop-panel="false"
  :show-3d-button="false"
>
  <template #toolbar="{ toggle3D, is3D }">
    <button @click="toggle3D">{{ is3D ? '2D' : '3D' }}</button>
  </template>
</MapView>

暴露的方法

const mapRef = ref<InstanceType<typeof MapView>>();

mapRef.value?.getMap();          // 原生 ol Map
mapRef.value?.fitExtent([minx, miny, maxx, maxy], 600);
mapRef.value?.triggerHighLight();
mapRef.value?.reloadLayers('WDM');
mapRef.value?.toggleFullscreen(); // 切换全屏 / 退出全屏
mapRef.value?.clearMarks();       // 清除临时标记(查询高亮 + 业务高亮状态)
mapRef.value?.controller;        // 完整控制器:状态 + 命令

用法二:只要逻辑(headless)

<script setup lang="ts">
import { useMapViewer } from 'lwx-wi-map/core';

const { targetRef, controller, map } = useMapViewer({
  group: 'FLOOD',
  time: () => timeline.value,          // 支持 值 / ref / getter
  timeLayerIds: ['flood_contour_mvt'],
  center: [121.49, 31.24],
  zoom: 10,
  onEvent: (evt) => {
    if (evt.type === 'feature-click') { /* ... */ }
    if (evt.type === 'time-rendered') { /* 推进播放下一帧 */ }
  },
});

// 命令
controller.setTime('2026-09-12 08:00:00');
controller.setVisibleIds(['flood_contour_mvt']);
controller.setBase('sat');
controller.toggle3D();
controller.fitExtent([...]);
await controller.triggerHighlight();
</script>

<template>
  <div style="position: relative; height: 100%">
    <div ref="targetRef" style="position: absolute; inset: 0" />
    <!-- 你自己的任意 UI,绑定 controller 的状态 -->
    <aside v-if="controller.selection.value">
      {{ controller.selection.value.otype }} / {{ controller.selection.value.oname }}
    </aside>
  </div>
</template>

useMapViewer(options) 选项

选项 类型 说明
layers / extent / group / time / timeLayerIds / center / zoom / base / stylePlugins 值 | Ref | () => 值 响应式来源,变化时自动同步到控制器
highlightDimOpacity 值 | Ref | () => 值 高亮置暗倍数(默认 0.25,传 1 不置暗)
onEvent (event: MapViewerEvent) => void 同 MapView 的事件

返回 { targetRef, controller, map }。targetRef 绑定到容器后组件挂载时自动初始化并在地图卸载时销毁。

MapController 状态与命令

状态(均为 Vue ref):map、layers、layersLoading、visibleLayerIds、currentTime、is3D、currentBase、isHighlighted、selection、selectedFeature、selectedLayerName、propViewConfig、group、extent、queryHighlight、queryHighlightLoading、alarmed、alarmPhase。

命令:mount、destroy、getMap、setLayers、setExtent、setGroup、setTime、setTimeLayerIds、setStylePlugins、setVisibleIds、setLayerOpacity、setHighlightDimOpacity、setBase、toggle3D、set3D、reloadLayers、fitExtent、triggerHighlight、setHighlights、setQueryHighlight、setSelection、clearMarks、setAlarms、clearAlarms。

选中态样式:仅对点、线要素生效(面要素不应用)——按 otype:oname 匹配后放大 2 倍(圆点半径 ×2、字体图标字号 ×2、线描边宽度 ×2),统一青色 + 白描边,zIndex 高于高亮;点击空白取消。程序化设置选中用 controller.setSelection({ otype, oname })(直接改 selection.value 不会触发重绘)。悬停可拾取要素时光标自动变 pointer。

查询高亮:setQueryHighlight({ url })(或 { queryId })拉取 /busigis/getBusiHighLightPdb 返回的 protobuf otype:oname 命中列表,命中要素由高亮叠加层以高亮色重绘、未命中要素整体压暗(默认 0.25 不透明度,可用 highlightDimOpacity 调整);clearMarks() 清除查询高亮与业务高亮状态。宿主自带高亮数据时(如连通性分析结果)用 setHighlights(keys) 直接设置命中键,键格式同报警('otype:oname' 字符串或 { otype, oname } 对象,全量替换,空数组即清除)。

MapController 可脱离 Vue 组件单独 new 并手动 mount(el) / destroy()。

图层样式插件

需要整层接管某类图层的渲染(例如把某类图层全部改成自定义样式):

import { Style, Stroke } from 'ol/style';
import type { LayerStylePlugin } from 'lwx-wi-map/core';

const plugins: LayerStylePlugin[] = [
  (layer) =>
    layer.type === 'TAIFENG'
      ? (feature) => new Style({ stroke: new Stroke({ color: '#f00', width: 4 }) })
      : undefined,
];

// MapView 用 <MapView :style-plugins="plugins" />
useMapViewer({ group: '气象监测', stylePlugins: plugins });

插件优先于基础样式链(legend > draw_style > 默认),命中即接管该图层。

插件 / 类型钩子返回的是 Canvas Style 函数,WebGLVectorTileLayer 只接受 flat style, 无法表达任意 JS 样式逻辑,因此被插件或钩子接管的图层会自动回退 Canvas 渲染, 其余 MVT 图层默认走 WebGL(GPU)。两种模式的高亮 / 选中 / 报警行为一致(见下一节)。

MVT 渲染:WebGL(GPU)+ 高亮叠加层

MVT(type 非 WMS)图层默认使用 OpenLayers 的 WebGLVectorTileLayer 渲染, 点 / 线 / 面 / 字体图标 / 图例分档都由 flat style 表达:

数据 GPU 样式
点 circle-*(draw_style.pcolor / psize)
字体图标 draw_style.logo 先在主线程栅格化成图片,再用 icon-src / icon-width / icon-height 绘制
线 stroke-*(lcolor / lsize)
面 fill-*(pcolor)+ stroke-*(lcolor / lsize)
图例 按 legend.column 用 Rule.filter 表达式分档(首命中取色,末档兜底)

图标为什么不用 text-*:WebGL 矢量瓦片的文字由 Worker 里的 OffscreenCanvas 绘制,而 Worker 的 self.fonts 不包含页面 @font-face 注册的图标字体(实测 self.fonts.size === 0), 走文字通道只会画出后备字形(方块)。因此改为「canvas 栅格化 → icon-src」, 图标字体加载完成后会清空栅格化缓存并按新字体重建 GPU 样式(字体未就绪时画的图不进缓存); 图标贴图解码完成后会通过 onIconImageReady 通知控制器补一次重绘(不再依赖固定延时)。

图例列必须是数值类型:GPU 路径在瓦片加载时把 legend.column 归一化到内部属性 __wi_legend_num__<column>(字符串型数值会转成数字,缺失 / 非数值写 NaN → 落到末档兜底色), 与 Canvas 路径 Number() 的口径一致。该内部属性不会出现在属性面板里。

临时态(选中 / 多选 / 分析高亮 / 业务高亮 / 报警闪烁)不再改写底图样式:每个 MVT 图层额外挂一个 Canvas 叠加层(共用同一个 VectorTileSource,瓦片只请求 / 解析一次),只把命中要素画在最上面。

  • 叠加层不参与拾取:点击命中的始终是底层业务图层,高亮图形不会挡住点击; 没有临时态时叠加层直接隐藏,不产生逐帧开销。
  • 叠加层按图层收敛显隐:MvtTileIndex 在瓦片加载时记录各图层出现过的 otype,只有可能包含 当前临时态要素的图层才显示叠加层(其余图层不参与样式求值)。要素可能在未加载区域、 或图层是 Canvas 回退时,保守地显示全部叠加层。
  • 叠加层统一放在固定层级(业务图层之上、测量 / 绘制图层之下),不按图层顺序与业务图层交错: OL 会给 WebGL 图层按渲染顺序分配画布,一旦中间夹了 Canvas 叠加层,每个 MVT 图层就会各占一个 WebGL context(实测 20 层时有 4 个 context 被浏览器丢弃、图层变黑)。因此排在后面的业务图层 仍可能被高亮覆盖,需要严格控制叠放顺序时请用 WMS / 图层分组,而不是依赖高亮层级。
  • 高亮置暗改为「压低底图图层不透明度」(默认 0.25,可用 highlightDimOpacity / setHighlightDimOpacity() 运行时调整),叠加层保持原不透明度, 视觉上等价于原来的「命中要素高亮 + 其余置暗」,但不再逐要素改颜色。
  • GPU 图层没有逐要素查询接口,拾取按几何自行计算(点顶点 / 点到线段 / 面包含 + 边界), 容差 6 CSS 像素,同级点击按「点 > 线 > 面」取,报警要素仍然优先; 瓦片层级与渲染器使用同一个 source.zDirection(否则小数缩放时拾取层级和屏幕层级会不一致), 瓦片按层级分桶、悬停时只遍历当前层级(及回退层级), 每个瓦片按要素包围盒建一次网格索引并缓存,悬停时只测少量候选要素; wrapX 场景下点击坐标先折叠回规范世界,否则世界副本里的点击会全部落空。
  • 图层重建 / 销毁时会显式 dispose() WebGL 图层,避免 WebGL context 泄漏。
  • 环境不支持 WebGL 时自动整体回退 Canvas 渲染。

内置样式链会保留图层原有图形结构:高亮命中的要素在原图标/圆点基础上换成高亮色,保留字体图标。

属性面板:属性视图配置接口失败(未登录 / 无权限)或该 otype 未配置时,面板会退回展示要素自带的 原始属性(过滤 geometry / 内部归一化属性等);要素本身没有业务属性时给出一条可读提示, 而不是只显示「未获取到属性配置」。

按图层类型注册样式钩子

地图包不内置任何业务类型样式,由宿主按需注册。适合「只覆盖某类图层的部分要素,其余回退内置样式链」的场景(如台风路径线):

import { registerLayerStyleHook } from 'lwx-wi-map';
import { Style, Stroke } from 'ol/style';

// 只对匹配要素返回样式,返回 undefined 继续走内置样式链
registerLayerStyleHook('MY_TYPE', (feature, layer) => {
  if (feature.getGeometry()?.getType() === 'LineString') {
    return new Style({ stroke: new Stroke({ color: '#ff0', width: 3 }) });
  }
  return undefined;
});

// 不再需要时移除
registerLayerStyleHook('MY_TYPE', null);

钩子优先级高于用户插件。stylePlugins 为整层接管,registerLayerStyleHook 适合按要素类型的局部覆盖。

报警闪烁

业务要素报警闪烁(点 / 线 / 面通用):硬闪两相位(亮 / 暗各 500ms),样式链最优先(报警 > 选中 > 高亮 > 基础),报警色默认 #FF3B30,可用 configureMapApi({ alarmStyle: { color } }) 定制。

const controller = mapRef.value?.controller;

controller.setAlarms(['Station:S001', { otype: 'Pipe', oname: 'P002' }]); // 开始闪烁('otype:oname' 或对象)
controller.clearAlarms(); // 停止

controller.alarmed.value; // 是否闪烁中(响应式,可联动外部红点 / 提示音)

行为细节:

  • 数据来源由宿主决定(WebSocket 推送 / REST 轮询均可),包内只负责命中与闪烁渲染;命中按要素属性 otype + oname(大小写兼容),与高亮机制同键
  • 报警要素所在图层自动置顶:即使该图层藏在图层列表底部、被其他图层盖住,报警时也会提升其 zIndex,清除报警后恢复原层级
  • 报警优先拾取:重叠点击时哪怕报警要素被其他要素盖住,也优先点中报警要素;点击报警要素照常走选中流程(属性面板展开),但样式保持闪烁
  • 相位由内部定时器驱动(仅在存在报警时运行,清空即停表),无报警时零开销
  • 限制:报警要素须位于 MVT 图层;WMS 栅格图层无法逐要素闪烁
  • 独立验证闪烁效果:createAlarmBlinkTest(map) 在地图中心放一组点(圆点 + 字体图标)/ 线 / 面测试要素,复用同一套报警样式与节奏,返回清理函数
import { createAlarmBlinkTest } from 'lwx-wi-map';

const stop = createAlarmBlinkTest(map, { interval: 500, size: 24 }); // 中心开始闪烁
stop(); // 清除

用法三:可选装配「功能菜单」

左侧功能菜单不内置在 MapView 中,由使用方按需装配:createFeatureMenu() 创建注册表 → 注册菜单项 → 渲染 MapFeatureMenu(菜单)与 MapFeaturePanel(面板外框)。不注册、不渲染就没有该功能。

<script setup lang="ts">
import { computed } from 'vue';
import { MapView, MapFeatureMenu, MapFeaturePanel, createFeatureMenu, type MapFeatureMenuItem } from 'lwx-wi-map';

const menu = createFeatureMenu();

const items: MapFeatureMenuItem[] = [
  { id: 'home', label: '首页', icon: 'home' },
  { id: 'stats', label: '自定义统计', icon: 'chart-bar', group: '对象统计',
    panel: { mode: 'side', width: 380 } },                    // 点击展开右侧停靠面板
  { id: 'pipe', label: '管线专题图', icon: 'chart-line', group: '管线专题',
    panel: { mode: 'overlay', component: MyOverlay } },       // 覆盖整个地图区域
  { id: 'analysis', label: '数据分析', icon: 'chart-box-outline',
    onSelect: (item) => console.log(item.id) },               // 纯动作按钮(无 panel)
];

const unregister = menu.register(items); // 注册;返回反注册函数,可在 onUnmounted 清理

const activePanel = computed(() => menu.activeItem.value?.panel ?? null);
// side:贴菜单右侧停靠;overlay:从菜单右侧铺满地图区域
const dockStyle = computed(() =>
  activePanel.value?.mode === 'overlay'
    ? { left: '156px', right: '0' }
    : { left: '156px', width: `${activePanel.value?.width ?? 360}px` },
);
</script>

<template>
  <div class="relative h-full">
    <MapView group="FLOOD" />
    <MapFeatureMenu :menu="menu" :width="148" />
    <!-- 面板外框定位由使用方决定;仅在存在激活面板时渲染,避免遮挡地图交互 -->
    <div v-if="activePanel" class="absolute top-0 bottom-0" :style="dockStyle">
      <MapFeaturePanel :menu="menu" position="static" />
    </div>
  </div>
</template>

菜单项字段(MapFeatureMenuItem)

字段 类型 说明
id string 唯一标识(重复注册即覆盖更新)
label string 显示名
icon string mdi 图标名(不含 mdi: 前缀)
group string 分组名(同名归入可折叠分组;缺省排在无分组散排区)
order number 排序权重(小在前;同权重按注册顺序)
disabled boolean 禁用
panel MapFeaturePanelConfig 点击后打开的面板:mode('side' 停靠 / 'overlay' 覆盖地图)、width、title、component、props;缺省时作为纯动作按钮(点击仅高亮选中并收起面板,不打开内容)
onSelect (item) => void 点击回调(与 panel 可同时使用,先切换面板再回调)

说明

  • 面板外框(标题栏 + 关闭按钮 + 内容区)由 MapFeaturePanel 提供;panel.component 缺省时只渲染外框占位,具体内容由使用方接入。
  • MapFeaturePanel 传 keep-mounted 时,面板关闭(最小化)仅 v-show 隐藏、内容组件不卸载,重开同一面板还原内部状态(查询条件 / 结果等);缺省关闭即卸载。
  • 注册表命令:register / unregister / select(id | null) / toggle(id) / close();状态:items / activeId / activeItem。
  • 后代组件可用 provideFeatureMenu(menu) / useFeatureMenu() 读写注册表(均为纯逻辑,出自 lwx-wi-map/core)。
  • 菜单项 icon 由数据传入,UnoCSS 静态提取不到,宿主需把用到的 icon-mdi:xxx 加入图标 safelist(参见 example/vite.config.ts)。

用法三·一:对象统计一键装配(useObjectStatsMenu)

「自定义统计 + 各 otype 统计」是包内置面板(ObjectStatsPanel,走 /busigis/getSearchOtypeList、searchOtypeValues、searchOtypeValuesPDB、searchOtypeValuesSummary),useObjectStatsMenu 负责注册整组菜单并在分组变化时重拉:

import { useObjectStatsMenu, type MapController } from 'lwx-wi-map';

const analysisProps = shallowReactive<{ controller: MapController | null; layerGroup: string }>({
  controller: null,      // 地图就绪后由宿主填充
  layerGroup: '智慧管网',
});
const unregisterStats = useObjectStatsMenu(menu, {
  props: analysisProps,        // 面板共享 props(shallowReactive,controller/layerGroup 变化自动跟随)
  layerGroup: '智慧管网',       // string / Ref<string> / () => string
  group: '对象统计',            // 菜单分组名,缺省「对象统计」
  order: 10,                   // 排序基准:自定义统计 = order,各 otype 项依次 +1
  width: 470,                  // side 面板宽度,缺省 470
});
onUnmounted(() => unregisterStats());
  • 菜单结构:最前为「自定义统计」(面板内选择 otype、自组条件),其后为 otype 列表展开的各「XX统计」(固定条件区)。
  • 面板能力:空间范围(全局 / 当前视图 / 矩形框选,矩形走 controller.startRectDraw)、固定过滤 / 自组条件、查询明细表格 + 分页(searchOtypeValues)、汇总柱状图(searchOtypeValuesSummary)、高亮(searchOtypeValuesPDB → controller.setHighlights,改命中要素自身颜色)与行定位(controller.showLocationMarker 统一定位)。
  • otype 列表按 layerGroup 模块级缓存(fetchOtypeStatList),菜单与面板共用一次请求;clearOtypeStatListCache() 可强制失效。

主题定制

组件方式

<!-- 内置深色,主色改为绿色 -->
<MapView group="FLOOD" theme-color="#00b96b" />

<!-- 浅色 -->
<MapView group="FLOOD" theme="light" />

<!-- 浅色 + 绿色 -->
<MapView group="FLOOD" theme="light" theme-color="#00b96b" />

独立使用某个组件(如 MapChartPanel)时也可传 themeColor / theme:

<MapChartPanel otype="Station" :oname="id" theme="light" theme-color="#00b96b" />

CSS 变量方式

内置 UI 只使用下列变量,可在任意容器覆盖:

.my-map-container {
  --wi-map-primary: #00b96b;
  --wi-map-primary-hover: #1fd18a;
  --wi-map-primary-active: #009957;
  --wi-map-primary-soft: rgba(0, 185, 107, 0.16);
  --wi-map-primary-glow: rgba(0, 185, 107, 0.35);
}

theme-color 会在 JS 侧由单个色值自动派生 hover / active / soft / glow,无需手写。

其余语义变量(--wi-map-panel-bg、--wi-map-panel-text、--wi-map-chart-border、--wi-map-btn-bg …)定义在 src/styles/theme.css,默认深色;根元素加 wi-map-light class 切换浅色。自定义组件主题时:

import { useMapThemeBindings } from 'lwx-wi-map';

const { theme, themeClass, themeStyle } = useMapThemeBindings({
  mode: () => 'light',        // 或继承父级
  color: () => '#00b96b',
});

teleport 到 body 的弹层(el-dialog / el-popover)无法继承容器 CSS 变量,需把 themeClass / themeStyle 同样绑到弹层元素上(内置组件已处理)。


内置组件

均从 lwx-wi-map 导出,可单独使用:

组件 说明
MapView 完整地图(逻辑 + 内置 UI 壳)
LayerList 图层树 + 图例 + 透明度 + 底图切换
PropPanel 属性面板(含曲线弹窗入口)
ChartDialog 曲线弹窗(teleport)
MapChartPanel 过程曲线面板(图表 / 列表、日期区间、多日对比)
TimeSlider 时间条
MapToolBar / MapToolButton 工具条容器 / 按钮
MapIcon 内置 mdi 图标
MapFeatureMenu 功能菜单(可选装配,配合 createFeatureMenu 使用)
MapFeaturePanel 功能菜单面板外框(side 停靠 / overlay 覆盖地图)
HorizontalSectionPanel / VerticalSectionPanel 横 / 纵断面分析面板(依赖 echarts)
ValveClosingPanel 爆管关阀分析面板

示例

example/ 内是四个可直接运行的示例:

  • full-ui.vue:全部使用内置 UI(<MapView>),mock 后端
  • custom-ui.vue:完全自定义 UI,只复用 useMapViewer() 与业务 API,mock 后端
  • bottom-chart.vue:底部曲线模式,mock 后端
  • feature-menu.vue:可选装配功能菜单与分析面板,接真实后端并需配置 wisession
pnpm example   # http://localhost:5180

详见 example/README.md。

底图

import { BASE_MAPS, DEFAULT_BASE_KEY, type BaseMapKey } from 'lwx-wi-map/core';
// BaseMapKey: 'vec' | 'cva' | 'sat' | 'satc' | 'ter'

开发

pnpm build              # vite 构建 + vue-tsc 生成 d.ts
pnpm build:js           # 仅 JS
pnpm build:types        # 仅类型
pnpm dev                # watch 构建
pnpm type-check         # 源码类型检查
pnpm example            # 启动示例(http://localhost:5180)
pnpm example:type-check # 示例类型检查

产物:

  • dist/index.js + dist/style.css:完整组件入口
  • dist/core.js:纯逻辑入口(不含 Element Plus / ECharts / CSS)

目录结构

src/
├── core/            # 纯逻辑:无 UI、无 Element Plus、无 echarts、无 CSS
│   ├── controller.ts    # MapController:图层/底图/时间/拾取/高亮/3D
│   ├── useMapViewer.ts  # headless composable
│   ├── featureMenu.ts   # 功能菜单注册表(可选装配)
│   ├── baseTiles.ts     # 底图配置(唯一事实来源)
│   ├── styles.ts        # 图层样式函数 + 插件机制
│   ├── picking.ts       # 要素拾取(含 3D 矩阵补偿)
│   ├── tiles.ts         # 瓦片加载等待
│   └── types.ts
├── components/      # UI 层:只依赖 core + CSS 变量
│   ├── MapFeatureMenu.vue   # 左侧功能菜单(可选装配)
│   └── MapFeaturePanel.vue  # 功能菜单面板外框(可选装配)
├── api/             # adapter(宿主注入)+ busigis 业务接口
├── styles/theme.css # --wi-map-* 主题变量
├── styles/ywiconfont/   # 内置 ywifont 字体图标(@font-face + 图标名→码点,随 style.css 发布)
└── theme.ts         # 主题上下文 / 变量派生

Related Packages

my-openlayer

my-openlayer 是一个基于 OpenLayers 的现代地图组件库,专为 Web GIS 应用开发者设计...

9,722 9
dnn-vue-ol

基于 openlayers 的二次封装

1,272
zc-map

缩放到地块范围的时候控制最大级别为8

6,884
zc-3d-map

地图私有库

788
ol-map-vue3

Vue3基于openLayers封装的地图组件库

999 1

Version History

Version Released License
0.10.0 MIT
0.9.2 MIT
0.9.1 MIT
0.9.0 MIT
0.8.0 MIT