|
@@ -0,0 +1,819 @@
|
|
|
+<script lang="ts" setup>
|
|
|
+import {points} from "@turf/helpers";
|
|
|
+import {bbox} from "@turf/bbox";
|
|
|
+import {LayerPopup, LineLayer, PointLayer, PolygonLayer, Popup, RasterLayer, Scene} from '@antv/l7';
|
|
|
+import {Map} from '@antv/l7-maps';
|
|
|
+// import {getLegendData, loadMapData, setCenter} from "@/utils/mapConfig";
|
|
|
+import {formatStringByTemplate} from "@/utils/string";
|
|
|
+import {copyObj} from "@/utils/ruoyi";
|
|
|
+import {onMounted, reactive} from "vue";
|
|
|
+import {getImageSrc} from "@/utils/image";
|
|
|
+
|
|
|
+let scene;
|
|
|
+let pointLayer;
|
|
|
+let pointLayerText;
|
|
|
+let lineLayer;
|
|
|
+let lineTextLayer;
|
|
|
+let polygonLayer;
|
|
|
+let polygonTextLayer;
|
|
|
+const token = 'a4eab5a1b0d94268669e192b8799f626';
|
|
|
+
|
|
|
+/**
|
|
|
+ * 初始化地图
|
|
|
+ */
|
|
|
+function init() {
|
|
|
+ const scene = new Scene({
|
|
|
+ id: 'mapDiv',
|
|
|
+ map: new Map({
|
|
|
+ center: [120.543139, 31.243133],
|
|
|
+ zoom: 9,
|
|
|
+ }),
|
|
|
+ });
|
|
|
+
|
|
|
+ const url1 = 'https://t0.tianditu.gov.cn/img_w/wmts?tk=b72aa81ac2b3cae941d1eb213499e15e&';
|
|
|
+ const layer1 = new RasterLayer().source(url1, {
|
|
|
+ parser: {
|
|
|
+ type: 'rasterTile',
|
|
|
+ tileSize: 256,
|
|
|
+ wmtsOptions: {
|
|
|
+ layer: 'img',
|
|
|
+ tileMatrixset: 'w',
|
|
|
+ format: 'tiles',
|
|
|
+ },
|
|
|
+ },
|
|
|
+ });
|
|
|
+
|
|
|
+ scene.on('loaded', () => {
|
|
|
+ scene.addLayer(layer1);
|
|
|
+ });
|
|
|
+
|
|
|
+ // scene = new Scene({
|
|
|
+ // id: 'mapDiv',
|
|
|
+ // map: new Map({}),
|
|
|
+ // });
|
|
|
+ // scene.on('mapmove', () => {
|
|
|
+ // console.log('中心点:', scene.getCenter().lng, scene.getCenter().lat, scene.getZoom(), scene.getPitch())
|
|
|
+ // }); // 地图平移时触发事件
|
|
|
+ //
|
|
|
+ // // 天地图卫片地图
|
|
|
+ // scene.on('loaded', () => {
|
|
|
+ // // 底图服务
|
|
|
+ // const baseLayer = new RasterLayer({zIndex: 1})
|
|
|
+ // .source(
|
|
|
+ // `https://t1.tianditu.gov.cn/DataServer?T=vec_w&X={x}&Y={y}&L={z}&tk=${this.token}`,
|
|
|
+ // {
|
|
|
+ // parser: {
|
|
|
+ // type: 'rasterTile',
|
|
|
+ // tileSize: 256,
|
|
|
+ // }
|
|
|
+ // }
|
|
|
+ // );
|
|
|
+ // // 注记服务
|
|
|
+ // const annotionLayer = new RasterLayer({zIndex: 2})
|
|
|
+ // .source(
|
|
|
+ // `https://t1.tianditu.gov.cn/DataServer?T=cva_w&X={x}&Y={y}&L={z}&tk=${this.token}`,
|
|
|
+ // {
|
|
|
+ // parser: {
|
|
|
+ // type: 'rasterTile',
|
|
|
+ // tileSize: 256,
|
|
|
+ // }
|
|
|
+ // }
|
|
|
+ // );
|
|
|
+ // scene.addLayer(baseLayer);
|
|
|
+ // scene.addLayer(annotionLayer);
|
|
|
+ //
|
|
|
+ // setCenter(scene, [120.543139, 31.243133], 8.03)
|
|
|
+ // });
|
|
|
+}
|
|
|
+
|
|
|
+function getWaterQualityTextByLevel(val, hasUnit = false) {
|
|
|
+ let waterQualityText = ''
|
|
|
+ switch (val) {
|
|
|
+ case '1':
|
|
|
+ waterQualityText = 'Ⅰ'
|
|
|
+ break
|
|
|
+ case '2':
|
|
|
+ waterQualityText = 'Ⅱ'
|
|
|
+ break
|
|
|
+ case '3':
|
|
|
+ waterQualityText = 'Ⅲ'
|
|
|
+ break
|
|
|
+ case '4':
|
|
|
+ waterQualityText = 'Ⅳ'
|
|
|
+ break
|
|
|
+ case '5':
|
|
|
+ waterQualityText = 'Ⅴ'
|
|
|
+ break
|
|
|
+ case '6':
|
|
|
+ waterQualityText = 'Ⅵ'
|
|
|
+ break
|
|
|
+ }
|
|
|
+
|
|
|
+ if (hasUnit && waterQualityText) {
|
|
|
+ waterQualityText = waterQualityText + '类'
|
|
|
+ }
|
|
|
+
|
|
|
+ return waterQualityText
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+// 图例
|
|
|
+const legendList = reactive([{}])
|
|
|
+const legendStyle = reactive({})
|
|
|
+
|
|
|
+/** 添加点(多个) */
|
|
|
+function addPoint(data, dataOptions = {}, nameField) {
|
|
|
+ // 1. 删除之前的图层
|
|
|
+ scene.removeAllLayer();
|
|
|
+
|
|
|
+ // 2. 添加点
|
|
|
+ // 点位标注
|
|
|
+ pointLayer = new PointLayer({})
|
|
|
+ .source(data, dataOptions)
|
|
|
+ .shape('circle')
|
|
|
+ .size(16)
|
|
|
+ .color('#004ef8')
|
|
|
+ .active(true)
|
|
|
+ scene.addLayer(pointLayer);
|
|
|
+ // 名称标注
|
|
|
+ pointLayerText = new PointLayer()
|
|
|
+ .source(data, dataOptions)
|
|
|
+ .shape(nameField, 'text')
|
|
|
+ .size(14)
|
|
|
+ .color('#000')
|
|
|
+ .style({
|
|
|
+ textOffset: [0, -50],
|
|
|
+ spacing: 2, // 字符间距
|
|
|
+ stroke: '#ffffff', // 描边颜色
|
|
|
+ strokeWidth: 2, // 描边宽度
|
|
|
+ strokeOpacity: 1.0,
|
|
|
+ });
|
|
|
+ scene.addLayer(pointLayerText);
|
|
|
+ // 3. 添加悬浮窗口
|
|
|
+ let keys = Object.keys(data[0]);
|
|
|
+ keys = keys.filter(k => !['经度', '纬度'].includes(k));
|
|
|
+ const fields = keys.map(k => {
|
|
|
+ return {
|
|
|
+ field: k,
|
|
|
+ formatField: () => k,
|
|
|
+ }
|
|
|
+ });
|
|
|
+ const layerPopup = new LayerPopup({
|
|
|
+ items: [
|
|
|
+ {
|
|
|
+ layer: pointLayer,
|
|
|
+ fields: fields,
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ });
|
|
|
+ scene.addPopup(layerPopup);
|
|
|
+}
|
|
|
+
|
|
|
+/** 添加线(多个) */
|
|
|
+function addLine(data, nameField) {
|
|
|
+ // 1. 删除之前的图层
|
|
|
+ scene.removeAllLayer();
|
|
|
+
|
|
|
+ lineLayer = new LineLayer()
|
|
|
+ .source(data)
|
|
|
+ .size(5)
|
|
|
+ .shape('line')
|
|
|
+ .active(true)
|
|
|
+ .color('ICON', (ICON) => {
|
|
|
+ switch (ICON) {
|
|
|
+ case '1':
|
|
|
+ return '#1d8add'
|
|
|
+ case '2':
|
|
|
+ return '#4af905'
|
|
|
+ case '3':
|
|
|
+ return '#fed202'
|
|
|
+ case '4':
|
|
|
+ return '#f91005'
|
|
|
+ case '5':
|
|
|
+ return '#fb0891'
|
|
|
+ case '6':
|
|
|
+ return '#252627'
|
|
|
+ default:
|
|
|
+ return '#909399'
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .style({
|
|
|
+ borderWidth: 0.4,
|
|
|
+ borderColor: '#fff',
|
|
|
+ });
|
|
|
+ scene.addLayer(lineLayer);
|
|
|
+
|
|
|
+ // 名称标注
|
|
|
+ const texts = []
|
|
|
+ data.features.forEach(d => {
|
|
|
+ let index = Math.ceil(d.geometry.coordinates[0].length / 2)
|
|
|
+ let array = d.geometry.coordinates[0][index]
|
|
|
+ texts.push({name: d.properties[nameField], x: array[0], y: array[1]})
|
|
|
+ })
|
|
|
+ lineTextLayer = new PointLayer()
|
|
|
+ .source(texts, {
|
|
|
+ parser: {
|
|
|
+ type: 'json',
|
|
|
+ x: 'x',
|
|
|
+ y: 'y',
|
|
|
+ },
|
|
|
+ })
|
|
|
+ .shape('name', 'text')
|
|
|
+ .color('#fff')
|
|
|
+ .size(14)
|
|
|
+ .style({
|
|
|
+ textOffset: [0, -50],
|
|
|
+ });
|
|
|
+ scene.addLayer(lineTextLayer);
|
|
|
+
|
|
|
+ // 悬浮窗
|
|
|
+ const fields = [
|
|
|
+ {field: 'HLNM', formatField: () => '河流名称'},
|
|
|
+ {field: 'ICON', formatField: () => '水质', formatValue: (val) => getWaterQualityTextByLevel(val, true)},
|
|
|
+ ];
|
|
|
+ const layerPopup = new LayerPopup({items: [{layer: lineLayer, fields: fields,},],});
|
|
|
+ scene.addPopup(layerPopup);
|
|
|
+}
|
|
|
+
|
|
|
+function addPolygon(data, nameField) {
|
|
|
+ // 1. 删除之前的图层
|
|
|
+ scene.removeAllLayer();
|
|
|
+
|
|
|
+ const color = [
|
|
|
+ 'rgb(255,255,217)',
|
|
|
+ 'rgb(237,248,177)',
|
|
|
+ 'rgb(199,233,180)',
|
|
|
+ 'rgb(127,205,187)',
|
|
|
+ 'rgb(65,182,196)',
|
|
|
+ 'rgb(29,145,192)',
|
|
|
+ 'rgb(34,94,168)',
|
|
|
+ 'rgb(12,44,132)',
|
|
|
+ ];
|
|
|
+ /**
|
|
|
+ * .scale('用水量', {
|
|
|
+ * type: 'quantile',
|
|
|
+ * })
|
|
|
+ * .color('用水量', color)
|
|
|
+ */
|
|
|
+ const layer = new PolygonLayer({})
|
|
|
+ .source(data)
|
|
|
+ .color('rgba(65,182,196,0.4)')
|
|
|
+ .shape('fill')
|
|
|
+ .active(true);
|
|
|
+ const layer2 = new LineLayer({zIndex: 2})
|
|
|
+ .source(data)
|
|
|
+ .color('#fff')
|
|
|
+ .active(true)
|
|
|
+ .size(1)
|
|
|
+ .style({
|
|
|
+ lineType: 'dash',
|
|
|
+ dashArray: [2, 2],
|
|
|
+ });
|
|
|
+ scene.addLayer(layer);
|
|
|
+ scene.addLayer(layer2);
|
|
|
+
|
|
|
+ const polygonTextLayer = new PointLayer({})
|
|
|
+ .source(data)
|
|
|
+ .shape(nameField, 'text')
|
|
|
+ .size(12)
|
|
|
+ .color('#000')
|
|
|
+ .style({
|
|
|
+ textAnchor: 'center', // 文本相对锚点的位置 center|left|right|top|bottom|top-left
|
|
|
+ textOffset: [0, 0], // 文本相对锚点的偏移量 [水平, 垂直]
|
|
|
+ spacing: 2, // 字符间距
|
|
|
+ padding: [1, 1], // 文本包围盒 padding [水平,垂直],影响碰撞检测结果,避免相邻文本靠的太近
|
|
|
+ stroke: '#ffffff', // 描边颜色
|
|
|
+ strokeWidth: 2, // 描边宽度
|
|
|
+ strokeOpacity: 1.0,
|
|
|
+ });
|
|
|
+
|
|
|
+ scene.addLayer(polygonTextLayer);
|
|
|
+
|
|
|
+ // layer.on('mousemove', (e) => {
|
|
|
+ // const popup = new Popup({
|
|
|
+ // offsets: [0, 0],
|
|
|
+ // closeButton: false,
|
|
|
+ // })
|
|
|
+ // .setLnglat(e.lngLat)
|
|
|
+ // .setHTML(
|
|
|
+ // `
|
|
|
+ // <span>${e.feature.properties['市']}: ${e.feature.properties['用水量']}</span>
|
|
|
+ // <br/>
|
|
|
+ // <span>许可水量: ${e.feature.properties['许可水量']}</span>
|
|
|
+ // `
|
|
|
+ // );
|
|
|
+ // scene.addPopup(popup);
|
|
|
+ // });
|
|
|
+}
|
|
|
+
|
|
|
+function add3DPoint(list) {
|
|
|
+ const pointLayer = new PointLayer({})
|
|
|
+ .source(list, {
|
|
|
+ parser: {
|
|
|
+ type: 'json',
|
|
|
+ x: 'j',
|
|
|
+ y: 'w',
|
|
|
+ },
|
|
|
+ })
|
|
|
+ .shape('cylinder')
|
|
|
+ .size('t', function (level) {
|
|
|
+ return [2, 2, level * 2 + 20];
|
|
|
+ })
|
|
|
+ .animate(true)
|
|
|
+ .active(true)
|
|
|
+ .color('t', [
|
|
|
+ '#094D4A',
|
|
|
+ '#146968',
|
|
|
+ '#1D7F7E',
|
|
|
+ '#289899',
|
|
|
+ '#34B6B7',
|
|
|
+ '#4AC5AF',
|
|
|
+ '#5FD3A6',
|
|
|
+ '#7BE39E',
|
|
|
+ '#A1EDB8',
|
|
|
+ '#CEF8D6',
|
|
|
+ ]);
|
|
|
+ scene.addLayer(pointLayer);
|
|
|
+}
|
|
|
+
|
|
|
+function getScene() {
|
|
|
+ return scene;
|
|
|
+}
|
|
|
+
|
|
|
+function loadMapData(mapConfig) {
|
|
|
+ if (['left', 'center', 'right'].includes(mapConfig.legend.left)) {
|
|
|
+ switch (mapConfig.legend.left) {
|
|
|
+ case "left":
|
|
|
+ this.legendStyle.left = '10px';
|
|
|
+ break
|
|
|
+ case "center":
|
|
|
+ this.legendStyle.left = `calc(50% - (${this.$refs.mapLegend.offsetWidth} / 2))`;
|
|
|
+ break
|
|
|
+ case "right":
|
|
|
+ this.legendStyle.right = '10px';
|
|
|
+ break
|
|
|
+ }
|
|
|
+ } else if (mapConfig.legend.left.startsWith('-')) {
|
|
|
+ this.legendStyle.right = mapConfig.legend.left.replace('-', '')
|
|
|
+ } else {
|
|
|
+ this.legendStyle.left = mapConfig.legend.left
|
|
|
+ }
|
|
|
+
|
|
|
+ if (['top', 'center', 'bottom'].includes(mapConfig.legend.top)) {
|
|
|
+ switch (mapConfig.legend.top) {
|
|
|
+ case "top":
|
|
|
+ this.legendStyle.top = '10px';
|
|
|
+ break
|
|
|
+ case "center":
|
|
|
+ this.legendStyle.top = `calc(50% - (${this.$refs.mapLegend.offsetHeight} / 2))`;
|
|
|
+ break
|
|
|
+ case "bottom":
|
|
|
+ this.legendStyle.bottom = '10px';
|
|
|
+ break
|
|
|
+ }
|
|
|
+ } else if (mapConfig.legend.top.startsWith('-')) {
|
|
|
+ this.legendStyle.bottom = mapConfig.legend.top.replace('-', '')
|
|
|
+ } else {
|
|
|
+ this.legendStyle.top = mapConfig.legend.top
|
|
|
+ }
|
|
|
+
|
|
|
+ // this.legendList = getLegendData(mapConfig)
|
|
|
+}
|
|
|
+
|
|
|
+function fitBounds(data) {
|
|
|
+ const features = points(data);
|
|
|
+ const bboxs = bbox(features);
|
|
|
+
|
|
|
+ let lttddd = (bboxs[3] - bboxs[1]) / 8 // 计算缩放级别
|
|
|
+ let lgtddd = (bboxs[2] - bboxs[0]) / 8 // 计算缩放级别
|
|
|
+ scene.fitBounds([[bboxs[0] - lgtddd, bboxs[1] - lttddd], [bboxs[2] + lgtddd, bboxs[3] + lttddd]]);
|
|
|
+}
|
|
|
+
|
|
|
+/** 设置事件节点 */
|
|
|
+function setEventData(events) {
|
|
|
+ const _self = this
|
|
|
+ // 1. 删除之前的图层
|
|
|
+ scene.removeAllLayer();
|
|
|
+
|
|
|
+ const sourceOptions = {
|
|
|
+ parser: {
|
|
|
+ type: 'json',
|
|
|
+ x: 'x',
|
|
|
+ y: 'y',
|
|
|
+ },
|
|
|
+ }
|
|
|
+
|
|
|
+ const imageSet = new Set()
|
|
|
+ events.forEach(event => {
|
|
|
+ if (event.image) {
|
|
|
+ imageSet.add(event.image)
|
|
|
+ }
|
|
|
+ })
|
|
|
+ imageSet.forEach(image => {
|
|
|
+ scene.addImage(
|
|
|
+ image,
|
|
|
+ getImageSrc(image)
|
|
|
+ );
|
|
|
+ })
|
|
|
+
|
|
|
+ const imageEvents = events.filter(event => !!event.image)
|
|
|
+ const imagePointLayer = new PointLayer()
|
|
|
+ .source(imageEvents, sourceOptions)
|
|
|
+ .size(16)
|
|
|
+ .shape('image', Array.of(imageSet))
|
|
|
+ .style({
|
|
|
+ opacity: 0.8,
|
|
|
+ strokeWidth: 4
|
|
|
+ })
|
|
|
+ .active(true);
|
|
|
+ scene.addLayer(imagePointLayer);
|
|
|
+
|
|
|
+ const shapeEvents = events.filter(event => !event.image)
|
|
|
+ const shapePointLayer = new PointLayer()
|
|
|
+ .source(shapeEvents, sourceOptions)
|
|
|
+ .size(16)
|
|
|
+ .shape('shape')
|
|
|
+ .color('color')
|
|
|
+ .style({
|
|
|
+ opacity: 0.8,
|
|
|
+ strokeWidth: 4
|
|
|
+ })
|
|
|
+ .active(true);
|
|
|
+ scene.addLayer(shapePointLayer);
|
|
|
+
|
|
|
+
|
|
|
+ // 设置标签
|
|
|
+ pointLayerText = new PointLayer()
|
|
|
+ .source(events, sourceOptions)
|
|
|
+ .shape('name', 'text')
|
|
|
+ .size(12)
|
|
|
+ .color('#000')
|
|
|
+ .style({
|
|
|
+ textAnchor: 'center', // 文本相对锚点的位置 center|left|right|top|bottom|top-left
|
|
|
+ textOffset: [0, -60], // 文本相对锚点的偏移量 [水平, 垂直]
|
|
|
+ spacing: 2, // 字符间距
|
|
|
+ padding: [1, 1], // 文本包围盒 padding [水平,垂直],影响碰撞检测结果,避免相邻文本靠的太近
|
|
|
+ stroke: '#fff', // 描边颜色
|
|
|
+ strokeWidth: 2, // 描边宽度
|
|
|
+ strokeOpacity: 1.0,
|
|
|
+ });
|
|
|
+ scene.addLayer(pointLayerText);
|
|
|
+
|
|
|
+ // 显示弹窗
|
|
|
+ const showPopup = (e) => {
|
|
|
+ let data = e.feature.data
|
|
|
+ const template =
|
|
|
+ '<div class="entry-card-component"><section class="entry-base-info">' +
|
|
|
+ '<section class="base-info"><div class="entry-avatar"><img alt="" src="{{imgUrl}}"></div><div class="entry-text-info"><div class="entry-name">{{name}}</div><div class="entry-desc">{{summary}}</div></div></section></section>' +
|
|
|
+ '<section class="entry-nodes"><div class="nodes-list"><div class="node-item" data-id="{{id}}">' +
|
|
|
+ '<div class="title">{{source.title}}</div>' +
|
|
|
+ '<div class="sub-title"><div class="time">{{source.dateString}}</div>' +
|
|
|
+ '<div class="address">{{source.locationDesc}}</div></div>' +
|
|
|
+ '<div class="desc">{{source.description}}</div></div></div></section></div>'
|
|
|
+ const content = formatStringByTemplate(data, template)
|
|
|
+ const popup = new Popup({maxWidth: '36vw', autoClose: true})
|
|
|
+ .setLnglat(e.lngLat)
|
|
|
+ .setHTML(content);
|
|
|
+ scene.addPopup(popup);
|
|
|
+
|
|
|
+ // 确保在 DOM 完全更新后执行
|
|
|
+ setTimeout(() => {
|
|
|
+ const eventItems = document.getElementsByClassName('node-item');
|
|
|
+ // 遍历所有 node-item 元素
|
|
|
+ Array.from(eventItems).forEach(item => {
|
|
|
+ item.addEventListener('click', (event) => {
|
|
|
+ // const id = event.currentTarget?.dataset?.id;
|
|
|
+ // _self.$router.push({path: `/geoTemporalSearch/detail/${id}`});
|
|
|
+ });
|
|
|
+ });
|
|
|
+ }, 0); // 使用 setTimeout 来确保 DOM 已经更新
|
|
|
+ };
|
|
|
+
|
|
|
+ imagePointLayer.on('click', showPopup);
|
|
|
+ shapePointLayer.on('click', showPopup);
|
|
|
+}
|
|
|
+
|
|
|
+function setEventPoint(events) {
|
|
|
+ const _self = this
|
|
|
+ // 1. 删除之前的图层
|
|
|
+ scene.removeAllLayer();
|
|
|
+
|
|
|
+ const sourceOptions = {
|
|
|
+ parser: {
|
|
|
+ type: 'json',
|
|
|
+ x: 'x',
|
|
|
+ y: 'y',
|
|
|
+ },
|
|
|
+ }
|
|
|
+ const pointLayer = new PointLayer()
|
|
|
+ .source(events, sourceOptions)
|
|
|
+ .size(12)
|
|
|
+ .shape('simple')
|
|
|
+ .color('#fe7331')
|
|
|
+ .style({
|
|
|
+ strokeWidth: 4
|
|
|
+ })
|
|
|
+ .active(false);
|
|
|
+ scene.addLayer(pointLayer);
|
|
|
+
|
|
|
+ // 设置标签
|
|
|
+ pointLayerText = new PointLayer()
|
|
|
+ .source(events, sourceOptions)
|
|
|
+ .shape('title', 'text')
|
|
|
+ .size(12)
|
|
|
+ .color('#000')
|
|
|
+ .style({
|
|
|
+ textAnchor: 'center', // 文本相对锚点的位置 center|left|right|top|bottom|top-left
|
|
|
+ textOffset: [0, -60], // 文本相对锚点的偏移量 [水平, 垂直]
|
|
|
+ spacing: 2, // 字符间距
|
|
|
+ padding: [1, 1], // 文本包围盒 padding [水平,垂直],影响碰撞检测结果,避免相邻文本靠的太近
|
|
|
+ stroke: '#fff', // 描边颜色
|
|
|
+ strokeWidth: 2, // 描边宽度
|
|
|
+ strokeOpacity: 1.0,
|
|
|
+ });
|
|
|
+ scene.addLayer(pointLayerText);
|
|
|
+}
|
|
|
+
|
|
|
+function setEventPointDetail(events) {
|
|
|
+ const allPoints = copyObj(events)
|
|
|
+ // 1. 删除之前的图层
|
|
|
+ scene.removeAllLayer();
|
|
|
+
|
|
|
+ let mainEvent;
|
|
|
+ let index = events.findIndex(item => item.pointType === 'main');
|
|
|
+ if (index > -1) {
|
|
|
+ mainEvent = events.splice(index, 1); // 移除找到的第一个元素 l
|
|
|
+ } else {
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ const sourceOptions = {
|
|
|
+ parser: {
|
|
|
+ type: 'json',
|
|
|
+ x: 'x',
|
|
|
+ y: 'y',
|
|
|
+ },
|
|
|
+ }
|
|
|
+ const pointLayer = new PointLayer()
|
|
|
+ .source(events, sourceOptions)
|
|
|
+ .size(12)
|
|
|
+ .shape('simple')
|
|
|
+ .color('#fe7331')
|
|
|
+ .style({
|
|
|
+ strokeWidth: 4
|
|
|
+ })
|
|
|
+ .active(false);
|
|
|
+ scene.addLayer(pointLayer);
|
|
|
+
|
|
|
+ const mainPointLayer = new PointLayer()
|
|
|
+ .source(mainEvent, sourceOptions)
|
|
|
+ .size(20)
|
|
|
+ .shape('simple')
|
|
|
+ .color('#fe7331')
|
|
|
+ .style({
|
|
|
+ strokeWidth: 4
|
|
|
+ })
|
|
|
+ .active(false);
|
|
|
+ scene.addLayer(mainPointLayer);
|
|
|
+
|
|
|
+ // 设置标签
|
|
|
+ pointLayerText = new PointLayer()
|
|
|
+ .source(allPoints, sourceOptions)
|
|
|
+ .shape('title', 'text')
|
|
|
+ .size(12)
|
|
|
+ .color('#000')
|
|
|
+ .style({
|
|
|
+ textAnchor: 'center', // 文本相对锚点的位置 center|left|right|top|bottom|top-left
|
|
|
+ textOffset: [0, -60], // 文本相对锚点的偏移量 [水平, 垂直]
|
|
|
+ spacing: 2, // 字符间距
|
|
|
+ padding: [1, 1], // 文本包围盒 padding [水平,垂直],影响碰撞检测结果,避免相邻文本靠的太近
|
|
|
+ stroke: '#fff', // 描边颜色
|
|
|
+ strokeWidth: 2, // 描边宽度
|
|
|
+ strokeOpacity: 1.0,
|
|
|
+ });
|
|
|
+ scene.addLayer(pointLayerText);
|
|
|
+
|
|
|
+ for (let e of events) {
|
|
|
+ let data = []
|
|
|
+ if (e.pointType === 'previous') {
|
|
|
+ data.push({lng: e.x, lat: e.y, lng1: mainEvent[0].x, lat1: mainEvent[0].y})
|
|
|
+ } else {
|
|
|
+ data.push({lng: mainEvent[0].x, lat: mainEvent[0].y, lng1: e.x, lat1: e.y})
|
|
|
+ }
|
|
|
+
|
|
|
+ const lineLayer = new LineLayer()
|
|
|
+ .source(data, {
|
|
|
+ parser: {
|
|
|
+ type: 'json',
|
|
|
+ x: 'lng',
|
|
|
+ y: 'lat',
|
|
|
+ x1: 'lng1',
|
|
|
+ y1: 'lat1',
|
|
|
+ },
|
|
|
+ })
|
|
|
+ .shape('line')
|
|
|
+ .size(2)
|
|
|
+ .color('#f00')
|
|
|
+ .animate({
|
|
|
+ duration: 2,
|
|
|
+ interval: 1,
|
|
|
+ trailLength: 1,
|
|
|
+ })
|
|
|
+ .style({
|
|
|
+ lineType: 'dash', // 设置虚线类型
|
|
|
+ // dashArray: [5, 5], // 设置虚线的间隔和长度
|
|
|
+ });
|
|
|
+ scene.addLayer(lineLayer);
|
|
|
+ }
|
|
|
+
|
|
|
+ pointLayer.on('click', e => {
|
|
|
+ if (e.feature?.id) {
|
|
|
+ this.$emit('updateEventId', e.feature?.id)
|
|
|
+ }
|
|
|
+ });
|
|
|
+}
|
|
|
+
|
|
|
+onMounted(() => {
|
|
|
+ init()
|
|
|
+})
|
|
|
+</script>
|
|
|
+
|
|
|
+<template>
|
|
|
+ <div class="gw-map">
|
|
|
+ <!-- 2D地图 -->
|
|
|
+ <div id="mapDiv"></div>
|
|
|
+ <!-- <div v-if="legendList && legendList.length > 0" ref="mapLegend" :style="legendStyle" class="map-legend">-->
|
|
|
+ <!-- <ul>-->
|
|
|
+ <!-- <li v-for="(item, index) in legendList" :key="index">-->
|
|
|
+ <!-- <span :title="item.label">{{ item.label }}</span>-->
|
|
|
+ <!-- <template v-if="item.imgType === 'svg'">-->
|
|
|
+ <!-- <svg-icon :icon-class="item.src" :style="item.imgStyle" class="image"></svg-icon>-->
|
|
|
+ <!-- </template>-->
|
|
|
+ <!-- <template v-if="item.imgType === 'img'">-->
|
|
|
+ <!-- <el-image :src="item.src" :style="item.imgStyle" class="image"></el-image>-->
|
|
|
+ <!-- </template>-->
|
|
|
+ <!-- </li>-->
|
|
|
+ <!-- </ul>-->
|
|
|
+ <!-- </div>-->
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+<style lang="scss" scoped>
|
|
|
+.gw-map {
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ position: relative;
|
|
|
+ pointer-events: auto;
|
|
|
+}
|
|
|
+
|
|
|
+#mapDiv {
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ z-index: 1;
|
|
|
+ opacity: 1;
|
|
|
+ overflow: hidden;
|
|
|
+ filter: saturate(1) contrast(1) hue-rotate(0deg) brightness(1);
|
|
|
+ transform: rotateZ(0deg) rotateX(0deg) rotateY(0deg) skewX(0deg) skewY(0deg);
|
|
|
+}
|
|
|
+
|
|
|
+.map-legend {
|
|
|
+ position: absolute;
|
|
|
+ bottom: 0;
|
|
|
+ right: 0;
|
|
|
+ z-index: 100;
|
|
|
+ background-color: #f2f2f2;
|
|
|
+ border-radius: 8px;
|
|
|
+ padding: 5px 10px;
|
|
|
+
|
|
|
+ ul {
|
|
|
+ margin: 0;
|
|
|
+ padding: 0;
|
|
|
+
|
|
|
+ li {
|
|
|
+ margin: 5px 0;
|
|
|
+ list-style: none;
|
|
|
+ display: flex;
|
|
|
+ justify-content: flex-end;
|
|
|
+ align-items: center;
|
|
|
+
|
|
|
+ span {
|
|
|
+ text-align: right;
|
|
|
+ width: 7vw;
|
|
|
+ white-space: nowrap;
|
|
|
+ overflow: hidden;
|
|
|
+ text-overflow: ellipsis;
|
|
|
+ }
|
|
|
+
|
|
|
+ .image {
|
|
|
+ margin-left: 5px;
|
|
|
+ width: 1rem;
|
|
|
+ height: 1rem;
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+:deep(.l7-control-logo) {
|
|
|
+ display: none;
|
|
|
+}
|
|
|
+
|
|
|
+:deep(.esri-view-surface) {
|
|
|
+ &:after {
|
|
|
+ display: none;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+</style>
|
|
|
+<style lang="scss">
|
|
|
+.entry-card-component {
|
|
|
+ .entry-base-info {
|
|
|
+
|
|
|
+ .base-info {
|
|
|
+ display: flex;
|
|
|
+ margin-bottom: 14px;
|
|
|
+
|
|
|
+ .entry-avatar {
|
|
|
+ width: 90px;
|
|
|
+ margin-right: 8px;
|
|
|
+ height: 108px;
|
|
|
+
|
|
|
+ img {
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ object-fit: cover;
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ .entry-text-info {
|
|
|
+ flex: 1;
|
|
|
+
|
|
|
+ .entry-name {
|
|
|
+ font-size: 16px;
|
|
|
+ line-height: 22px;
|
|
|
+ font-weight: 600;
|
|
|
+ margin-bottom: 10px;
|
|
|
+ margin-right: 24px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .entry-desc {
|
|
|
+ line-height: 20px;
|
|
|
+ font-size: 12px;
|
|
|
+ word-break: break-word;
|
|
|
+ display: -webkit-box;
|
|
|
+ height: 80px;
|
|
|
+ overflow: hidden;
|
|
|
+ text-overflow: ellipsis;
|
|
|
+ -webkit-line-clamp: 4;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ .entry-nodes {
|
|
|
+ .nodes-list {
|
|
|
+ border-top: 1px solid #ebebeb;
|
|
|
+ padding-top: 7px;
|
|
|
+
|
|
|
+ .node-item {
|
|
|
+ cursor: pointer;
|
|
|
+
|
|
|
+ .title {
|
|
|
+ word-break: break-word;
|
|
|
+ display: -webkit-box;
|
|
|
+ -webkit-box-orient: vertical;
|
|
|
+ overflow: hidden;
|
|
|
+ text-overflow: ellipsis;
|
|
|
+ -webkit-line-clamp: 2;
|
|
|
+ }
|
|
|
+
|
|
|
+ .sub-title {
|
|
|
+ display: flex;
|
|
|
+ margin-bottom: 8px;
|
|
|
+ color: #999;
|
|
|
+ line-height: 14px;
|
|
|
+
|
|
|
+ .time {
|
|
|
+ margin-right: 4px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .address {
|
|
|
+ overflow: hidden;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .desc {
|
|
|
+ font-size: 12px;
|
|
|
+ color: #666;
|
|
|
+ line-height: 20px;
|
|
|
+ max-height: 40px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|