UNPKG

gisviewer-vue3-arcgis

Version:

在应用中引入私服的包, 项目根目录下 新建文件 .npmrc 在 .npmrc 中对包源进行配置:

384 lines (383 loc) 12.4 kB
import l from "ol/Feature"; import { LineString as f, Point as d } from "ol/geom"; import C from "ol/layer/Vector"; import w from "ol/source/Vector"; import { Style as u, Stroke as m, Circle as S, Fill as y, Icon as x } from "ol/style"; import { toRaw as M } from "vue"; import N from "../../../stores/index.mjs"; import { getLineStyle as b } from "../style/line-style.mjs"; import { getPointStyle as I } from "../style/point-style.mjs"; const g = 13, p = 17; class T { /** * 构造函数 * @param map - OpenLayers 地图实例 */ constructor(e) { this.subSystemDataMap = /* @__PURE__ */ new Map(), this.zoomChangeListener = null, this.grayLineStyle = new u({ stroke: new m({ color: "rgba(200, 200, 200, 0.8)", width: 2 }) }), this.grayPointStyle = new u({ image: new S({ radius: 4, fill: new y({ color: "rgba(200, 200, 200, 0.8)" }), stroke: new m({ color: "rgba(150, 150, 150, 0.8)", width: 1.5 }) }) }), this.highlightState = null; const i = N.useAppDataStore; M( i.olMapInitializer ).subscribeClick( (r, s, o, n) => { this.mapClick(r, o); }, { triggerOnBlankClick: !0 } ), this.map = e, this.source = new w(), this.signalSystemLayer = new C({ source: this.source }), this.signalSystemLayer.set("id", "signal-system-layer"), this.map.addLayer(this.signalSystemLayer), this.setupZoomListener(); } mapClick(e, i) { if (e === "map-blank") { this.resetHighlight(); return; } if (e !== "sub-district-road" && e !== "sub-district-node") return; const { areaCode: t, subCode: r } = i; this.focusSubSystem(t, r), this.highlight({ areaCode: t, subAreaCode: r, nonHighlightMode: "gray" }); } /** * 设置 zoom 变化监听器 */ setupZoomListener() { let e = null; this.zoomChangeListener = () => { const i = this.map.getView().getZoom() ?? 0; if (e === null) { e = i; return; } (this.hasCrossedThreshold(e, i, g + 1) || this.hasCrossedThreshold( e, i, p )) && this.reRenderAllSubSystems(), e = i; }, this.map.getView().on("change:resolution", this.zoomChangeListener); } /** * 判断 zoom 是否跨越了指定阈值 * @param oldZoom - 旧的 zoom 值 * @param newZoom - 新的 zoom 值 * @param threshold - 阈值 * @returns 是否跨越阈值 */ hasCrossedThreshold(e, i, t) { const r = Math.floor(e), s = Math.floor(i); return r < t && s >= t || r >= t && s < t; } /** * 重新渲染所有已存储的子系统 */ reRenderAllSubSystems() { this.source.getFeatures().filter((i) => i.get("subCode") !== void 0).forEach((i) => { this.source.removeFeature(i); }), this.subSystemDataMap.forEach(({ subSystem: i, areaCode: t }) => { this.renderSubSystem(i, t); }); } /** * 计算点集的重心坐标 * @param points - 点坐标数组 [{x, y}, ...] * @returns 重心坐标 [x, y] */ calculateCentroid(e) { if (e.length === 0) return [0, 0]; const i = e.reduce((r, s) => r + s.x, 0), t = e.reduce((r, s) => r + s.y, 0); return [i / e.length, t / e.length]; } /** 根据区控和子区编码查找子区 */ findSubSystem(e, i) { if (!i) return null; for (const { subSystem: t, areaCode: r } of this.subSystemDataMap.values()) if (t.subAreaCode === i && (!e || (r || "") === e)) return t; return null; } /** 聚焦子区:优先保证可见所有路口 */ focusSubSystem(e, i) { const t = this.findSubSystem(e, i); if (!t) return; const r = this.getSubSystemCrossExtent(t); if (r) { this.map.getView().fit(r, { padding: [80, 80, 80, 80], maxZoom: 17, duration: 350 }); return; } const s = this.getSubSystemCenter(t); s && this.map.getView().animate({ center: s, zoom: 17, duration: 350 }); } /** 计算子区路口范围,确保地图能看到所有路口 */ getSubSystemCrossExtent(e) { if (!e.children || e.children.length === 0) return null; let i = 1 / 0, t = 1 / 0, r = -1 / 0, s = -1 / 0; return e.children.forEach((o) => { const n = Number(o.x || o.lon), a = Number(o.y || o.lat); Number.isNaN(n) || Number.isNaN(a) || (i = Math.min(i, n), t = Math.min(t, a), r = Math.max(r, n), s = Math.max(s, a)); }), i === 1 / 0 || t === 1 / 0 || r === -1 / 0 || s === -1 / 0 ? null : [i, t, r, s]; } /** 根据子区数据计算中心点 */ getSubSystemCenter(e) { if (e.children && e.children.length > 0) { const i = e.children.map((t) => { const r = Number(t.x || t.lon), s = Number(t.y || t.lat); return { x: r, y: s }; }).filter((t) => !Number.isNaN(t.x) && !Number.isNaN(t.y)); if (i.length > 0) return this.calculateCentroid(i); } if (e.subShape) { let i; typeof e.subShape == "string" ? i = JSON.parse(e.subShape) : i = e.subShape; let t = 1 / 0, r = 1 / 0, s = -1 / 0, o = -1 / 0; if (i.forEach((n) => { n.forEach((a) => { const [h, c] = a; typeof h != "number" || typeof c != "number" || (t = Math.min(t, h), r = Math.min(r, c), s = Math.max(s, h), o = Math.max(o, c)); }); }), t !== 1 / 0 && r !== 1 / 0 && s !== -1 / 0 && o !== -1 / 0) return [(t + s) / 2, (r + o) / 2]; } return null; } showSignalSystem(e) { e.areaList.forEach((t) => { this.showSystem(t); }); const i = this.source.getExtent(); return i && i[0] !== 1 / 0 ? new Promise((t) => { this.map.getView().fit(i, { padding: [50, 50, 50, 50], callback: () => { t({ status: 0, message: "success" }); } }); }) : { status: 1, message: "No features to display" }; } removeSignalSystem(e) { if (!e) { this.source.clear(), this.subSystemDataMap.clear(), this.zoomChangeListener && (this.map.getView().un("change:resolution", this.zoomChangeListener), this.zoomChangeListener = null); return; } this.source.getFeatures().filter((t) => t.get("areaCode") === e).forEach((t) => { this.source.removeFeature(t); }), this.subSystemDataMap.forEach(({ subSystem: t, areaCode: r }) => { r === r && this.subSystemDataMap.delete(r + "-" + t.subAreaCode); }); } showSystem(e) { if (e.shape) { let i; typeof e.shape == "string" ? i = JSON.parse(e.shape) : i = e.shape; const t = b(e.lineSymbol, e), r = new l({ geometry: new f(i), areaCode: e.areaCode, type: "signal-system-boundary" }); r.setStyle(t), r.set("_originalStyle", t), this.source.addFeature(r); } e.children && e.children.forEach((i) => { this.showSubSystem(i, e.areaCode); }); } /** * 展示多个信号子区系统 * 遍历所有子区并渲染,完成后自动缩放地图视角以显示所有子区 * * @param params - 展示参数,包含子区列表 * @returns 操作结果 */ async showSubSignalSystem(e) { e.areaList.forEach((t) => { this.showSubSystem(t); }); const i = this.source.getExtent(); return i && i[0] !== 1 / 0 ? new Promise((t) => { this.map.getView().fit(i, { padding: [50, 50, 50, 50], callback: () => { t({ status: 0, message: "success" }); } }); }) : { status: 1, message: "No features to display" }; } /** * 移除信号子区系统 * 若不传 subCode,则清除所有子区;否则只清除指定子区 * * @param subCode - 可选,子区编码。不传则清除全部 */ removeSubSignalSystem(e) { if (!e) { this.source.clear(); return; } this.source.getFeatures().filter((t) => t.get("subCode") === e).forEach((t) => { this.source.removeFeature(t); }); } highlight(e) { if (e.areaCode) this.highlightState = { areaCode: e.areaCode, subAreaCode: e.subAreaCode, nonHighlightMode: e.nonHighlightMode || "hide", needZoom: e.needZoom || !1 }; else return { status: -1, message: "No areaCode provided" }; return this.reRenderAllSubSystems(), this.highlightState.needZoom && this.focusSubSystem(e.areaCode, e.subAreaCode), { status: 0, message: "ok" }; } resetHighlight() { this.highlightState = null, this.source.getFeatures().forEach((e) => { const i = e.get("_originalStyle"); e.setStyle(i); }), this.reRenderAllSubSystems(); } /** * 渲染单个信号子区系统 * 包括子区道路线和路口节点的渲染 * * @param subSystem - 信号子区系统数据 * @param areaCode - 区域编码,用于关联要素 */ showSubSystem(e, i) { const t = i + "-" + e.subAreaCode; this.subSystemDataMap.set(t, { subSystem: e, areaCode: i }), this.renderSubSystem(e, i); } /** * 根据当前 zoom 级别渲染子系统 * zoom <= 13: 显示重心图标(不显示道路和路口) * zoom >= 14: 显示 subShape 和 children * * @param subSystem - 子区系统数据 * @param areaCode - 区控编码 */ renderSubSystem(e, i) { const t = Math.floor(this.map.getView().getZoom() ?? 0); let r = !1; if (this.highlightState) { const s = this.highlightState.areaCode === i, o = !this.highlightState.subAreaCode || e.subAreaCode === this.highlightState.subAreaCode; if (!(s && o)) { if (this.highlightState.nonHighlightMode === "hide") return; r = !0; } } r && t <= g || (t <= g ? this.renderCentroidIcon(e, i) : this.renderSubSystemDetail(e, i, r)); } /** * 渲染子系统重心图标 * @param subSystem - 信号子区系统数据 * @param areaCode - 区域编码 */ renderCentroidIcon(e, i) { if (!e.children || e.children.length === 0) return; e.children.forEach((o) => { o.x = Number(o.x || o.lon), o.y = Number(o.y || o.lat); }); const t = this.calculateCentroid(e.children), r = new u({ image: new x({ src: "/GisViewerAssets/Images/gis/ic_zixitong.png", scale: 0.5, anchor: [0.5, 1] }) }), s = new l({ subCode: e.subAreaCode, areaCode: i || "", isCentroid: !0, // 标记为重心图标 geometry: new d(t), type: "signal-subsystem-centroid" }); s.setStyle(r), s.set("_originalStyle", r), this.source.addFeature(s); } /** * 渲染子系统详细信息(道路线和节点) * @param subSystem - 信号子区系统数据 * @param areaCode - 区域编码 */ renderSubSystemDetail(e, i, t = !1) { if (e.subShape) { let r; typeof e.subShape == "string" ? r = JSON.parse(e.subShape) : r = e.subShape; const s = t ? this.grayLineStyle : b(e.roadSymbol), o = r.map((n) => { const a = new l({ geometry: new f(n), subCode: e.subAreaCode, areaCode: i || "", type: "sub-district-road", selected: !t }); return a.setStyle(s), a.set("_originalStyle", s), a; }); this.source.addFeatures(o); } if (e.children) { const r = Math.floor(this.map.getView().getZoom() ?? 0), s = e.children.map((o) => { const n = o.symbol || e.nodeSymbol, a = t ? this.grayPointStyle : this.getNodeStyleByZoom(n, o, r), h = new l({ ...o, subCode: e.subAreaCode, areaCode: i || "", geometry: new d([o.x, o.y]), type: "sub-district-node", selected: !t }); return h.setStyle(a), h.set("_originalStyle", a), h; }); this.source.addFeatures(s); } } /** * 根据缩放层级获取路口节点样式 * 14 <= zoom < 17: 显示蓝色圆点 * zoom >= 17: 显示传入参数配置的 symbol * * @param symbol - 节点符号配置 * @param node - 节点数据 * @param zoom - 当前缩放层级 * @returns 样式对象 */ getNodeStyleByZoom(e, i, t) { return t >= p ? I(e, i) : new u({ image: new S({ radius: 4, fill: new y({ color: "#2563eb" }), stroke: new m({ color: "#ffffff", width: 1.5 }) }) }); } } export { T as default };