gisviewer-vue3-arcgis
Version:
在应用中引入私服的包, 项目根目录下 新建文件 .npmrc 在 .npmrc 中对包源进行配置:
300 lines (299 loc) • 10.2 kB
JavaScript
import P from "axios";
import w from "ol/Feature";
import M from "ol/geom/LineString";
import C from "ol/geom/Point";
import F from "ol/geom/Polygon";
import y from "ol/layer/Vector";
import p from "ol/source/Vector";
import v from "ol/style/Circle";
import L from "ol/style/Fill";
import x from "ol/style/Icon";
import S from "ol/style/Stroke";
import d from "ol/style/Style";
import u from "./sumo-utils.mjs";
class E {
constructor(o) {
this.arrowCanvasCache = /* @__PURE__ */ new Map(), this.nodeStyleCache = /* @__PURE__ */ new Map(), this.trafficLightStyleCache = /* @__PURE__ */ new Map(), this.stopLineStyleCache = /* @__PURE__ */ new Map(), this.map = o, this.trafficLightImage = u.createTrafficLightImage(), this.setupLayers();
}
setupLayers() {
this.nodePolygonSource = new p(), this.nodePolygonLayer = new y({
source: this.nodePolygonSource
}), this.nodePolygonLayer.set("id", "sumo-node-polygon-layer"), this.nodePolygonLayer.setStyle(
new d({
fill: new L({ color: "#8B0000" })
})
), this.map.addLayer(this.nodePolygonLayer), this.polygonLaneSource = new p();
const o = new y({
source: this.polygonLaneSource
});
o.set("id", "sumo-polygon-lane-layer");
const t = new d({
fill: new L({ color: "#1a1a1a" })
}), r = new d({
fill: new L({ color: "#1a1a1a" }),
stroke: new S({
color: "#ffffff",
width: 1,
lineDash: [5, 3]
})
});
o.setStyle(() => (this.map.getView().getZoom() ?? 0) <= 16 ? t : r), this.map.addLayer(o), this.connectorLaneSource = new p();
const e = new y({
source: this.connectorLaneSource,
style: [
// 底层:白色描边,宽度4,透明度0.6
new d({
stroke: new S({
color: [255, 255, 255, 0.6],
width: 4,
lineCap: "round",
lineJoin: "round"
})
}),
// 上层:灰色中心线,宽度2
new d({
stroke: new S({
color: "#666666",
width: 2,
lineCap: "round",
lineJoin: "round"
})
})
]
});
e.set("id", "sumo-connector-lane-layer"), this.map.addLayer(e), this.stopLineSource = new p();
const c = new y({
source: this.stopLineSource
});
c.setStyle((s) => {
const l = s.get("color") || "#52C41A";
let n = this.stopLineStyleCache.get(l);
return n || (n = new d({
stroke: new S({
color: l,
width: 4,
lineCap: "butt",
lineJoin: "round"
})
}), this.stopLineStyleCache.set(l, n)), n;
}), c.set("id", "sumo-stop-line-layer"), this.map.addLayer(c), this.laneArrowSource = new p();
const a = new y({
source: this.laneArrowSource
});
a.set("id", "sumo-lane-arrow-layer"), a.setStyle((s) => {
if ((this.map.getView().getZoom() ?? 0) <= 17)
return;
const l = s.get("arrowType"), n = s.get("angle");
return new d({
image: new x({
img: this.getArrowCanvas(l),
scale: this.getArrowScale(),
// 图标朝上绘制,按方位角顺时针旋转对齐车道方向
rotation: n * Math.PI / 180,
anchor: [0.5, 0.5]
})
});
}), this.map.addLayer(a), this.nodePointSource = new p(), this.nodePointLayer = new y({ source: this.nodePointSource }), this.nodePointLayer.set("id", "sumo-node-point-layer"), this.nodePointLayer.setStyle((s) => this.getNodeStyle(s)), this.map.addLayer(this.nodePointLayer);
}
getNodeStyle(o) {
const t = this.getNodeScale(), r = o.get("type");
if ((this.map.getView().getZoom() ?? 0) <= 15 && r === "traffic_light")
return;
const e = Math.round(t * 100) / 100, c = r === "traffic_light" ? this.trafficLightStyleCache : this.nodeStyleCache;
let a = c.get(e);
return a || (a = r === "traffic_light" ? new d({
image: new x({
img: this.trafficLightImage,
scale: e
})
}) : new d({
image: new v({
radius: 6,
scale: e,
fill: new L({ color: "#FF6B6B" }),
stroke: new S({ color: "#ffffff", width: 1.5 })
})
}), c.set(e, a)), a;
}
/**
* 显示 SUMO 路网数据
* @param params 显示 SUMO 路网数据的参数
* @param params.server 解析 SUMO 文件的后端服务地址
* @param params.file 待解析的 SUMO 文件 URL
* @param params.options 可选,显示选项配置
* @param params.options.showJunctionPolygon 是否显示路口多边形
* @param params.options.showJunctionPoint 可选,是否显示路口点
* @param params.options.showJunctionLane 是否显示路口车道
* @param params.options.showRoadName 是否显示道路名称
* @param params.options.needZoom 可选,是否将地图缩放到显示所有车道,默认 true
* @param params.selectedCallback 可选,要素选中时的回调函数
* @returns 显示结果,包含状态码和消息
*/
async showSumoFromFile(o) {
var h, f, m;
let t;
try {
const i = await P.get(o.file, {
responseType: "blob"
}), g = new URL(o.file).pathname.split("/").pop() || "sumo";
t = new File([i.data], g, {
type: i.data.type
});
} catch (i) {
return console.error("下载 SUMO 文件失败:", o.file, i), {
status: -1,
message: `下载 SUMO 文件失败:${(i == null ? void 0 : i.message) || "未知错误"}`
};
}
const r = new FormData();
r.append("file", t);
let e;
try {
e = await P.post(o.server, r);
} catch (i) {
return console.error("解析 SUMO 文件失败:", o.server, i), {
status: -1,
message: `解析 SUMO 文件失败:${(i == null ? void 0 : i.message) || "未知错误"}`
};
}
if (e.status !== 200)
return {
status: -1,
message: e.statusText || "error"
};
this.nodePolygonLayer.setVisible(
((h = o.options) == null ? void 0 : h.showJunctionPolygon) !== !1
), this.nodePointLayer.setVisible(((f = o.options) == null ? void 0 : f.showJunctionPoint) !== !1);
const { nodes: c, edges: a, connections: s, trafficLights: l } = e.data;
console.log(l), this.showNodes(c);
const n = this.showEdges(a, s);
if (((m = o.options) == null ? void 0 : m.needZoom) !== !1) {
const i = u.getFeaturesExtent(n);
i && this.map.getView().fit(i, {
padding: [10, 10, 10, 10]
});
}
return {
status: 0,
message: "success"
};
}
/**
* 显示 SUMO 节点
* @param nodes
*/
showNodes(o) {
this.nodePointSource.clear(), this.nodePolygonSource.clear();
const t = [], r = [];
for (const e of o)
t.push(
new w({
geometry: new C([e.x, e.y]),
...e
})
), !(e.type === "internal" || !e.shape || e.shape.length < 3) && r.push(
new w({
geometry: new F([[...e.shape, e.shape[0]]]),
...e
})
);
this.nodePointSource.addFeatures(t), this.nodePolygonSource.addFeatures(r);
}
/**
* 显示 SUMO 边(车道、连接段、转向箭头)
* @param edges
* @returns
*/
showEdges(o, t) {
const r = [], e = [], c = [], a = /* @__PURE__ */ new Map();
for (const s of t) {
if (s.fromLane === void 0)
continue;
const l = `${s.from}_${s.fromLane}`, n = a.get(l) ?? [];
if (s.dir) {
const h = s.dir.toUpperCase();
n.includes(h) || n.push(h);
}
a.set(l, n);
}
for (const s of o) {
if (!s.lanes || s.lanes.length === 0)
continue;
const l = s.isInternal ?? !1;
for (const n of s.lanes)
if (!(!n.shape || n.shape.length < 2))
if (l) {
const h = `${s.id}_${n.index}`, i = !(a.get(h) ?? []).some((g) => g !== "S") ? n.shape : u.smoothShape(n.shape);
r.push(
new w({
geometry: new M(i),
id: s.id,
laneIndex: n.index
})
);
} else {
const h = u.laneToPolygon(n.shape, n.width);
h.length > 0 && e.push(
new w({
geometry: new F([h]),
id: s.id,
laneIndex: n.index
})
);
const { point: f, angle: m } = u.getLaneArrowPosition(n.shape), i = `${s.id}_${n.index}`, g = a.get(i) ?? [];
if (g.length > 0) {
const A = u.determineArrowType(g);
c.push(
new w({
geometry: new C(f),
id: i,
angle: m,
arrowType: A
})
);
}
}
}
return this.connectorLaneSource.addFeatures(r), this.polygonLaneSource.addFeatures(e), this.laneArrowSource.addFeatures(c), [...r, ...e];
}
showStopLines(o, t) {
}
/**
* 计算当前缩放级别下的箭头图标 scale:
* zoom<=18 时为 0.035,zoom>=21 时为 0.6,中间线性插值
*/
getArrowScale() {
const o = this.map.getView().getZoom() ?? 14, t = 18, r = 21, e = 0.035, c = 0.6;
if (o <= t)
return e;
if (o >= r)
return c;
const a = (o - t) / (r - t);
return e + a * (c - e);
}
getNodeScale() {
const o = this.map.getView().getZoom() ?? 14, t = 18, r = 21, e = 0.6, c = 1.2;
if (o <= t)
return e;
if (o >= r)
return c;
const a = (o - t) / (r - t);
return e + a * (c - e);
}
/** 获取(并按箭头类型缓存)箭头图标 canvas */
getArrowCanvas(o) {
let t = this.arrowCanvasCache.get(o);
return t || (t = u.createArrowIcon(o, 64), this.arrowCanvasCache.set(o, t)), t;
}
/**
* 清空 SUMO 渲染结果
* 清空路口点、路口面、连接段车道、车道面图层的所有要素
* 但不清除图层本身,也不清除地图上其他图层的要素
*/
clearSumo() {
this.nodePointSource.clear(), this.nodePolygonSource.clear(), this.connectorLaneSource.clear(), this.polygonLaneSource.clear(), this.laneArrowSource.clear();
}
}
export {
E as default
};