@roland0521/map-scene-vue

Reusable Vue label runtime and skins for map-scene (mapvthree DOMOverlay + Teleport host). Shared by digital-sand-table and map-scene-designer.
525
Install
npm install @roland0521/map-scene-vue
Latest Version:0.1.2
Vue:3
License:MIT
Last Updated:Oct 9, 2026
Links: npm
Maintainer: roland~

@roland0521/map-scene-vue

跨项目共用的地图标签运行时与皮肤组件库。运行时基于 mapv-three DOMOverlay + 单一宿主 Vue app + Teleport 投射,与 @roland0521/map-scene-sdk 的 marker-batch 渲染契约对接。

被 digital-sand-table(沙盘)与 map-scene-designer(场景编辑器)共同以正式包入口引用;本地联调可通过 alias 或 workspace/link 指向同一份 dist。

分层

src/
  runtime/    机制:宿主、渲染工厂、注册表、聚合工具、zoom 注入
  skins/      皮肤:标签容器与默认卡片,自包含样式,支持 props/样式覆盖
  index.ts    公共 API 桶文件
  • runtime 与 skins 是纯逻辑/纯展示,可安全共用。
  • 业务卡片(带数据请求、领域类型、Element Plus 的,如 ResourceCard/ProductCard/LandCard)不内置,由各项目启动时经 registerLabelCard 注入。

用法

0. 引入公共样式

import "@roland0521/map-scene-vue/style.css";

1. 配置宿主(可选)

皮肤与机制本身不依赖任何 UI 库。若你的业务卡片用了 Element Plus(如 el-image/el-dialog),需在挂载任何 label 前把安装器注入宿主 app:

import { configureLabels } from "@roland0521/map-scene-vue";
import { installElementPlus } from "@/plugins/elementPlus"; // 你项目的安装器

configureLabels({ setupHostApp: installElementPlus });

不依赖 UI 库的项目(如 designer)可不调用。

2. 注册业务卡片(可选)

import { registerLabelCard } from "@roland0521/map-scene-vue";
import ResourceCard from "@/components/ResourceCard.vue";

registerLabelCard("resourcecard", ResourceCard);
// 未注册/缺失 type 时,容器回退到库内置的精简 ConfiguredBaseCard。

3. 纯 JSON Label 配置

Designer 和生产项目共享 marker-batch 对象,表现配置放在 properties.mapSceneVue。这里不保存 Vue 组件、函数、任意 CSS/HTML 或接口地址:

import {
  createDefaultVueLabelObject,
  validateVueLabelObject,
  type VueLabelDefinition,
} from "@roland0521/map-scene-vue";

const object = createDefaultVueLabelObject("resource");
object.properties = {
  mapSceneVue: {
    schemaVersion: 1,
    shell: "zoom",
    preset: "resource",
    bindings: {
      name: { path: "resource.name" },
      area: { path: "resource.area", format: "number", defaultValue: 0 },
    },
    appearance: { accentColor: "#1ff6bc", fontSize: 14 },
    interaction: {
      splitZoom: 15,
      expand: "click",
      actionId: "carrier.open-detail",
      actionPayload: { id: "resource.id" },
    },
  } satisfies VueLabelDefinition,
};

if (!validateVueLabelObject(object).valid) throw new Error("invalid Vue Label object");

旧的 contentType / extraInfo.type 定义可以通过 migrateVueLabelDefinition 迁移; toLegacyLabelLayerDef 只在运行时生成兼容旧业务卡片的适配器。

4. 生成图层渲染工厂并接入 SDK

import { createLabelRenderFeature, markerFeatureRenderers } from "@roland0521/map-scene-vue";

markerFeatureRenderers[layerId] = createLabelRenderFeature({
  contentType: "base-zoomlabel",
  extraInfo: { type: "resourcecard", splitZoom: 14 },
  pickInfo: (properties) => properties.resource ?? properties,
});
// 把同一个 markerFeatureRenderers 引用传给 createMapScene({ markerFeatureRenderers })

如果场景对象已经携带 properties.mapSceneVue,推荐直接使用组合入口。它会在 updateScene、addObject、updateObject、removeObject 和 destroy 时同步 renderer 注册表,SDK 仍然负责地图生命周期:

import { createVueMapScene } from "@roland0521/map-scene-vue";

const controller = createVueMapScene(container, scene, {
  actions: {
    "carrier.open-detail": async (payload, { signal }) => {
      await openCarrierDetail(String(payload.id), { signal });
    },
  },
});

action runner 会把字段路径解析为 payload,自动处理 loading 状态 (data-map-scene-action-loading / aria-busy)、错误状态、重复点击去重、 AbortSignal 和 marker 销毁取消。业务项目只注册真实 handler,Designer 只注册 mock handler。

Designer 可按需使用 @roland0521/map-scene-vue/designer 子入口,获取预设元数据、 示例 features 和 mock actions;这些内容不进入生产运行时入口,也不会写入 Scene JSON。

5. 群组 Label(DOM + Three.js)

group-label 是 SDK 原生场景对象:SDK 负责 Group 862/854 地面特效、聚合、zoom 和销毁;本包只负责 Group 861/849 Vue 皮肤。Designer 导出的对象可原样交给生产项目:

import { createDefaultGroupLabelObject } from "@roland0521/map-scene-vue";

const station = createDefaultGroupLabelObject("transport-station");
station.bindings = {
  title: "properties.name",
  subtitle: "properties.distanceText",
  featureId: "id",
};
station.label = {
  ...station.label,
  // 默认值也可以直接输入 HTTP(S) 或站内相对 URL 替换。
  backgroundAsset: "group849-default",
  icon: { url: "group849-default-icon", width: 52, height: 52, gap: 6 },
  width: "auto",
  height: "auto",
};

内置两个受控预设:

preset DOM 皮肤 Three.js 地面特效
industrial-park Figma Group 861 group862-industrial
transport-station Figma Group 849(双行文字 + 左侧 icon) group854-transport

新配置统一写在 groundEffect 下;旧 Scene JSON 的顶层 pyramid、 ellipse1915/1913/1914 仍由 SDK 兼容读取。开启 polymerization 后,四个 Three.js 部件共用 GeoInstancedMesh,DOM 只保留每个聚合簇的代表标签。

与 SDK 的私有契约(重要)

本库依赖以下 @roland0521/map-scene-sdk 的非公开但稳定的契约。升级 SDK 时需确认这些约定未变:

  • markerFeatureRenderers:SDK 的 marker-batch 渲染器不读 config.renderFeature,而是从 CreateMapSceneOptions.markerFeatureRenderers[config.id] 按图层 id 取工厂。使用方须把本库导出的同一个 markerFeatureRenderers 对象引用传给 SDK。
  • __mapSceneFeatureCleanup:渲染工厂把卸载函数挂在返回的 marker DOM 的 __mapSceneFeatureCleanup 属性上,SDK dispose 该 marker 时调用以卸载对应 Vue 组件。
  • 聚合注入字段:SDK 聚合后在代表 feature 的 properties 上注入 polymerizationCount: number 与 polymerizationChildren: Feature[]。本库 runtime/aggregate.ts 据此归一化成员。
  • data-map-scene-object-id:SDK 在 marker 根 DOM 上设置该属性,皮肤容器用 closest("[data-map-scene-object-id]") 找到宿主 marker 以切换 is-on-front 提层。

皮肤组件

组件 说明
BaseLabel 通用展开容器(深色背景 + 左强调条),theme 可覆盖背景/强调色
BaseZoomLabel 带 splitZoom 的容器,zoom 过阈值切换 zoomType
BaseBackgroundLabel 背景图容器(boxWidth/boxHeight/imgUrl/name)
PopupLabel 简单按钮容器(fontColor/fillColor/borderColor/width)
AggregateMemberList 聚合展开态左侧成员列表
ConfiguredBaseCard 库内置默认卡片(注册表兜底,不含业务依赖)
PinLabel 紧凑"图钉标签"(左 icon + 右文字 + 背景色),供 designer 的 pin-label 对象用
GroupLabel Figma Group 861 产业园单行标签
TransportStationGroupLabel Figma Group 849 交通站点双行标签,背景与 icon URL 可替换、尺寸由内容撑开

所有皮肤自包含样式(plain CSS + 组件内 CSS 变量),不依赖宿主全局 scss 变量或 Element Plus 主题;视觉参数经 props / theme / info.* 注入。

类型检查

pnpm typecheck   # vue-tsc --noEmit
pnpm build       # Vite library + declaration output
pnpm test:dist   # import the generated ESM entry

产物位于 dist/,vue 与 @roland0521/map-scene-sdk 保持为 peerDependency,不会被打包进库。

场景销毁时 SDK 的 marker cleanup 会自动回收共享 Vue host;如宿主应用需要显式清理空闲 host,可调用 destroyLabelHost()。

Related Packages

th-gis

gis公共组件

3,208
vue-float-label

Float label pattern for Vue.js

55,766 174
tg-map-vue3

封装 百度地图, Google地图, Here地图(未完成), Maptalks 的Vue3组件库

8,977
@akuno/vue-cesium

Vue 2.x components for CesiumJS.

968 1,917
agile-cesium

Vue 2.x components for CesiumJS.

420

Version History

Version Released Vue License
0.1.2 >=3.4.0 <4 MIT
0.1.1 >=3.4.0 <4 MIT
0.1.0 >=3.4.0 <4 MIT