gisviewer-vue3-arcgis
Version:
在应用中引入私服的包, 项目根目录下 新建文件 .npmrc 在 .npmrc 中对包源进行配置:
439 lines (438 loc) • 14.4 kB
JavaScript
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
};