CzRger 1 gadu atpakaļ
vecāks
revīzija
7bcc2385da

+ 3 - 1
package.json

@@ -17,7 +17,9 @@
     "uuid": "^9.0.0",
     "vue": "^3.2.47",
     "vue-router": "^4.1.6",
-    "vuex": "^4.1.0"
+    "vuex": "^4.1.0",
+    "ol": "^6.5.0",
+    "@turf/turf": "^6.5.0"
   },
   "devDependencies": {
     "@types/uuid": "^9.0.2",

+ 55 - 0
src/components/easyMap/func/location.ts

@@ -0,0 +1,55 @@
+import * as ol from 'ol'
+import * as style from 'ol/style'
+import * as layer from 'ol/layer'
+import * as source from 'ol/source'
+import * as geom from 'ol/geom'
+import * as proj from 'ol/proj'
+import * as interaction from 'ol/interaction'
+import * as coordinate from 'ol/coordinate'
+import * as format from "ol/format";
+
+const layerFlag = ['layerName', 'positionLayer']
+export default function Location ({map, position = null, wkt = null, zoom = null, color = '#039ff3'}) {
+    let _source = null
+    const realLayer = map.getLayers().getArray().filter(v => v.get(layerFlag[0]) === layerFlag[1])
+    if (realLayer[0]) {
+        _source = realLayer[0].getSource()
+        _source.clear()
+    } else {
+        _source = new source.Vector(); //图层数据源
+        const _vector = new layer.Vector({
+            zIndex: 9999,
+            source: _source,
+        });
+        _vector.set(layerFlag[0], layerFlag[1])
+        map.addLayer(_vector);
+    }
+    const feat = new format.WKT().readFeature(position ? `POINT(${position[0]} ${position[1]})` : wkt)
+    const radius = 25
+    const longRadius = radius * Math.SQRT2
+    feat.setStyle([new style.Style({ //图层样式
+        image: new style.RegularShape({
+            stroke: new style.Stroke({
+                color: color,
+                width: 2,
+                lineDash: [
+                    (longRadius * 3) / 10,
+                    (longRadius * 4) / 10,
+                    (longRadius * 3) / 10,
+                    0
+                ]
+            }),
+            radius1: radius,
+            rotation: Math.PI / (180 / 45),
+            points: 4
+        })
+    })])
+    _source.addFeature(feat)
+    setTimeout(() => {
+        feat?.getGeometry().setCoordinates([0, 0])
+    }, 3000)
+    map.getView().setCenter(feat?.getGeometry().getCoordinates())
+    if (zoom) {
+        map.getView().setZoom(zoom)
+    }
+}

+ 45 - 0
src/components/easyMap/func/measure.scss

@@ -0,0 +1,45 @@
+.tooltip {
+  position: relative;
+  background: rgba(0, 0, 0, 0.5);
+  border-radius: 4px;
+  color: white;
+  padding: 4px 8px;
+  white-space: nowrap;
+}
+
+.tooltip-measure {
+  opacity: 1;
+  font-weight: bold;
+}
+
+.tooltip-static {
+  background-color: #ffcc33;
+  color: black;
+  border: 1px solid white;
+}
+
+.tooltip-measure:before,
+.tooltip-static:before {
+  border-top: 6px solid rgba(0, 0, 0, 0.5);
+  border-right: 6px solid transparent;
+  border-left: 6px solid transparent;
+  content: "";
+  position: absolute;
+  bottom: -6px;
+  margin-left: -7px;
+  left: 50%;
+}
+
+.tooltip-static:before {
+  border-top-color: #ffcc33;
+}
+.lineDel {
+  width: 16px;
+  height: 16px;
+  display: inline-block;
+  vertical-align: middle;
+  margin-left: 10px;
+  cursor: pointer;
+  //background: url('@/assets/images/map/lineDel.png') no-repeat;
+  background-size: 100% 100%;
+}

+ 262 - 0
src/components/easyMap/func/measure.ts

@@ -0,0 +1,262 @@
+import * as ol from 'ol'
+import * as style from 'ol/style'
+import * as layer from 'ol/layer'
+import * as source from 'ol/source'
+import * as geom from 'ol/geom'
+import * as proj from 'ol/proj'
+import * as interaction from 'ol/interaction'
+import * as coordinate from 'ol/coordinate'
+import * as control from 'ol/control'
+import * as sphere from 'ol/sphere'
+import { unByKey } from 'ol/Observable'
+import './measure.scss'
+import {createBox} from "ol/interaction/Draw";
+import {Circle, LineString, Polygon} from "ol/geom";
+
+const layerFlag = ['layerName', 'measureLayer']
+let measureTooltipElement;
+let helpTooltipElement;
+const typeMapper = new Map([
+    ['line', 'LineString'],
+    ['rectangle', 'LineString'],
+    ['polygon', 'Polygon'],
+    ['circle', 'Circle'],
+])
+/**
+ *
+ * @param map
+ * @param typeSelect    line线,rectangle矩形,polygon多边形,circle圆形
+ */
+export default function Measure (map, typeSelect) {
+    let _source = null
+    const realLayer = map.getLayers().getArray().filter(v => v.get(layerFlag[0]) === layerFlag[1])
+    if (realLayer[0]) {
+        _source = realLayer[0].getSource()
+    } else {
+        _source = new source.Vector(); //图层数据源
+        const _vector = new layer.Vector({
+            zIndex: 9999,
+            source: _source,
+            style: new style.Style({ //图层样式
+                fill: new style.Fill({
+                    color: 'rgba(255, 255, 255, 0.2)' //填充颜色
+                }),
+                stroke: new style.Stroke({
+                    color: '#f31a4a',  //边框颜色
+                    width: 2   // 边框宽度
+                }),
+                image: new style.Circle({
+                    radius: 7,
+                    fill: new style.Fill({
+                        color: '#ffcc33'
+                    })
+                })
+            })
+        });
+        _vector.set(layerFlag[0], layerFlag[1])
+        map.addLayer(_vector);
+    }
+    let sketch;
+    let helpTooltip;
+    let measureTooltip;
+    let continueMsg = '双击结束测量';
+    const geodesicCheckbox = true;//测地学方式对象
+    const createMeasureTooltip = () => {
+        const id = 'measureTooltipElementId'
+        if (measureTooltipElement) {
+            map.removeOverlay(map.getOverlayById(id))
+            measureTooltipElement.parentNode.removeChild(measureTooltipElement);
+        }
+        measureTooltipElement = document.createElement('div');
+        measureTooltipElement.className = 'tooltip tooltip-measure';
+        measureTooltip = new ol.Overlay({
+            id,
+            element: measureTooltipElement,
+            offset: [0, -15],
+            positioning: 'bottom-center'
+        });
+        map.addOverlay(measureTooltip);
+    }
+    const createHelpTooltip = () => {
+        const id = 'helpTooltipElementId'
+        if (helpTooltipElement) {
+            map.removeOverlay(map.getOverlayById(id))
+            helpTooltipElement.parentNode.removeChild(helpTooltipElement);
+        }
+        helpTooltipElement = document.createElement('div');
+        helpTooltipElement.className = 'tooltip hidden';
+        helpTooltip = new ol.Overlay({
+            id,
+            element: helpTooltipElement,
+            offset: [15, 0],
+            positioning: 'center-left'
+        });
+        map.addOverlay(helpTooltip);
+    }
+    const formatLength = (line) => {
+        // 获取投影坐标系
+        const sourceProj = map.getView().getProjection();
+        // ol/sphere里有getLength()和getArea()用来测量距离和区域面积,默认的投影坐标系是EPSG:3857, 其中有个options的参数,可以设置投影坐标系
+        const length = sphere.getLength(line, {projection: sourceProj});
+        // const length = getLength(line);
+        let output;
+        if (length > 100) {
+            const km = Math.round((length / 1000) * 100) / 100;
+            output = `${km} 千米 <br>${parseFloat(String(km * 0.53995)).toFixed(2)} 海里`;
+        } else {
+            output = `${Math.round(length * 100) / 100} m`;
+        }
+        return output;
+    };
+    //获取圆的面积
+    const getCircleArea = (circle, projection) => {
+        const P = 3.14
+        const radius = getCircleRadius(circle, projection)
+        return P * radius * radius
+    }
+//获取圆的半径
+    const getCircleRadius = (circle, projection) => {
+        return circle.getRadius() * projection.getMetersPerUnit()
+    }
+    const formatArea = (polygon, type= 'polygon') => {
+        let area
+        const sourceProj = map.getView().getProjection();
+        // 获取投影坐标系
+        if (type === 'polygon') {
+            area = sphere.getArea(polygon, {
+                projection: sourceProj,
+            });
+        } else if (type === 'circle') {
+            area = getCircleArea(polygon, sourceProj)
+        }
+        let output;
+        if (area > 10000) {
+            const km = Math.round((area / 1000000) * 100) / 100;
+            output = `${km} 平方公里<br>${parseFloat(String(km * 0.38610)).toFixed(
+                2
+            )} 平方英里`;
+        } else {
+            output = `${Math.round(area * 100) / 100} ` + " m<sup>2</sup>";
+        }
+        return output;
+    };
+    const addInteraction = () => {
+        const id = 'drawName'
+        const draw = new interaction.Draw({
+            source: _source,//测量绘制层数据源
+            type: typeMapper.get(typeSelect),  //几何图形类型
+            geometryFunction: typeSelect === 'rectangle' ? createBox() : null,
+            style: new style.Style({
+                fill: new style.Fill({
+                    color: "rgba(255, 255, 255, 0.2)",
+                }),
+                stroke: new style.Stroke({
+                    color: "#f3584a",
+                    width: 2,
+                }),
+                image: new style.Circle({
+                    radius: 5,
+                    stroke: new style.Stroke({
+                        color: "rgba(0, 0, 0, 0.7)",
+                    }),
+                    fill: new style.Fill({
+                        color: "rgba(255, 255, 255, 0.2)",
+                    }),
+                }),
+            }),
+        });
+        draw.set(id, id)
+        createMeasureTooltip(); //创建测量工具提示框
+        createHelpTooltip(); //创建帮助提示框
+        map.addInteraction(draw);
+        let listener;
+        //绑定交互绘制工具开始绘制的事件
+        const drawstartHandle = (evt) => {
+            sketch = evt.feature; //绘制的要素
+            let tooltipCoord = evt.coordinate;// 绘制的坐标
+            //绑定change事件,根据绘制几何类型得到测量长度值或面积值,并将其设置到测量工具提示框中显示
+            listener = sketch.getGeometry().on('change', function (evt) {
+                const geom = evt.target
+                let output;
+                if (geom.getType() === 'LineString') {
+                    output = formatLength(geom);//长度值
+                    tooltipCoord = geom.getLastCoordinate();//坐标
+                } else if (geom.getType() === 'Polygon') {
+                    output = formatArea(geom);//面积值
+                    tooltipCoord = geom.getInteriorPoint().getCoordinates();//坐标
+                } else if (geom.getType() === 'Circle') {
+                    output = formatArea(geom, 'circle');//面积值
+                    tooltipCoord = geom.getCenter()
+                }
+                measureTooltipElement.innerHTML = output;//将测量值设置到测量工具提示框中显示
+                measureTooltip.setPosition(tooltipCoord);//设置测量工具提示框的显示位置
+            });
+        }
+        draw.on('drawstart', drawstartHandle);
+        //绑定交互绘制工具结束绘制的事件
+        const copy = (value) => {
+            const str = document.createElement('input')
+            str.setAttribute('value', value)
+            document.body.appendChild(str)
+            str.select()
+            document.execCommand('copy')
+            document.body.removeChild(str)
+        }
+        const drawendHandle = (evt) => {
+            map.removeInteraction(map.getInteractions().getArray().filter(v => v.get(id) === id)[0]);
+            const del = document.createElement("div");
+            del.className = "lineDel";
+            measureTooltipElement.append(del);
+            del.onclick = () => {
+                _source.removeFeature(evt.feature)
+                const b = del.parentElement.parentElement
+                b.parentElement.removeChild(b);
+                const g = evt.feature.getGeometry()
+                if (g.getType() === 'LineString') {
+                    const w = `LINESTRING(${g.getCoordinates().map(v => v[0] + ' ' + v[1]).join(',')})`
+                    copy(w)
+                } else if (g.getType() === 'Polygon') {
+                    const w = `POLYGON(${g.getCoordinates().map(v => '(' + v.map(c => c[0] + ' ' + c[1]) + ')').join(',')})`
+                    copy(w)
+                }
+            };
+            measureTooltipElement.className = 'tooltip tooltip-static'; //设置测量提示框的样式
+            measureTooltip.setOffset([0, -7]);
+            sketch = null; //置空当前绘制的要素对象
+            measureTooltipElement = null; //置空测量工具提示框对象
+            helpTooltipElement.parentNode.removeChild(helpTooltipElement);
+            helpTooltipElement = null; //置空测量工具提示框对象
+            unByKey(listener);
+            draw.un('drawstart', drawstartHandle);
+            draw.un('drawend', drawendHandle);
+            map.removeInteraction(map.getInteractions().getArray().filter(v => v.get(id) === id)[0]);
+            map.un('pointermove', pointerMoveHandler)
+        }
+        draw.on('drawend', drawendHandle);
+    }
+    addInteraction(); //调用加载绘制交互控件方法,添加绘图进行测量
+    const pointerMoveHandler = (evt) => {
+        if (evt.dragging) {
+            return;
+        }
+        let helpMsg = '单击开始测量';//当前默认提示信息
+        //判断绘制几何类型设置相应的帮助提示信息
+        if (sketch) {
+            const geom = sketch.getGeometry()
+            helpMsg = continueMsg;
+            // if (geom.getType() === 'Polygon') {
+            //     helpMsg = continueMsg; //绘制多边形时提示相应内容
+            // } else if (geom.getType() === 'LineString') {
+            //     helpMsg = continueMsg; //绘制线时提示相应内容
+            // }
+        }
+        helpTooltipElement.innerHTML = helpMsg; //将提示信息设置到对话框中显示
+        helpTooltip.setPosition(evt.coordinate);//设置帮助提示框的位置
+        helpTooltipElement.classList.remove('hidden');//移除帮助提示框的隐藏样式进行显示
+    };
+    map.on('pointermove', pointerMoveHandler); //地图容器绑定鼠标移动事件,动态显示帮助提示框内容
+    //地图绑定鼠标移出事件,鼠标移出时为帮助提示框设置隐藏样式
+    map.getViewport().on('mouseout', () => {
+        helpTooltipElement.addClass('hidden');
+    });
+}

BIN
src/components/easyMap/images/bg-land.png


BIN
src/components/easyMap/images/bg-ocean.png


BIN
src/components/easyMap/images/bg-sky.png


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 12 - 0
src/components/easyMap/images/bg-switch.svg


+ 165 - 0
src/components/easyMap/index.vue

@@ -0,0 +1,165 @@
+<template>
+  <div class="easy-map">
+    <OlMap
+      ref="ref_olMap"
+      :baseMapLayers="_baseMapLayers"
+      :baseMapView="_baseMapView"
+      @olZoomChange="(zoom) => $emit('zoomChange', zoom)"
+      @olMapLoad="(map) => handleOlMapLoad(map)"
+    />
+    <template v-if="showBaseSwitch">
+      <div class="base-switch">
+        <el-popover
+          placement="left"
+          trigger="hover"
+          popper-class="easy-map-base-switch"
+        >
+          <template #reference>
+            <img class="__hover" src="./images/bg-switch.svg" />
+          </template>
+          <div class="base-switch-item">
+            <template v-for="item in _baseMapLayers">
+              <div
+                class="base-item __hover"
+                :class="{
+                  active: judgeBaseLayerActive(
+                    item.get('_easyMapOl_layerName')
+                  ),
+                }"
+                @click="
+                  ref_olMap.switchBaseLayer(item.get('_easyMapOl_layerName'))
+                "
+              >
+                <div class="label">{{ item.get("_label") }}</div>
+                <img :src="item.get('_img')" />
+              </div>
+            </template>
+          </div>
+        </el-popover>
+      </div>
+    </template>
+  </div>
+</template>
+
+<script lang="ts">
+import {
+  defineComponent,
+  onMounted,
+  ref,
+  toRefs,
+  reactive,
+  watch,
+  getCurrentInstance,
+  ComponentInternalInstance,
+  computed,
+  nextTick,
+} from "vue";
+import { useStore } from "vuex";
+import OlMap from "./ol-map.vue";
+import InitMapInfoClass from "./initMapInfo";
+import MeasureFunc from "./func/measure";
+import LocationFunc from "./func/location";
+
+export default defineComponent({
+  name: "EasyMap",
+  components: {
+    OlMap,
+  },
+  props: {
+    baseMapLayers: {},
+    baseMapView: {},
+    showBaseSwitch: {
+      default: false,
+    },
+  },
+  setup(props, { emit }) {
+    const store = useStore();
+    const that = (getCurrentInstance() as ComponentInternalInstance).appContext
+      .config.globalProperties;
+    const state = reactive({});
+    const ref_olMap = ref();
+    const _baseMapLayers = computed(
+      () => props.baseMapLayers || InitMapInfoClass.baseMapLayers
+    );
+    const _baseMapView = computed(
+      () => props.baseMapView || InitMapInfoClass.baseMapView
+    );
+    const easyMap = computed(() => ref_olMap.value?.easyMapOl);
+    const handleOlMapLoad = (map) => {
+      emit("easyMapLoad", map, {
+        getBBOX,
+        measure,
+        toLocation,
+        resetCenter,
+        baseLayer: {
+          switchMapper: _baseMapLayers.value,
+          switchLayer: ref_olMap.value.switchBaseLayer,
+          judgeActive: judgeBaseLayerActive,
+        },
+      });
+    };
+    const getBBOX = () => {
+      return easyMap.value.getView().calculateExtent(easyMap.value.getSize());
+    };
+    const judgeBaseLayerActive = (layerName) => {
+      return easyMap.value
+        ?.getLayers()
+        .getArray()
+        .filter((v) => v.get("_easyMapOl_layerGroupType") === "base")[0]
+        .getLayers()
+        .getArray()
+        .filter((v) => v.get("_easyMapOl_layerName") === layerName)[0]
+        ?.getVisible();
+    };
+    const measure = (type) => {
+      MeasureFunc(easyMap.value, type);
+    };
+    const toLocation = ({ position = null, zoom = null, wkt = null }) => {
+      LocationFunc({
+        map: easyMap.value,
+        position,
+        wkt,
+        zoom,
+      });
+    };
+    const resetCenter = () => {
+      easyMap.value.getView().setCenter(_baseMapView.value.center);
+      easyMap.value.getView().setZoom(_baseMapView.value.zoom);
+    };
+    onMounted(() => {
+      nextTick(() => {});
+    });
+    return {
+      ...toRefs(state),
+      ref_olMap,
+      _baseMapLayers,
+      _baseMapView,
+      easyMap,
+      getBBOX,
+      measure,
+      toLocation,
+      handleOlMapLoad,
+      judgeBaseLayerActive,
+    };
+  },
+});
+</script>
+<style scoped lang="scss">
+.easy-map {
+  width: 100%;
+  height: 100%;
+  position: relative;
+  .base-switch {
+    position: absolute;
+    z-index: 2;
+    right: 40px;
+    bottom: 70px;
+    width: 26px;
+    height: 26px;
+    background-color: #f2f8fd;
+    border-radius: 4px;
+    display: grid;
+    place-items: center;
+  }
+}
+</style>

+ 89 - 0
src/components/easyMap/initMapInfo.ts

@@ -0,0 +1,89 @@
+import * as layer from 'ol/layer'
+import * as source from 'ol/source'
+import HaituImg from './images/bg-ocean.png'
+import LutuImg from './images/bg-land.png'
+import WeixingImg from './images/bg-sky.png'
+// @ts-ignore
+import store from '@/store/index'
+
+const baseMapView = {
+  center: [109.6915958479584, 19.111636735969318],
+  projection: "EPSG:4326",
+  zoom: 9
+  // extent: [120.8953306326286,31.3667480047968,121.37735577911297,31.692561298253832]
+}
+const initBaseLayer = (obj: { key: any; name: any; label: any; maxZoom: any; minZoom: any; visible: any; img: any }) => {
+  const _layer = new layer.Tile({
+    source: new source.XYZ({
+      projection: "EPSG:4326",
+      url: `/EzServer6/Maps/${obj.key}/EzMap?Service=getImage&Type=RGB&ZoomOffset=0&Col={x}&Row={y}&Zoom={z}&V=0.3`,
+    }),
+    visible: obj.visible,
+  })
+  _layer.set('_maxZoom', obj.maxZoom)
+  _layer.set('_minZoom', obj.minZoom)
+  _layer.set('_easyMapOl_layerName', obj.name)
+  _layer.set('_label', obj.label)
+  _layer.set('_img', obj.img)
+  return _layer
+}
+const initLocalhost = (obj: { key?: string; name: any; label: any; maxZoom: any; minZoom: any; visible: any; img: any }) => {
+  const _layer = new layer.Tile({
+    className: "blueLayer",
+    source: new source.XYZ({
+      url: 'http://wprd0{1-4}.is.autonavi.com/appmaptile?lang=zh_cn&size=1&style=7&x={x}&y={y}&z={z}'
+    }),
+    visible: obj.visible,
+  })
+  _layer.set('_maxZoom', obj.maxZoom)
+  _layer.set('_minZoom', obj.minZoom)
+  _layer.set('_easyMapOl_layerName', obj.name)
+  _layer.set('_label', obj.label)
+  _layer.set('_img', obj.img)
+  return _layer
+}
+
+const baseMapLayers = [
+  initBaseLayer({
+    key: 'sea',
+    name: 'base_haitu',
+    label: '海图',
+    maxZoom: 14,
+    minZoom: 5,
+    visible: false,
+    img: HaituImg
+  }),
+  !window.location.origin.includes('localhost')
+    ? initBaseLayer({
+      key: 'tdtsl',
+      name: 'base_tianditu',
+      label: '陆图',
+      maxZoom: 20,
+      minZoom: 8,
+      visible: true,
+      img: LutuImg
+    })
+  : initLocalhost({
+      key: 'tdtsl',
+      name: 'base_tianditu',
+      label: '陆图',
+      maxZoom: 20,
+      minZoom: 8,
+      visible: true,
+      img: LutuImg
+    }),
+  initBaseLayer({
+    key: 'hnimg',
+    name: 'base_weixingtu',
+    label: '卫星遥感图',
+    maxZoom: 19,
+    minZoom: 8,
+    visible: false,
+    img: WeixingImg
+  }),
+]
+
+export default {
+  baseMapView,
+  baseMapLayers,
+}

+ 300 - 0
src/components/easyMap/ol-map.vue

@@ -0,0 +1,300 @@
+<template>
+  <div class="easy-map-ol">
+    <div class="map" ref="ref_easyMapOl"/>
+    <div class="easy-map_ol-mouse-position" ref="ref_easyMap_olMousePosition" @click="controlMousePosition.format = !controlMousePosition.format">
+      <template v-if="controlMousePosition.format">
+        {{controlMousePosition.formatLongitude}}<br/>
+        {{controlMousePosition.formatLatitude}}
+      </template>
+      <template v-else>
+        {{controlMousePosition.longitude}}<br/>
+        {{controlMousePosition.latitude}}
+      </template>
+    </div>
+    <div class="easy-map_ol-zoom" ref="ref_easyMap_olZoom">
+      <div class="easy-map_ol-zoom-button" @click="zoomChange(true)">+</div>
+      <div class="easy-map_ol-zoom-num">{{Math.floor(interactionZoom)}}</div>
+      <div class="easy-map_ol-zoom-button" @click="zoomChange(false)">-</div>
+    </div>
+    <div class="easy-map_ol-scaleLine" ref="ref_easyMap_scaleLine"></div>
+  </div>
+</template>
+
+<script lang="ts">
+  import {
+    defineComponent,
+    onMounted,
+    ref,
+    toRefs,
+    reactive,
+    watch,
+    getCurrentInstance,
+    ComponentInternalInstance,
+    computed,
+    nextTick,
+  } from "vue";
+  import { useStore } from "vuex";
+  import * as ol from 'ol'
+  import * as style from 'ol/style'
+  import * as layer from 'ol/layer'
+  import * as source from 'ol/source'
+  import * as geom from 'ol/geom'
+  import * as proj from 'ol/proj'
+  import * as interaction from 'ol/interaction'
+  import * as coordinate from 'ol/coordinate'
+  import * as control from 'ol/control'
+
+  export default defineComponent({
+    name: "",
+    components: {
+    },
+    props: {
+      baseMapLayers: { default: () => [] },
+      baseMapView: {},
+    },
+    setup(props, { emit }) {
+      const store = useStore();
+      const that = (getCurrentInstance() as ComponentInternalInstance).appContext.config.globalProperties;
+      const state = reactive({
+        controlMousePosition: {
+          longitude: <any>null,
+          latitude: <any>null,
+          format: false,
+          formatLongitude: <any>null,
+          formatLatitude: <any>null,
+        },
+        interactionZoom: props.baseMapView.zoom,
+      });
+      const easyMapOl = ref()
+      const ref_easyMapOl = ref()
+      const ref_easyMap_olMousePosition = ref()
+      const ref_easyMap_olZoom = ref()
+      const ref_easyMap_scaleLine = ref()
+      const initMap = () => {
+        easyMapOl.value = new ol.Map({
+          target: ref_easyMapOl.value,
+          layers: [
+            new layer.Group({
+              _easyMapOl_layerGroupType: 'base',
+              layers: props.baseMapLayers,
+              zIndex: 1
+            }),
+          ],
+          view: new ol.View(props.baseMapView),
+          controls: control.defaults({
+            attribution: false,
+            rotate: false,
+            zoom: false,
+          }).extend([
+            new control.MousePosition({
+              target: ref_easyMap_olMousePosition.value,
+              coordinateFormat: (e) => {
+                state.controlMousePosition.longitude = e[0]
+                state.controlMousePosition.latitude = e[1]
+                const f = coordinate.toStringHDMS(e, 0).split(' ')
+                state.controlMousePosition.formatLatitude = `${f[0]} ${f[1]} ${f[2]} ${f[3]}`
+                state.controlMousePosition.formatLongitude = `${f[4]} ${f[5]} ${f[6]} ${f[7]}`
+                return null
+              },
+              placeholder: ''
+            }),
+            new control.Zoom({
+              target: ref_easyMap_olZoom.value,
+            }),
+            new control.ScaleLine({
+              target: ref_easyMap_scaleLine.value,
+              bar: true
+            })
+          ]),
+          interactions: interaction.defaults({
+            doubleClickZoom: false
+          })
+        })
+        easyMapOl.value.getView().on('change:resolution', e => {
+          state.interactionZoom = e.target.getZoom()
+          emit('olZoomChange', state.interactionZoom)
+        })
+        const defaultBaseLayer = props.baseMapLayers.filter(v => v.getVisible())[0]
+        setLayerView(defaultBaseLayer)
+        emit('olMapLoad', easyMapOl.value)
+        easyMapOl.value.on('contextmenu', e => {
+          window.event.returnValue = false
+          if (window?.event?.shiftKey) {
+            const str = document.createElement('input')
+            str.setAttribute('value', `POINT(${e.coordinate[0]} ${e.coordinate[1]})`)
+            document.body.appendChild(str)
+            str.select()
+            document.execCommand('copy')
+            document.body.removeChild(str)
+          }
+        })
+      }
+      const zoomChange = (flag) => {
+        state.interactionZoom = flag ? state.interactionZoom + 1 : state.interactionZoom - 1
+        if (state.interactionZoom > easyMapOl.value.getView().getMaxZoom()) {
+          state.interactionZoom = easyMapOl.value.getView().getMaxZoom()
+        } else if (state.interactionZoom < easyMapOl.value.getView().getMinZoom()) {
+          state.interactionZoom = easyMapOl.value.getView().getMinZoom()
+        }
+        easyMapOl.value.getView().setZoom(state.interactionZoom)
+      }
+      const baseLayersMap = computed(() => {
+        const map = new Map()
+        easyMapOl.value?.getLayers().getArray().filter(v => v.get('_easyMapOl_layerGroupType') === 'base')[0].getLayers().getArray().forEach(v => {
+          map.set(v.get('_easyMapOl_layerName'), v)
+        })
+        return map
+      })
+      const switchBaseLayer = (layerName) => {
+        baseLayersMap.value.forEach(v => {
+          if (layerName === v.get('_easyMapOl_layerName')) {
+            setLayerView(v)
+            v.setVisible(true)
+          } else {
+            v.setVisible(false)
+          }
+        })
+      }
+      const setLayerView = (_layer) => {
+        easyMapOl.value.getView().setMaxZoom(_layer.get('_maxZoom'))
+        easyMapOl.value.getView().setMinZoom(_layer.get('_minZoom'))
+      }
+      onMounted(() => {
+        nextTick(() => {
+          initMap()
+          setTimeout(() => {
+            easyMapOl.value.updateSize();
+            easyMapOl.value.render()
+          })
+        })
+      })
+      return {
+        ...toRefs(state),
+        ref_easyMapOl,
+        ref_easyMap_olMousePosition,
+        ref_easyMap_olZoom,
+        ref_easyMap_scaleLine,
+        easyMapOl,
+        zoomChange,
+        switchBaseLayer,
+        baseLayersMap,
+      }
+    },
+  });
+</script>
+<style scoped lang="scss">
+.easy-map-ol {
+  width: 100%;
+  height: 100%;
+  position: relative;
+  .map {
+    width: 100%;
+    height: 100%;
+    background-color: #bfdbf3;
+  }
+  .easy-map_ol-mouse-position {
+    cursor: pointer;
+    position: absolute;
+    z-index: 1;
+    color: #000;
+    top: unset;
+    font-size: 14px;
+    right: 10px;
+    bottom: 10px;
+    height: 50px;
+    padding: 5px 10px;
+    background-color: #fff;
+    border-radius: 2px;
+    line-height: 22px;
+    opacity: .8;
+  }
+  .easy-map_ol-zoom {
+    position: absolute;
+    bottom: 70px;
+    right: 10px;
+    >div {
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      margin: 0;
+      padding: 0;
+      color: #000;
+      font-size: 12px;
+      font-weight: 700;
+      height: 20px;
+      width: 20px;
+      background-color: #fff;
+    }
+    .easy-map_ol-zoom-num {
+      border-top: 1px solid rgba(153, 153, 153, 0.32);
+      border-bottom: 1px solid rgba(153, 153, 153, 0.32);
+    }
+    .easy-map_ol-zoom-button {
+      cursor: pointer;
+      &:hover {
+        opacity: 0.7;
+      }
+    }
+  }
+  .easy-map_ol-scaleLine {
+    position: absolute;
+    bottom: 20px;
+    left: 20px;
+  }
+  .easy-map_switchBaseLayer {
+    position: absolute;
+    left: 20px;
+    bottom: 40px;
+  }
+  ::v-deep(.ol-zoom) {
+    display: none;
+  }
+  ::v-deep(.ol-scale-bar-inner) {
+    position: absolute;
+    bottom: 1%;
+    left: 1%;
+
+    &>div>div:nth-child(2) {
+      .ol-scale-singlebar {
+        border-left: 2px solid #807A7A;
+      }
+    }
+
+    &>div>div:nth-child(5) {
+      .ol-scale-singlebar {
+        border-right: 2px solid #807A7A;
+      }
+    }
+
+    .ol-scale-step-text {
+      padding-bottom: 20px;
+      font-size: 12px;
+      transform: scale(0.8);
+      position: absolute;
+      bottom: -5px;
+      font-size: 12px;
+      z-index: 11;
+      color: #000000;
+      text-shadow: -2px 0 #ffffff,
+      0 2px #ffffff,
+      2px 0 #ffffff,
+      0 -2px #ffffff;
+    }
+
+    .ol-scale-singlebar {
+      border: 0;
+      background-color: transparent !important;
+      border-bottom: 2px solid #807A7A;
+      height: 10px;
+    }
+
+    .ol-scale-step-marker {
+      display: none;
+    }
+  }
+  ::v-deep(.blueLayer) {
+    filter: grayscale(98%) invert(100%) sepia(20%) hue-rotate(180deg) saturate(1600%) brightness(80%) contrast(90%);
+    //filter: grayscale(100%) sepia(51%) invert(100%) saturate(350%);
+  }
+}
+</style>

+ 5 - 0
src/main.ts

@@ -8,10 +8,15 @@ import * as api from './api/index'
 import 'animate.css';
 import './style/cus-element.scss'
 import * as util from '@/utils/util'
+import EasyMapComponent from '@/components/easyMap/index.vue'
+import * as easyMap from '@/utils/easyMap'
+
 const app = createApp(App)
 app.use(router)
 app.use(store)
 app.use(ElementPlus)
 app.config.globalProperties.$util = util
 app.config.globalProperties.$api = api.default
+app.config.globalProperties.$easyMap = easyMap
+app.component('EasyMapComponent', EasyMapComponent)
 app.mount('#app')

+ 4 - 2
src/router/index.ts

@@ -14,8 +14,8 @@ const routes = [
         component: () => import('@/views/screen/index.vue'),
     },
     {
-        path: '/map',
-        component: () => import('@/views/map/index.vue'),
+        path: '/video-resource',
+        component: () => import('@/views/screen/video-resource/index.vue'),
         meta: {
             noLogin: true
         }
@@ -28,6 +28,8 @@ const router = createRouter({
 });
 
 router.beforeEach((to, from, next) => {
+    console.info(to)
+
     if (to.meta.noLogin) {
         next()
     } else {

+ 2 - 0
src/store/index.ts

@@ -1,5 +1,6 @@
 import { createStore } from "vuex";
 import app from "./modules/app";
+import easyMap from "./modules/easy-map";
 
 export default createStore({
   state: {},
@@ -7,5 +8,6 @@ export default createStore({
   actions: {},
   modules: {
     app,
+    easyMap
   },
 });

+ 0 - 1
src/store/modules/app.js

@@ -3,7 +3,6 @@ import {ElMessageBox} from "element-plus";
 
 const state = {
 	apiProxy: {
-		EzServer6Api: 'EzServer6-api',	// 地图底图代理
 	},
 	userInfo: null
 }

+ 38 - 0
src/store/modules/easy-map.ts

@@ -0,0 +1,38 @@
+const state = {
+	clickInfo: {
+		layerName: null,
+		value: null,
+		feature: null,
+		isClick: false,
+		e: null
+	},
+	hoverInfo: {
+		layerName: null,
+		value: null,
+		feature: null
+	},
+}
+
+const mutations = {
+	SET_INFO (state: { clickInfo: any; hoverInfo: any }, {data, type}: any) {
+		if (type === 'click') {
+			state.clickInfo = data
+		} else if (type === 'hover') {
+			state.hoverInfo = data
+		}
+	},
+}
+
+const actions = {
+	// @ts-ignore
+	LOAD_INFO ({ commit }, {data, type}) {
+		commit('SET_INFO', {data, type})
+	},
+}
+
+export default {
+	namespaced: true,
+	state,
+	mutations,
+	actions
+}

+ 391 - 0
src/utils/easyMap.ts

@@ -0,0 +1,391 @@
+import * as ol from 'ol'
+import * as style from 'ol/style'
+import * as layer from 'ol/layer'
+import * as source from 'ol/source'
+import * as geom from 'ol/geom'
+import * as proj from 'ol/proj'
+import * as format from 'ol/format'
+import * as extent from 'ol/extent'
+import store from '@/store/index'
+
+let hasPointClick = false
+let zIndex = 999
+let ctrlHideListGlobal = []
+const activeFeatureMap = new Map()
+const hoverFeatureMap = new Map()
+let moveFlag = false
+
+export const initShape = ({map, layerName, list, clickEl, hoverEl, hoverClick = false, clickHandle = (feature: any) => {}, layerZIndex}) => {
+  const _layers = map.getLayers().getArray().filter(v => v.get('easyMapLayerName') === layerName)
+  let realLayer = _layers.length > 0 ? _layers[0] : null
+  const features = []
+  const featuresMap = new Map()
+  list.forEach((v, i) => {
+    try {
+      const feat = new format.WKT().readFeature(v.easyMapParams.position)
+      feat.set('layerName', layerName)
+      feat.set('easyMap', v)
+      feat.set('_geom', feat.getGeometry())
+      feat.setStyle(v.easyMapParams.normalStyle)
+      feat.set('normalStyle', v.easyMapParams.normalStyle)
+      feat.set('activeStyle', v.easyMapParams.activeStyle ? v.easyMapParams.activeStyle : v.easyMapParams.normalStyle)
+      feat.set('hoverStyle', v.easyMapParams.hoverStyle ? v.easyMapParams.hoverStyle : (v.easyMapParams.activeStyle ? v.easyMapParams.activeStyle : v.easyMapParams.normalStyle))
+      feat.set('backStyle', v.easyMapParams.normalStyle)
+      feat.set('layerZ', realLayer ? realLayer.getZIndex() : layerZIndex ? layerZIndex : zIndex)
+      feat.set('featureZ', i)
+      feat.set('value', v.value)
+      feat.setId(v.easyMapParams.id)
+      v.easyMapParams.featureSetHandle?.(feat)
+      features.push(feat)
+      featuresMap.set(v.easyMapParams.id, feat)
+    } catch (e) {
+      console.log('v:\n%o  e:\n%o', v, e)
+    }
+  })
+  const vectorSource = new source.Vector({
+    features: features,
+    wrapX: false
+  });
+  let clickDialog = clickEl ? map.getOverlayById(clickEl.id) : null
+  let hoverDialog = hoverEl ? map.getOverlayById(hoverEl.id) : null
+  const clickClose = () => {
+    clickDialog?.setPosition(undefined)
+  }
+  const hoverClose = () => {
+    hoverDialog?.setPosition(undefined)
+  }
+  const setActive = (feature, isClick = false, e = null) => {
+    if (feature) {
+      feature.set('backStyle', feature.getStyle())
+      feature.setStyle(hoverFeatureMap.get(layerName)?.getId() === feature.getId() ? feature.get('hoverStyle') : feature.get('activeStyle'))
+      activeFeatureMap.set(layerName, feature)
+      store.dispatch('easyMap/LOAD_INFO', {
+        type: 'click',
+        data: {
+          layerName: layerName,
+          value: feature.get('easyMap'),
+          feature: feature,
+          isClick,
+          e
+        }
+      })
+    }
+  }
+  const setHover = (feature) => {
+    if (feature) {
+      if (hoverDialog && !(hoverClick || activeFeatureMap.get(layerName)?.getId() !== hoverFeatureMap.get(layerName)?.getId())) {
+        hoverClose()
+      }
+      feature.set('backStyle', feature.getStyle())
+      feature.setStyle(feature.get('hoverStyle'))
+      hoverFeatureMap.set(layerName, feature)
+      store.dispatch('easyMap/LOAD_INFO', {
+        type: 'hover',
+        data: {
+          layerName: layerName,
+          value: feature.get('easyMap'),
+          feature: feature
+        }
+      })
+    }
+  }
+  if (hoverFeatureMap.get(layerName)) {
+    hoverFeatureMap.set(layerName, vectorSource.getFeatureById(hoverFeatureMap.get(layerName).getId()))
+    setHover(hoverFeatureMap.get(layerName))
+  } else {
+    hoverFeatureMap.set(layerName, null)
+  }
+  if (activeFeatureMap.get(layerName)) {
+    activeFeatureMap.set(layerName, vectorSource.getFeatureById(activeFeatureMap.get(layerName).getId()))
+    setActive(activeFeatureMap.get(layerName))
+  } else {
+    activeFeatureMap.set(layerName, null)
+  }
+    if (realLayer) {
+    realLayer.setSource(vectorSource)
+  } else {
+    realLayer = new layer.VectorImage({
+      source: vectorSource,
+      easyMapLayerName: layerName,
+      layerType: 'easyMap',
+      zIndex: layerZIndex ? layerZIndex : zIndex--
+    })
+    map.addLayer(realLayer)
+    map.on('movestart', e => {
+      moveFlag = true
+      map.un('pointermove', mapPointerMove)
+      map.un('singleclick', mapSingleClick)
+      map.un('contextmenu', mapContextmenu)
+    })
+    map.on('moveend', e => {
+      map.on('singleclick', mapSingleClick)
+      map.on('pointermove', mapPointerMove)
+      map.on('contextmenu', mapContextmenu)
+      moveFlag = false
+    })
+    if (clickEl) {
+      clickDialog = setOverlay(clickEl)
+      map.addOverlay(clickDialog)
+    }
+    const mapSingleClick = e => {
+      let pointFlag = true
+      clickDialog?.setPosition(undefined)
+      // activeFeatureMap.get(layerName)?.setStyle(activeFeatureMap.get(layerName).get('normalStyle'))
+      let activeLayer = {
+        zIndex: 0,
+        layerName: null,
+      }
+      map.forEachFeatureAtPixel(e.pixel, (feature) => {
+        if (feature.get('layerZ') >= activeLayer.zIndex) {
+          activeLayer = {
+            zIndex: feature.get('layerZ'),
+            layerName: feature.get('layerName'),
+          }
+        }
+      }, {
+        hitTolerance: 0,
+      });
+      map.forEachFeatureAtPixel(e.pixel, (feature) => {
+        if (activeLayer.layerName === layerName && feature.get('layerName') === layerName && !hasPointClick) {
+          if (pointFlag) {
+            hasPointClick = true
+            if (activeFeatureMap.get(layerName)) {
+              activeFeatureMap.get(layerName).set('backStyle', activeFeatureMap.get(layerName).getStyle())
+              activeFeatureMap.get(layerName).setStyle(feature.get('normalStyle'))
+            }
+            pointFlag = false
+            if (!hoverClick) {
+              hoverClose()
+              hoverFeatureMap.delete(layerName)
+            }
+            setActive(feature, true, e)
+            clickHandle(feature)
+            if (clickDialog) {
+              if (feature.getGeometry().getType() !== 'Point') {
+                clickDialog.setPosition(e.coordinate)
+              } else {
+                clickDialog.setPosition(feature.getGeometry().getCoordinates())
+              }
+            }
+            setTimeout(() => {
+              hasPointClick = false
+            }, 100)
+          }
+        }
+      }, {
+        hitTolerance: 0,
+      });
+    }
+    map.on('singleclick', mapSingleClick)
+    if (hoverEl) {
+      hoverDialog = setOverlay(hoverEl)
+      map.addOverlay(hoverDialog)
+    }
+    let pointerMoveTime = null
+    const mapPointerMove = e => {
+      clearTimeout(pointerMoveTime)
+      pointerMoveTime = setTimeout(() => {
+        if (!moveFlag) {
+          let isFeature = false
+          let hoverLayer = {
+            zIndex: 0,
+            layerName: null
+          }
+          map.forEachFeatureAtPixel(e.pixel, (feature) => {
+            if (feature.get('layerZ') > hoverLayer.zIndex) {
+              hoverLayer = {
+                zIndex: feature.get('layerZ'),
+                layerName: feature.get('layerName')
+              }
+            }
+            isFeature = true
+          }, {
+            hitTolerance: 0,
+          });
+          const reset = () => {
+            hoverDialog?.setPosition(undefined)
+            hoverFeatureMap.get(layerName)?.setStyle(hoverFeatureMap.get(layerName).get('backStyle'))
+            hoverFeatureMap.delete(layerName)
+          }
+          if (layerName !== hoverLayer.layerName) {
+            reset()
+          }
+          if (!isFeature) {
+            reset()
+          }
+          let pointFlag = true
+          map.forEachFeatureAtPixel(e.pixel, (feature) => {
+            if (feature.get('layerName') === layerName) {
+              if (pointFlag) {
+                if (layerName !== hoverLayer.layerName) {
+                  hoverDialog?.setPosition(undefined)
+                } else {
+                  pointFlag = false
+                  if (hoverFeatureMap.get(layerName)?.getId() !== feature.getId()) {
+                    if (feature.getId() !== hoverFeatureMap.get(layerName)?.getId()) {
+                      reset()
+                    }
+                    setHover(feature)
+                    if (hoverDialog && (hoverClick || activeFeatureMap.get(layerName)?.getId() !== hoverFeatureMap.get(layerName)?.getId())) {
+                      if (feature.getGeometry().getType() !== 'Point') {
+                        hoverDialog.setPosition(e.coordinate)
+                      } else {
+                        hoverDialog.setPosition(feature.getGeometry().getCoordinates())
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          }, {
+            hitTolerance: 0,
+          });
+        }
+      }, 10)
+    }
+    map.on('pointermove', mapPointerMove)
+    let ctrlHideList = []
+    const mapContextmenu = e => {
+      let isFeature = false
+      let hoverLayer = {
+        zIndex: 0,
+        layerName: null
+      }
+      map.forEachFeatureAtPixel(e.pixel, (feature) => {
+        if (feature.get('layerZ') > hoverLayer.zIndex) {
+          hoverLayer = {
+            zIndex: feature.get('layerZ'),
+            layerName: feature.get('layerName')
+          }
+        }
+        isFeature = true
+      }, {
+        hitTolerance: 0,
+      });
+      if (ctrlHideList.length > 0 && !window?.event?.ctrlKey && !window?.event.altKey) {
+        if (ctrlHideListGlobal[ctrlHideListGlobal.length - 1] === ctrlHideList[ctrlHideList.length - 1]) {
+          setTimeout(() => {
+            switchVisible([ctrlHideList.pop()], true)
+            ctrlHideListGlobal.pop()
+          }, 100)
+        }
+      } else if (ctrlHideList.length > 0 && window?.event.altKey) {
+        switchVisible(ctrlHideList, true)
+        ctrlHideList = []
+        ctrlHideListGlobal = []
+      }
+      let pointFlag = true
+      map.forEachFeatureAtPixel(e.pixel, (feature) => {
+        if (feature.get('layerName') === layerName) {
+          if (pointFlag) {
+            if (feature.get('layerName') === hoverLayer.layerName) {
+              pointFlag = false
+              if (window?.event?.ctrlKey) {
+                switchVisible([feature.get('easyMap').easyMapParams.id], false)
+                ctrlHideList.push(feature.get('easyMap').easyMapParams.id)
+                ctrlHideListGlobal.push(feature.get('easyMap').easyMapParams.id)
+              }
+            }
+          }
+        }
+      }, {
+        hitTolerance: 0,
+      });
+    }
+    map.on('contextmenu', mapContextmenu)
+  }
+  const switchVisible = (arr, show) => {
+    arr.forEach(v => {
+      const feat = featuresMap.get(v)
+      if (show) {
+        feat.setGeometry(feat.get('_geom'))
+      } else {
+        if (feat.getGeometry().getCoordinates().toString() !== [0, 0].toString()) {
+          feat.setGeometry(new geom.Point([0, 0]))
+        }
+      }
+    })
+  }
+  const removeRealLayer = () => {
+    map.removeOverlay(clickDialog)
+    map.removeOverlay(hoverDialog)
+    map.removeLayer(realLayer)
+  }
+  return {
+    clickDialog, hoverDialog, clickClose, hoverClose, switchVisible, features, realLayer, removeRealLayer, setActive
+  }
+}
+
+const setOverlay = (el) => {
+  const over = new ol.Overlay({
+    id: el.id,
+    element: el.element,
+    autoPan: false,
+    offset: el.offset,
+    positioning: el.positioning,
+    stopEvent: true,
+    autoPanAnimation: {
+      duration: 250
+    }
+  })
+  return over
+}
+
+/**
+ *
+ * @param map         地图实例,传了直接定位到中心点最大可视范围,不传返回中心点和最大分辨率
+ * @param position    坐标数组
+ * @param L           缩放比例系数,数值越小,要素边界越靠近中心
+ */
+export const getShapeView = (map, position, L = 600) => {
+  const center = extent.getCenter(extent.boundingExtent(position))
+  let x = 0
+  let y = 0
+  position.forEach(v => {
+    if (Math.abs(v[0] - center[0]) > x) {
+      x = Math.abs(v[0] - center[0])
+    }
+    if (Math.abs(v[1] - center[1]) > y) {
+      y = Math.abs(v[1] - center[1])
+    }
+  })
+  const resolution = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)) / (L / document.body.clientWidth * document.body.clientHeight)
+  if (map) {
+    map.getView().animate({
+      center, resolution
+    })
+  }
+  return {
+    center, resolution
+  }
+}
+
+export const formatPosition = {
+  wptTwl: (arr) => {  // WKT POINT ARR TO WKT LINESTRING
+    const temp = arr.map(v => new format.WKT().readFeature(v).getGeometry().getCoordinates())
+    return new format.WKT().writeGeometry(new geom.LineString(proj.fromLonLat(temp, 'EPSG:4326')), {
+      dataProjection: 'EPSG:4326'
+    })
+  },
+  cptTwpt: (cpt) => {  // coordinates POINT TO WKT POINT
+    return `POINT(${cpt[0]} ${cpt[1]})`
+  },
+  wptTcpt: (wpt) => {  // WKT POINT TO coordinates POINT
+    return new format.WKT().readFeature(wpt).getGeometry().getCoordinates()
+  },
+  wpnTcpn: (wpn) => {  // WKT POLYGON TO coordinates POLYGON
+    return new format.WKT().readFeature(wpn).getGeometry().getCoordinates()
+  },
+  cpnTwpn: (cpn) => {  // coordinates POLYGON TO WKT POLYGON
+    return `POLYGON(${cpn.map(v => '(' + v.map(c => `${c[0]} ${c[1]}`).join(',') + ')')})`
+  },
+  cmpnTwmpn: (cmpt) => {  // coordinates MULTIPOLYGON TO WKT MULTIPOLYGON
+    return `MULTIPOLYGON(${cmpt.map(v1 => `(${v1.map(v => '(' + v.map(c => `${c[0]} ${c[1]}`).join(',') + ')')})`)})`
+  },
+  wmpnTcmpn: (wmpn) => {  // WKT MULTIPOLYGON TO coordinates MULTIPOLYGON
+    return new format.WKT().readFeature(wmpn).getGeometry().getCoordinates()
+  },
+  wlTcl: (wl) => {  // WKT LINESTRING TO coordinates LINESTRING
+    return new format.WKT().readFeature(wl).getGeometry().getCoordinates()
+  }
+}

+ 0 - 38
src/views/map/index.vue

@@ -1,38 +0,0 @@
-<template>
-  地图
-</template>
-
-<script lang="ts">
-import {
-  defineComponent,
-  computed,
-  onMounted,
-  ref,
-  reactive,
-  watch,
-  getCurrentInstance,
-  ComponentInternalInstance,
-  toRefs,
-  nextTick
-} from 'vue'
-import {useStore} from 'vuex'
-import {useRouter, useRoute} from 'vue-router'
-
-export default defineComponent({
-  name: '',
-  components: {},
-  setup() {
-    const store = useStore();
-    const router = useRouter();
-    const route = useRoute();
-    const that = (getCurrentInstance() as ComponentInternalInstance).appContext.config.globalProperties
-    const state = reactive({})
-    return {
-      ...toRefs(state)
-    }
-  },
-})
-</script>
-
-<style scoped lang="scss">
-</style>

BIN
src/views/screen/video-resource/22.png


+ 86 - 0
src/views/screen/video-resource/index.vue

@@ -0,0 +1,86 @@
+<template>
+  <div class="video-resource">
+    <EasyMapComponent
+        class="map"
+        :showBaseSwitch="false"
+        @easyMapLoad="mapLoad"
+    />
+  </div>
+</template>
+
+<script lang="ts">
+import {
+  defineComponent,
+  ref,
+  nextTick,
+  onMounted,
+  watch,
+  computed,
+  ComponentInternalInstance,
+  reactive,
+  toRefs,
+  getCurrentInstance
+} from 'vue'
+import {useStore} from 'vuex'
+import axios from "axios";
+import {ElMessage, ElMessageBox} from "element-plus";
+import MapStyle from "@/views/screen/video-resource/map-style";
+
+export default defineComponent({
+  name: 'App',
+  components: {},
+  setup() {
+    const store = useStore()
+    const that = (getCurrentInstance() as ComponentInternalInstance).appContext.config.globalProperties
+    const state = reactive({
+      map: <any>null,
+      mapFunc: null,
+      videoLayer: null
+    });
+    const mapLoad = (map: null, func: null) => {
+      state.map = map
+      state.mapFunc = func
+      that.$easyMap.initShape({
+        map: state.map,
+        layerName: "track-point-line",
+        layerZIndex: 7,
+        list: [
+          {
+            easyMapParams: {
+              id: `1`,
+              position: 'POINT(109.19 19.45)',
+              normalStyle: MapStyle.videoPointStyle()
+            }
+          },
+          {
+            easyMapParams: {
+              id: `2`,
+              position: 'POLYGON((108.26 19.07, 110.19 18.45, 111.19 20.45,109.19 19.45))',
+              normalStyle: MapStyle.normalStyleArea()
+            }
+          },
+        ]
+      });
+      const addFeatures = (arr: any) => {}
+      const delFeatures = (arr: any) => {}
+    }
+
+    return {
+      ...toRefs(state),
+      mapLoad,
+    }
+  }
+})
+</script>
+
+<style lang="scss" scoped>
+.video-resource {
+  width: 100%;
+  height: 100%;
+  position: relative;
+  .map {
+    width: 100%;
+    height: 100vh;
+  }
+}
+</style>

+ 41 - 0
src/views/screen/video-resource/map-style.ts

@@ -0,0 +1,41 @@
+import * as ol from 'ol'
+import * as style from 'ol/style'
+import * as layer from 'ol/layer'
+import * as source from 'ol/source'
+import * as geom from 'ol/geom'
+import * as proj from 'ol/proj'
+import * as interaction from 'ol/interaction'
+import * as extent from "ol/extent";
+import * as format from "ol/format";
+import { Coordinate } from 'ol/coordinate'
+import * as turf from '@turf/turf'
+import VideoImg from './22.png'
+
+const videoPointStyle = () => {
+    const _style = []
+    const img = VideoImg
+    _style.push(new style.Style({
+        image: new style.Icon({
+            src: `.${img}`,
+            scale: 1
+        })
+    }))
+    return _style
+}
+const normalStyleArea = () => {
+    const _style = []
+    _style.push(new style.Style({
+        stroke: new style.Stroke({
+            color: '#ed3880',
+            width: 2,
+        }),
+        fill: new style.Fill({
+            color: 'rgba(47,232,217,0.35)',
+        }),
+    }))
+    return _style
+}
+export default {
+    videoPointStyle,
+    normalStyleArea
+}

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 2152 - 478
yarn.lock