|
|
@@ -1,185 +1,210 @@
|
|
|
<template>
|
|
|
<div ref="mapContainer" class="map-container"></div>
|
|
|
+ <div class="map-container cad-container" id="map2dContainer"></div>
|
|
|
<div v-if="!isTopLevel" class="map-reset-btn">
|
|
|
- <Button type="primary" @click="reset">重置</Button>
|
|
|
+ <Button type="primary" @click="revertStack">返回上级</Button>
|
|
|
+ </div>
|
|
|
+ <div
|
|
|
+ id="map-copyright"
|
|
|
+ style="
|
|
|
+ position: absolute;
|
|
|
+ bottom: 10px;
|
|
|
+ left: 500px;
|
|
|
+ z-index: 1000;
|
|
|
+ background: rgba(0, 0, 0, 0.2);
|
|
|
+ color: white;
|
|
|
+ padding: 2px 5px;
|
|
|
+ font-size: 12px;
|
|
|
+ border-radius: 3px;
|
|
|
+ "
|
|
|
+ >
|
|
|
+ © 高德地图
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
|
<script lang="ts" setup>
|
|
|
+ import 'vjmap/dist/vjmap.min.css';
|
|
|
import { ref, onMounted, onUnmounted, computed } from 'vue';
|
|
|
- import L from 'leaflet';
|
|
|
- import 'leaflet/dist/leaflet.css';
|
|
|
import { Button } from 'ant-design-vue';
|
|
|
- import { getMarkers } from '/@/api/sys/map';
|
|
|
- import { DEFAULT_LAYER_ID, regionColorMap, tileLayerConfigs, generatePopupContent, getRootMarkerIcon, GEOJSON_LAYER_ID } from './simpleMap.data';
|
|
|
import { useAppStore } from '/@/store/modules/app';
|
|
|
- import { isEmpty } from '/@/utils/is';
|
|
|
- import { useRoute } from 'vue-router';
|
|
|
- import { PageEnum } from '/@/enums/pageEnum';
|
|
|
+ // import { useRoute } from 'vue-router';
|
|
|
+ import vjmap from 'vjmap';
|
|
|
+ import type vjmap3d from 'vjmap3d';
|
|
|
+ import { getGeoJSON } from '/@/api/sys/map';
|
|
|
+ import { useMineDepartmentStore } from '/@/store/modules/mine';
|
|
|
+ import { get, last } from 'lodash-es';
|
|
|
+ import { env } from '/@/views/system/cadFile/env';
|
|
|
+ import { StatusColorEnum } from '/@/enums/jeecgEnum';
|
|
|
+ import { generatePopupContent, generateSimplePopup } from './SimpleMap/simpleMap.data';
|
|
|
+ import { initMap2d } from '/@/views/system/cadFile/app';
|
|
|
|
|
|
const appStore = useAppStore();
|
|
|
- const route = useRoute();
|
|
|
- const mapContainer = ref(null);
|
|
|
-
|
|
|
- const isTopLevel = computed(() => {
|
|
|
- return isEmpty(appStore.getSimpleMapParams);
|
|
|
- });
|
|
|
-
|
|
|
- let map: L.Map | null = null;
|
|
|
-
|
|
|
- // 图层组 Map(基于所有区域编码初始化)
|
|
|
- const layerMap = new Map<string, L.LayerGroup>([
|
|
|
- [DEFAULT_LAYER_ID, L.featureGroup()],
|
|
|
- [GEOJSON_LAYER_ID, L.featureGroup()],
|
|
|
- // // 西安
|
|
|
- // ['1566101', L.featureGroup()],
|
|
|
- // // 铜川
|
|
|
- // ['1566102', L.featureGroup()],
|
|
|
- // // 宝鸡
|
|
|
- // ['1566103', L.featureGroup()],
|
|
|
- // // 咸阳
|
|
|
- // ['1566104', L.featureGroup()],
|
|
|
- // // 渭南
|
|
|
- // ['1566105', L.featureGroup()],
|
|
|
- // // 延安
|
|
|
- // ['1566106', L.featureGroup()],
|
|
|
- // // 汉中
|
|
|
- // ['1566107', L.featureGroup()],
|
|
|
- // // 榆林
|
|
|
- // ['1566108', L.featureGroup()],
|
|
|
- // // 安康
|
|
|
- // ['1566109', L.featureGroup()],
|
|
|
- // // 商洛
|
|
|
- // ['1566111', L.featureGroup()],
|
|
|
- ]);
|
|
|
-
|
|
|
- onMounted(async () => {
|
|
|
- if (!mapContainer.value) return;
|
|
|
-
|
|
|
- reset();
|
|
|
-
|
|
|
- map = L.map(mapContainer.value, {
|
|
|
- center: [35.841, 108.94],
|
|
|
- zoom: 7,
|
|
|
- zoomControl: false,
|
|
|
- attributionControl: false,
|
|
|
+ const mineStore = useMineDepartmentStore();
|
|
|
+ appStore.setSimpleMapParams({ deptId: mineStore.getRootId });
|
|
|
+ // const route = useRoute();
|
|
|
+
|
|
|
+ const mapContainer = ref<HTMLElement>();
|
|
|
+ let map: vjmap.Map;
|
|
|
+ let app: vjmap3d.App;
|
|
|
+ let cadOpened = false;
|
|
|
+
|
|
|
+ const GEO_LAYER_ID = 'geojson-layer';
|
|
|
+ const CIRCLE_LAYER_ID = 'circle-layer';
|
|
|
+ const SYMBOL_LAYER_ID = 'symbol-layer';
|
|
|
+ const DEFAULT_NODE = {
|
|
|
+ id: mineStore.getRootId!,
|
|
|
+ name: '根节点',
|
|
|
+ parentId: null,
|
|
|
+ longitude: 108.367283,
|
|
|
+ latitude: 36.024691,
|
|
|
+ zoom: 6,
|
|
|
+ };
|
|
|
+
|
|
|
+ const historyStack = ref([DEFAULT_NODE]); // 用于存储历史节点的栈,实现返回上一级功能
|
|
|
+ const isTopLevel = computed(() => historyStack.value.length === 1);
|
|
|
+
|
|
|
+ function initMapGeoJSON(map: vjmap.Map, geojson) {
|
|
|
+ map.addSource('geojson-data', {
|
|
|
+ type: 'geojson',
|
|
|
+ data: geojson,
|
|
|
+ generateId: true,
|
|
|
});
|
|
|
+ map.addFillLayer(GEO_LAYER_ID, 'geojson-data', {
|
|
|
+ fillColor: ['get', 'fillColor'],
|
|
|
+ fillOpacity: ['case', ['to-boolean', ['feature-state', 'hover']], 0.6, 0.2],
|
|
|
+ fillOutlineColor: '#ff9100', // 边线颜色,没错,确实没有边线宽度这个选项,所以有了下面的LineLayer做边线
|
|
|
+ // filter: ['in', last(historyStack.value) as string, ['get', 'children']],
|
|
|
+ });
|
|
|
+ map.addLineLayer('geoline-layer', 'geojson-data', {
|
|
|
+ lineColor: '#ff9100',
|
|
|
+ lineWidth: 2,
|
|
|
+ });
|
|
|
+ // map.hoverPointer([GEO_LAYER_ID]);
|
|
|
+ map.hoverFeatureState(GEO_LAYER_ID);
|
|
|
+ }
|
|
|
|
|
|
- initTileLayers();
|
|
|
-
|
|
|
- if (route.path === PageEnum.BASE_HOME) {
|
|
|
- await initMarkers();
|
|
|
- await initGeoJSON();
|
|
|
- }
|
|
|
-
|
|
|
- layerMap.get(DEFAULT_LAYER_ID)?.addTo(map);
|
|
|
- });
|
|
|
-
|
|
|
- onUnmounted(() => {
|
|
|
- map?.remove();
|
|
|
- });
|
|
|
-
|
|
|
- /** 初始化瓦片图层 */
|
|
|
- function initTileLayers() {
|
|
|
- tileLayerConfigs.forEach((config) => {
|
|
|
- const layer = L.tileLayer(config.url, config.options);
|
|
|
- if (config.addByDefault) {
|
|
|
- layer.addTo(map!);
|
|
|
+ function initMapMarker(map: vjmap.Map, markers) {
|
|
|
+ // 绘制背景圆圈
|
|
|
+ const circles = new vjmap.Circle({
|
|
|
+ layerId: CIRCLE_LAYER_ID,
|
|
|
+ data: markers,
|
|
|
+ // 根据hover不同的状态设置不同的颜色值
|
|
|
+ circleColor: ['case', ['to-boolean', ['feature-state', 'hover']], StatusColorEnum.gray, ['get', 'fillColor']],
|
|
|
+ // 根据hover不同的状态设置不同的宽度值
|
|
|
+ circleStrokeWidth: 1,
|
|
|
+ circleRadius: ['case', ['to-boolean', ['get', 'isLeaf']], 8, 16],
|
|
|
+ // 根据用户所属部门进行初步筛选
|
|
|
+ filter: ['==', last(historyStack.value)!.id, ['get', 'parentId']],
|
|
|
+ });
|
|
|
+ circles.addTo(map);
|
|
|
+ // 设置 hover 鼠标指针样式和状态更新
|
|
|
+ circles.hoverPointer();
|
|
|
+ circles.hoverFeatureState();
|
|
|
+ circles.hoverPopup((f) => {
|
|
|
+ if (f.properties.isLeaf) {
|
|
|
+ return generatePopupContent(f.properties);
|
|
|
+ } else {
|
|
|
+ return generateSimplePopup(f.properties);
|
|
|
}
|
|
|
});
|
|
|
- }
|
|
|
|
|
|
- /** 加载 GeoJSON 并添加到对应图层组 */
|
|
|
- async function initGeoJSON() {
|
|
|
- const response = await fetch('/js/shanxi.geo.json');
|
|
|
- const ShanXiGeoJSON = await response.json();
|
|
|
-
|
|
|
- const geoJsonLayer = L.geoJSON(ShanXiGeoJSON, {
|
|
|
- style(feature) {
|
|
|
- const gb = feature.properties.gb.slice(0, -2);
|
|
|
- return {
|
|
|
- fillColor: regionColorMap[gb] || '#14baff',
|
|
|
- fillOpacity: 0.2,
|
|
|
- weight: 2,
|
|
|
- opacity: 1,
|
|
|
- color: '#ff9100',
|
|
|
- };
|
|
|
- },
|
|
|
- onEachFeature(_, layer) {
|
|
|
- layer.on({
|
|
|
- mouseover: (e) => {
|
|
|
- e.target.setStyle({ weight: 2, fillOpacity: 0.6 });
|
|
|
- e.target.bringToFront();
|
|
|
- },
|
|
|
- mouseout: (e) => {
|
|
|
- geoJsonLayer.resetStyle(e.target);
|
|
|
- },
|
|
|
- });
|
|
|
- },
|
|
|
+ const symbols = new vjmap.Symbol({
|
|
|
+ layerId: SYMBOL_LAYER_ID,
|
|
|
+ data: markers,
|
|
|
+ textField: ['case', ['to-boolean', ['get', 'isLeaf']], '', ['get', 'count']],
|
|
|
+ textFont: ['Arial Unicode MS Regular'],
|
|
|
+ textSize: 16,
|
|
|
+ textAllowOverlap: true,
|
|
|
+ textColor: '#ffffff',
|
|
|
+ filter: ['==', last(historyStack.value)!.id, ['get', 'parentId']],
|
|
|
});
|
|
|
+ symbols.addTo(map);
|
|
|
|
|
|
- map.addLayer(geoJsonLayer);
|
|
|
- // geoJsonLayer.addTo(layerMap.get(GEOJSON_LAYER_ID));
|
|
|
- // layerMap.forEach((group, code) => {
|
|
|
- // const features = ShanXiGeoJSON.features.filter((feature: any) => {
|
|
|
- // if (code === DEFAULT_LAYER_ID) return true;
|
|
|
- // return feature.properties.gb.startsWith(code);
|
|
|
- // });
|
|
|
- // });
|
|
|
+ circles.clickLayer((e) => {
|
|
|
+ if (e.defaultPrevented) return; // 如果事件之前阻止了,则不再执行了
|
|
|
+ historyStack.value.push(get(e, 'features[0].properties', DEFAULT_NODE));
|
|
|
+ markerClickHandler();
|
|
|
+ e.preventDefault(); // 阻止之后的事件执行
|
|
|
+ });
|
|
|
}
|
|
|
|
|
|
- /** 初始化所有标记点 */
|
|
|
- async function initMarkers() {
|
|
|
- const records = await getMarkers({ pageNo: 0, pageSize: 9999 });
|
|
|
+ function markerClickHandler() {
|
|
|
+ const node: any = last(historyStack.value);
|
|
|
+ if (!node) return;
|
|
|
|
|
|
- records.forEach((item, index) => {
|
|
|
- if (!layerMap.has(item.id)) {
|
|
|
- layerMap.set(item.id, L.featureGroup());
|
|
|
- }
|
|
|
- // 创建根标记点
|
|
|
- const iconConfig = getRootMarkerIcon(40, item.children.length, Object.values(regionColorMap)[index]);
|
|
|
-
|
|
|
- const marker = L.marker([item.lat, item.lng], {
|
|
|
- icon: L.divIcon(iconConfig),
|
|
|
- riseOnHover: true,
|
|
|
- }).on('click', () => {
|
|
|
- // 将绑定到该标记点的所有子标记点添加到地图上
|
|
|
- layerMap.forEach((group, code) => {
|
|
|
- map?.removeLayer(group);
|
|
|
- if (code === item.id) {
|
|
|
- map?.addLayer(group);
|
|
|
- map?.flyToBounds(group.getBounds());
|
|
|
- // map?.flyToBounds(layerMap.get(item.id).getBounds());
|
|
|
- }
|
|
|
- });
|
|
|
- appStore.setSimpleMapParams({ mineCode: item.mineCode });
|
|
|
+ appStore.setSimpleMapParams({ deptId: node.id });
|
|
|
+
|
|
|
+ if (node.isLeaf) {
|
|
|
+ document.getElementById('map2dContainer')!.style.display = 'block';
|
|
|
+ initMap2d('map2dContainer').then((r) => {
|
|
|
+ app = r!;
|
|
|
+ cadOpened = true;
|
|
|
});
|
|
|
- // 将该标记点添加到默认地图上
|
|
|
- marker.addTo(layerMap.get(DEFAULT_LAYER_ID)!);
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
- // 创建子标记点
|
|
|
- if (!item.children.length) return;
|
|
|
+ map.setFilter(CIRCLE_LAYER_ID, ['==', node.id, ['get', 'parentId']]);
|
|
|
+ map.setFilter(SYMBOL_LAYER_ID, ['==', node.id, ['get', 'parentId']]);
|
|
|
+ // map.setFilter(GEO_LAYER_ID, ['in', node.id, ['get', 'children']]);
|
|
|
|
|
|
- item.children.forEach((child: any) => {
|
|
|
- const popupContent = generatePopupContent(child);
|
|
|
- const childMarker = L.marker([child.lat, child.lng]).bindPopup(popupContent);
|
|
|
- childMarker.addTo(layerMap.get(item.id)!);
|
|
|
- });
|
|
|
+ map.flyTo({
|
|
|
+ center: [node.longitude, node.latitude],
|
|
|
+ zoom: node.zoom,
|
|
|
});
|
|
|
}
|
|
|
|
|
|
- /** 重置视图到默认图层 */
|
|
|
- function reset() {
|
|
|
- layerMap.forEach((group, code) => {
|
|
|
- map?.removeLayer(group);
|
|
|
- if (code === DEFAULT_LAYER_ID) {
|
|
|
- map?.addLayer(group);
|
|
|
- map?.flyToBounds(group.getBounds());
|
|
|
- }
|
|
|
+ function revertStack() {
|
|
|
+ if (cadOpened) {
|
|
|
+ document.getElementById('map2dContainer')!.style.display = 'none';
|
|
|
+ app.destroy();
|
|
|
+ }
|
|
|
+ if (historyStack.value.length > 1) {
|
|
|
+ historyStack.value.pop();
|
|
|
+ markerClickHandler();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ async function initMap(HTMLElement) {
|
|
|
+ let svc = new vjmap.Service(env.serviceUrl, env.accessToken);
|
|
|
+ map = new vjmap.Map({
|
|
|
+ container: HTMLElement,
|
|
|
+ // 这个zoom配合了getGeoJSON,要改两边都要改
|
|
|
+ maxZoom: 20,
|
|
|
+ minZoom: 1,
|
|
|
+ center: [DEFAULT_NODE.longitude, DEFAULT_NODE.latitude],
|
|
|
+ zoom: DEFAULT_NODE.zoom,
|
|
|
+ // style: {
|
|
|
+ // version: 8,
|
|
|
+ // name: 'my-style',
|
|
|
+ // // 关键:配置字体服务地址
|
|
|
+ // glyphs: 'https://fonts.vjmap.com/{fontstack}/{range}.pbf',
|
|
|
+ // sources: {},
|
|
|
+ // layers: [],
|
|
|
+ // },
|
|
|
+ style: svc.rasterStyle('https://webrd01.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=7&x={x}&y={y}&z={z}'),
|
|
|
});
|
|
|
+ // const [geojson, __, markers] = await getGeoJSON({ deptId: mineStore.getRoot?.id, pageSize: 9999 });
|
|
|
+ const [___, [geojson, __, markers]] = await Promise.all([map.onLoad(), getGeoJSON({ deptId: mineStore.getRootId, pageSize: 9999 })]);
|
|
|
|
|
|
- appStore.setSimpleMapParams({});
|
|
|
+ // await map.onLoad();
|
|
|
+ // initMapWMS(map);
|
|
|
+ initMapGeoJSON(map, geojson);
|
|
|
+ initMapMarker(map, markers);
|
|
|
}
|
|
|
+
|
|
|
+ onMounted(() => {
|
|
|
+ if (!mineStore.getRoot?.isLeaf) {
|
|
|
+ initMap(mapContainer.value!);
|
|
|
+ } else {
|
|
|
+ document.getElementById('map2dContainer')!.style.display = 'block';
|
|
|
+ initMap2d('map2dContainer')!.then((r) => (app = r!));
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ onUnmounted(() => {
|
|
|
+ map?.remove();
|
|
|
+ app?.destroy();
|
|
|
+ });
|
|
|
</script>
|
|
|
|
|
|
<style lang="less">
|
|
|
@@ -194,24 +219,89 @@
|
|
|
// filter: grayscale(80%) invert(0%) sepia(10%) hue-rotate(150deg) saturate(200%) brightness(100%) contrast(100%);
|
|
|
}
|
|
|
|
|
|
+ .cad-container {
|
|
|
+ display: none;
|
|
|
+ z-index: @cad-map-z-index;
|
|
|
+ background: @map-bg !important;
|
|
|
+ }
|
|
|
+
|
|
|
+ // .map-container canvas {
|
|
|
.light-blue-theme {
|
|
|
filter: invert(0.1) hue-rotate(190deg) saturate(2);
|
|
|
// filter: sepia(0.3) hue-rotate(180deg) saturate(1.8);
|
|
|
}
|
|
|
|
|
|
- .leaflet-popup {
|
|
|
+ // .leaflet-popup {
|
|
|
+ // color: @white;
|
|
|
+ // &-content-wrapper {
|
|
|
+ // background-color: @map-popup-bg;
|
|
|
+ // }
|
|
|
+
|
|
|
+ // &-tip {
|
|
|
+ // background-color: @map-popup-bg;
|
|
|
+ // }
|
|
|
+
|
|
|
+ // .leaflet-popup-content {
|
|
|
+ // margin: 13px 20px;
|
|
|
+ // min-width: 280px;
|
|
|
+ // // &__popup {
|
|
|
+ // // }
|
|
|
+
|
|
|
+ // &__divider {
|
|
|
+ // height: 1px;
|
|
|
+ // background-color: @white;
|
|
|
+ // margin: 10px 5px;
|
|
|
+ // }
|
|
|
+
|
|
|
+ // &__title {
|
|
|
+ // color: @white;
|
|
|
+ // text-align: center;
|
|
|
+ // }
|
|
|
+
|
|
|
+ // &__board {
|
|
|
+ // padding: 10px;
|
|
|
+ // border-radius: 5px;
|
|
|
+ // background-color: @map-popup-board-bg;
|
|
|
+ // display: flex;
|
|
|
+ // justify-content: space-between;
|
|
|
+ // }
|
|
|
+
|
|
|
+ // &__table {
|
|
|
+ // color: @white;
|
|
|
+ // text-align: center;
|
|
|
+
|
|
|
+ // thead {
|
|
|
+ // height: 20px;
|
|
|
+ // }
|
|
|
+ // tbody {
|
|
|
+ // tr {
|
|
|
+ // background-color: @map-popup-table-th-bg;
|
|
|
+ // }
|
|
|
+ // tr:nth-child(even) {
|
|
|
+ // background-color: @map-popup-table-theven-bg;
|
|
|
+ // }
|
|
|
+ // td {
|
|
|
+ // padding: 5px;
|
|
|
+ // }
|
|
|
+ // }
|
|
|
+ // }
|
|
|
+ // }
|
|
|
+ // }
|
|
|
+
|
|
|
+ .vjmapgis-popup {
|
|
|
color: @white;
|
|
|
- &-content-wrapper {
|
|
|
- background-color: @map-popup-bg;
|
|
|
- }
|
|
|
+ // &-content-wrapper {
|
|
|
+ // background-color: @map-popup-bg;
|
|
|
+ // }
|
|
|
|
|
|
&-tip {
|
|
|
background-color: @map-popup-bg;
|
|
|
}
|
|
|
|
|
|
- .leaflet-popup-content {
|
|
|
- margin: 13px 20px;
|
|
|
- min-width: 280px;
|
|
|
+ .vjmapgis-popup-content {
|
|
|
+ // margin: 13px 20px;
|
|
|
+ // min-width: 300px;
|
|
|
+ background-color: @map-popup-bg;
|
|
|
// &__popup {
|
|
|
// }
|
|
|
|
|
|
@@ -226,10 +316,18 @@
|
|
|
text-align: center;
|
|
|
}
|
|
|
|
|
|
+ &__strong {
|
|
|
+ color: @white;
|
|
|
+ text-align: center;
|
|
|
+ font-weight: bold;
|
|
|
+ font-size: 20px;
|
|
|
+ }
|
|
|
+
|
|
|
&__board {
|
|
|
padding: 10px;
|
|
|
border-radius: 5px;
|
|
|
background-color: @map-popup-board-bg;
|
|
|
+ color: @text-color-base;
|
|
|
display: flex;
|
|
|
justify-content: space-between;
|
|
|
}
|
|
|
@@ -255,7 +353,6 @@
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
.map-reset-btn {
|
|
|
position: absolute;
|
|
|
right: 30%; /* 距离右边 20px */
|