UNPKG

gisviewer-vue3-arcgis

Version:

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

439 lines (438 loc) 14.4 kB
import p from "ol/Feature"; import x from "ol/geom/LineString"; import C from "ol/geom/Point"; import N from "ol/layer/Vector"; import _ from "ol/source/Vector"; import { Style as F, Stroke as A, Icon as b, Circle as V, Fill as O, Text as W } from "ol/style"; class H { constructor(e) { this.hasGpu = !0, this.animationFrameIds = /* @__PURE__ */ new Map(), this.animatedArrows = /* @__PURE__ */ new Map(), this.nodeFeatures = /* @__PURE__ */ new Map(), this.zoomChangeKey = null, this.NODE_MIN_ZOOM = 14, this.NODE_ZOOM_THRESHOLD = 16, this.bandConfigs = /* @__PURE__ */ new Map(), this.centerIconFeatures = /* @__PURE__ */ new Map(), this.hiddenStyle = new F({}); const i = localStorage.getItem("gpu"); this.hasGpu = i !== "Unknown", this.map = e, this.mapView = this.map.getView(), this.source = new _(), this.bandLayer = new N({ source: this.source }), this.bandLayer.set("id", "green-wave-band-layer"), this.map.addLayer(this.bandLayer); } showGreenWaveBand(e) { var w; this.removeGreenWaveBand(e.bandId); const i = e.lineWidth || 4, t = this.parseColor(e.lineColor, [55, 125, 34, 1]), o = this.parseColor(e.arrowColor, [255, 255, 255, 1]), s = e.arrowDirection || "double", n = s === "double" ? 0 : e.animationSpeed ?? 0.2, r = e.needZoom || !1, h = e.lineOnly || !1; this.bandConfigs.set(e.bandId, { coordinates: e.coordinates, lineWidth: i, lineColor: t, arrowColor: o, arrowDirection: s, lineOnly: h, animationSpeed: n }); const c = (this.mapView.getZoom() || 0) >= this.NODE_MIN_ZOOM, l = new p({ geometry: new x(e.coordinates) }); if (l.set("bandId", e.bandId), l.set("type", "greenWaveBand"), l.set("id", e.bandId), h || c ? l.setStyle( new F({ stroke: new A({ color: t, width: i }) }) ) : l.setStyle(new F({})), this.source.addFeature(l), !h) { const u = this.calculateLineCenterPoint(e.coordinates), a = new p({ geometry: new C(u) }); a.set("bandId", e.bandId), a.set("type", "greenWaveBandCenterIcon"), a.set("id", `${e.bandId}_center`), c ? a.setStyle(new F({})) : a.setStyle(this.createCenterIconStyle()), this.source.addFeature(a), this.centerIconFeatures.set(e.bandId, a); } if (this.hasGpu && (n > 0 ? this.startFlowAnimation( e.coordinates, e.bandId, i, o, s, n ) : this.addArrowsAlongLine( e.coordinates, e.bandId, i, o, s )), h || this.ensureZoomChangeListener(), r) { const u = (w = l.getGeometry()) == null ? void 0 : w.getExtent(); u && this.mapView.fit(u, { padding: [50, 50, 50, 50] // duration: 500 }); } !h && e.nodeList && e.nodeList.length > 0 && this.addNodeFeatures(e.bandId, e.nodeList); } /** * 沿线添加箭头 */ addArrowsAlongLine(e, i, t, o, s) { if (e.length < 2) return; let n = 0; const r = []; for (let l = 0; l < e.length - 1; l++) { const w = e[l], u = e[l + 1], a = u[0] - w[0], m = u[1] - w[1], d = Math.sqrt(a * a + m * m); r.push({ start: w, end: u, length: d }), n += d; } if (n <= 0 || r.length === 0) return; const h = Math.max(r.length, 3), g = Math.min( Math.max(h, Math.floor(n / 1e-3)), 50 ); if (g <= 0) return; const c = n / (g + 1); for (let l = 1; l <= g; l++) { const w = c * l; let u = 0; for (const a of r) { if (u + a.length >= w) { const d = (w - u) / a.length, S = a.start[0] + (a.end[0] - a.start[0]) * d, I = a.start[1] + (a.end[1] - a.start[1]) * d, y = Math.atan2( a.end[1] - a.start[1], a.end[0] - a.start[0] ); this.addArrowFeature( [S, I], i, t, o, y, s ); break; } u += a.length; } } } /** * 添加箭头 Feature */ addArrowFeature(e, i, t, o, s, n) { const r = new p({ geometry: new C(e) }); r.set("bandId", i), r.set("type", "greenWaveBandArrow"), r.set("arrowLineWidth", t), r.set("arrowColor", o), r.set("arrowAngle", s), r.set("arrowDirection", n), (this.mapView.getZoom() || 0) < this.NODE_MIN_ZOOM ? r.setStyle(this.hiddenStyle) : r.setStyle( this.createArrowStyle(t, o, s, n) ), this.source.addFeature(r); } /** * 创建箭头样式 */ createArrowStyle(e, i, t, o = "double") { const s = e * 2, n = `${s * 0.18},${s * 0.3} ${s * 0.82},${s * 0.5} ${s * 0.18},${s * 0.7}`, r = `${s * 0.36},${s * 0.32} ${s * 0.12},${s * 0.5} ${s * 0.36},${s * 0.68}`, h = `${s * 0.64},${s * 0.32} ${s * 0.88},${s * 0.5} ${s * 0.64},${s * 0.68}`, g = ` <svg xmlns="http://www.w3.org/2000/svg" width="${s}" height="${s}" viewBox="0 0 ${s} ${s}"> <polyline points="${o === "double" ? h : n}" fill="none" stroke="${i}" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" /> ${o === "double" ? `<polyline points="${r}" fill="none" stroke="${i}" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" />` : ""} </svg> `, c = "data:image/svg+xml;charset=utf-8," + encodeURIComponent(g); return new F({ image: new b({ src: c, scale: 1, rotation: -t, // 调整旋转方向 rotateWithView: !1 }) }); } /** * 计算折线的中点坐标 */ calculateLineCenterPoint(e) { if (e.length === 0) return [0, 0]; if (e.length === 1) return e[0]; let i = 0; const t = []; for (let n = 0; n < e.length - 1; n++) { const r = e[n], h = e[n + 1], g = h[0] - r[0], c = h[1] - r[1], l = Math.sqrt(g * g + c * c); t.push({ start: r, end: h, length: l }), i += l; } const o = i / 2; let s = 0; for (const n of t) { if (s + n.length >= o) { const h = (o - s) / n.length, g = n.start[0] + (n.end[0] - n.start[0]) * h, c = n.start[1] + (n.end[1] - n.start[1]) * h; return [g, c]; } s += n.length; } return e[e.length - 1]; } /** * 创建中点图标样式 */ createCenterIconStyle() { return new F({ image: new b({ src: "/GisViewerAssets/Images/gis/ic_gxlb.png", scale: 0.8, anchor: [0.5, 1] }) }); } /** * 解析颜色值 */ parseColor(e, i) { if (!e) return `rgba(${i.join(",")})`; if (typeof e == "string") return e; if (Array.isArray(e)) { if (e.length === 3) return `rgba(${e[0]},${e[1]},${e[2]},1)`; if (e.length === 4) { const t = e[3] > 1 ? e[3] / 255 : e[3]; return `rgba(${e[0]},${e[1]},${e[2]},${t})`; } } return `rgba(${i.join(",")})`; } removeGreenWaveBand(e) { e ? (this.stopFlowAnimation(e), this.removeNodeFeatures(e), this.bandConfigs.delete(e), this.centerIconFeatures.delete(e), this.source.getFeatures().filter( (t) => t.get("bandId") && t.get("bandId") === e ).forEach((t) => { this.source.removeFeature(t); })) : (this.animationFrameIds.forEach((t, o) => { cancelAnimationFrame(t); }), this.animationFrameIds.clear(), this.animatedArrows.forEach((t) => { t.forEach((o) => { this.source.removeFeature(o); }); }), this.animatedArrows.clear(), this.nodeFeatures.forEach((t) => { t.forEach((o) => { this.source.removeFeature(o); }); }), this.nodeFeatures.clear(), this.bandConfigs.clear(), this.centerIconFeatures.clear(), this.zoomChangeKey && (this.mapView.un("change:resolution", this.onZoomChange.bind(this)), this.zoomChangeKey = null), this.source.getFeatures().filter((t) => t.get("bandId")).forEach((t) => { this.source.removeFeature(t); })); } /** * 启动流动动画 */ /** * 启动流动动画 * @param speed 速度倍数,默认为 1,值越大越快 */ startFlowAnimation(e, i, t, o, s, n = 1) { if (e.length < 2) return; let r = 0; const h = []; for (let m = 0; m < e.length - 1; m++) { const d = e[m], S = e[m + 1], I = S[0] - d[0], y = S[1] - d[1], v = Math.sqrt(I * I + y * y); h.push({ start: d, end: S, length: v }), r += v; } if (r <= 0) return; const g = 4, c = []; for (let m = 0; m < g; m++) { const d = new p({ geometry: new C(e[0]) }); d.set("bandId", i), d.set("type", "greenWaveBandFlowArrow"), d.setStyle( this.createArrowStyle(t, o, 0, s) ), this.source.addFeature(d), c.push(d); } this.animatedArrows.set(i, c); const l = 3e3 / Math.max(n, 0.1); let w = null; const u = (m) => { w || (w = m); const d = m - w; if ((this.mapView.getZoom() || 0) < this.NODE_MIN_ZOOM) { for (const v of c) v.setStyle(new F({})); const y = requestAnimationFrame(u); this.animationFrameIds.set(i, y); return; } for (let y = 0; y < c.length; y++) { const v = y / g, M = (d / l + v) % 1 * r; let $ = 0; for (const f of h) { if ($ + f.length >= M) { const Z = (M - $) / f.length, D = f.start[0] + (f.end[0] - f.start[0]) * Z, E = f.start[1] + (f.end[1] - f.start[1]) * Z, L = Math.atan2( f.end[1] - f.start[1], f.end[0] - f.start[0] ); c[y].getGeometry().setCoordinates([D, E]), c[y].setStyle( this.createArrowStyle( t, o, L, s ) ); break; } $ += f.length; } } const I = requestAnimationFrame(u); this.animationFrameIds.set(i, I); }, a = requestAnimationFrame(u); this.animationFrameIds.set(i, a); } /** * 停止流动动画 */ stopFlowAnimation(e) { const i = this.animationFrameIds.get(e); i && (cancelAnimationFrame(i), this.animationFrameIds.delete(e)); const t = this.animatedArrows.get(e); t && (t.forEach((o) => { this.source.removeFeature(o); }), this.animatedArrows.delete(e)); } /** * 添加路口节点 */ addNodeFeatures(e, i) { const t = [], o = this.mapView.getZoom() || 0; i.forEach((s) => { const n = new p({ geometry: new C([s.longitude, s.latitude]) }); n.set("bandId", e), n.set("type", "greenWaveBandNode"), n.set("id", s.id), n.set("name", s.name), n.set("signalId", s.signalId || ""), n.set("active", s.active ?? !1), o < this.NODE_MIN_ZOOM ? n.setStyle(this.hiddenStyle) : n.setStyle(this.getNodeStyle(s, o)), this.source.addFeature(n), t.push(n); }), this.nodeFeatures.set(e, t), this.ensureZoomChangeListener(); } /** * 确保层级变化监听器已挂载 */ ensureZoomChangeListener() { this.zoomChangeKey || (this.zoomChangeKey = this.mapView.on( "change:resolution", this.onZoomChange.bind(this) )); } /** * 层级变化回调 */ onZoomChange() { const e = this.mapView.getZoom() || 0, i = e >= this.NODE_MIN_ZOOM; this.source.getFeatures().forEach((t) => { const o = t.get("type"), s = t.get("bandId"); if (o === "greenWaveBand") { const n = this.bandConfigs.get(s); if (n != null && n.lineOnly) return; i && n ? t.setStyle( new F({ stroke: new A({ color: n.lineColor, width: n.lineWidth }) }) ) : t.setStyle(this.hiddenStyle); } else if (o === "greenWaveBandCenterIcon") { const n = this.bandConfigs.get(s); !i && n ? t.setStyle(this.createCenterIconStyle()) : t.setStyle(this.hiddenStyle); } else if (o === "greenWaveBandArrow" || o === "greenWaveBandFlowArrow") if (!i) t.setStyle(this.hiddenStyle); else if (o === "greenWaveBandArrow") { const n = t.get("arrowLineWidth"), r = t.get("arrowColor"), h = t.get("arrowAngle"), g = t.get("arrowDirection") || "double"; n != null && r != null && h != null && t.setStyle(this.createArrowStyle(n, r, h, g)); } else t.setStyle(void 0); }), this.nodeFeatures.forEach((t) => { t.forEach((o) => { if (!i) { o.setStyle(this.hiddenStyle); return; } const s = { id: o.get("nodeId"), name: o.get("name"), signalId: o.get("signalId"), active: o.get("active"), longitude: 0, latitude: 0 }; o.setStyle(this.getNodeStyle(s, e)); }); }); } /** * 获取路口节点样式 * @param node 路口信息 * @param zoom 当前地图层级 */ getNodeStyle(e, i) { const t = e.active ?? !1; if (i <= this.NODE_ZOOM_THRESHOLD) { const o = i < 15 ? 3 : 6; return new F({ image: new V({ radius: o, fill: new O({ color: t ? "#2ce90f" : "#3d8bf9" }), stroke: new A({ color: "#ffffff", width: 2 }) }) }); } else { const o = `${e.name || ""} ${e.signalId || ""}`; return [ // 图标 new F({ image: new b({ src: t ? "/GisViewerAssets/Images/cross/gis_xhj_green.png" : "/GisViewerAssets/Images/cross/gis_xhj_blue.png", scale: 0.8 }) }), // 路口名称 new F({ text: new W({ text: o, font: "bold 12px Microsoft YaHei", fill: new O({ color: "#000000" }), stroke: new A({ color: "#ffffff", width: 3 }), padding: [2, 4, 2, 4], offsetY: -25 }) }) ]; } } /** * 移除路口节点 */ removeNodeFeatures(e) { const i = this.nodeFeatures.get(e); i && (i.forEach((t) => { this.source.removeFeature(t); }), this.nodeFeatures.delete(e)), this.nodeFeatures.size === 0 && this.zoomChangeKey && (this.mapView.un("change:resolution", this.onZoomChange.bind(this)), this.zoomChangeKey = null); } } export { H as default };