| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300 |
- <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 :loading="mapLoading" type="primary" @click="revertStack">返回上级</Button>
- </div>
- </template>
- <script lang="ts" setup>
- import 'vjmap/dist/vjmap.min.css';
- import { ref, onMounted, onUnmounted, computed, createApp } from 'vue';
- import { Button } from 'ant-design-vue';
- import { useAppStore } from '/@/store/modules/app';
- // 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 { generateSimplePopup } from './hooks/popup';
- import { initMap2d, renderGoafMarkers } from '/@/views/system/cadFile/app';
- import { getGoafList } from '/@/views/system/cadFile/cad.api';
- import LeafPopup from './components/LeafPopup.vue';
- // import { useGlobSetting } from '/@/hooks/setting';
- const appStore = useAppStore();
- const mineStore = useMineDepartmentStore();
- // const globSetting = useGlobSetting();
- appStore.setSimpleMapParams({ deptId: mineStore.getRootId, isLeaf: mineStore.getRoot?.isLeaf });
- // const route = useRoute();
- const mapContainer = ref<HTMLElement>();
- // let svc = new vjmap.Service(env.serviceUrl, env.accessToken);
- let map: vjmap.Map;
- // let app: vjmap3d.App;
- const GEO_LAYER_ID = 'geojson-layer';
- const GEO_BORDER_ID = 'geoline-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,
- isLeaf: false,
- };
- const historyStack = ref([DEFAULT_NODE]); // 用于存储历史节点的栈,实现返回上一级功能
- const isTopLevel = computed(() => historyStack.value.length === 1);
- /** 根据GeoJSON文件绘制省市边界和填充色到地图上,其将作为一个新图层 */
- 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)!.id, ['get', 'deptIds']],
- });
- map.addLineLayer(GEO_BORDER_ID, 'geojson-data', {
- lineColor: '#ff9100',
- lineWidth: 2,
- filter: ['in', last(historyStack.value)!.id, ['get', 'deptIds']],
- });
- // map.hoverPointer([GEO_LAYER_ID]);
- map.hoverFeatureState(GEO_LAYER_ID);
- }
- /** 根据标记点信息绘制两个图层,一个圆标点图层和一个文本标点图层 */
- 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 generateSimplePopup(f.properties);
- }
- },
- {
- maxWidth: '300px',
- }
- );
- const symbols = new vjmap.Symbol({
- layerId: SYMBOL_LAYER_ID,
- data: markers,
- textField: ['case', ['to-boolean', ['get', 'isLeaf']], '', ['get', 'count']],
- textFont: ['Noto Sans Italic'],
- textSize: 16,
- textAllowOverlap: true,
- textColor: '#ffffff',
- filter: ['==', last(historyStack.value)!.id, ['get', 'parentId']],
- });
- symbols.addTo(map);
- circles.clickLayer((e) => {
- if (e.defaultPrevented) return; // 如果事件之前阻止了,则不再执行了
- historyStack.value.push(get(e, 'features[0].properties', DEFAULT_NODE));
- markerClickHandler();
- e.preventDefault(); // 阻止之后的事件执行
- });
- }
- /** 标记点点击后,如果不是叶节点那么聚焦到下一级,如果已经是叶节点了则显示该节点的CAD地图 */
- function markerClickHandler() {
- const node: any = last(historyStack.value);
- if (!node) return;
- appStore.setSimpleMapParams({ deptId: node.id, isLeaf: node.isLeaf });
- // 标点点击后,如果是叶节点需要显示CAD图
- if (!node.isLeaf) {
- 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', 'deptIds']]);
- map.setFilter(GEO_BORDER_ID, ['in', node.id, ['get', 'deptIds']]);
- map.flyTo({
- center: [node.longitude, node.latitude],
- zoom: node.zoom,
- });
- } else {
- const popup = new vjmap.Popup({ maxWidth: '1000' });
- const app = createApp(LeafPopup, {
- node,
- callback() {
- toggleCADMap(true, node).then(() => {
- // 将历史栈推一个进去,因为用户要点击返回上一级时需要
- historyStack.value.push(node);
- });
- },
- });
- const el = document.createElement('div');
- app.mount(el);
- // 将历史栈拉一个出来,因为点击后页面上并没有钻入下一级
- historyStack.value.pop();
- popup.setLngLat([node.longitude, node.latitude]).setDOMContent(el).addTo(map);
- }
- }
- /** 返回上一级操作,如果存在CAD地图,则切换至底图地图,否则回退历史记录栈 */
- async function revertStack() {
- if (historyStack.value.length === 1) return;
- historyStack.value.pop()!;
- toggleCADMap(false).then(() => {
- markerClickHandler();
- });
- }
- /** 初始化地图对象,仅负责初始化地图及其瓦片底图,待map加载完成后返回 */
- async function initMap(HTMLElement) {
- const map = new vjmap.Map({
- container: HTMLElement,
- // 这个zoom配合了getGeoJSON,要改两边都要改
- maxZoom: 20,
- minZoom: 1,
- center: [DEFAULT_NODE.longitude, DEFAULT_NODE.latitude],
- zoom: DEFAULT_NODE.zoom,
- // style: svc.rasterStyle('https://webrd01.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=7&x={x}&y={y}&z={z}'),
- style: `${window.location.origin}/js/shanxi.map.json`,
- });
- await map.onLoad();
- return map;
- }
- const mapLoading = ref(false);
- let cadOpened: boolean;
- /** 切换CAD地图和瓦片地图的显示,通过重新初始化进行切换,避免出现动画异常和多个DOM节点 */
- async function toggleCADMap(visiable: boolean, data?: any) {
- if (cadOpened === visiable) return;
- cadOpened = visiable;
- mapLoading.value = true;
- map?.destory();
- try {
- if (visiable) {
- const [m, res] = await Promise.all([
- initMap2d(mapContainer.value!, {
- // fileUrl: node.url
- // fileUrl: `${globSetting.apiUrl}/sys/common/static/webfile/hongliulin_default.dwg`,
- style: { backcolor: 0xe6f3ff },
- }),
- getGoafList({
- mineCode: data ? data.mineCode : mineStore.getRoot?.fax,
- deptId: data ? data.id : mineStore.getRootId,
- }),
- ]);
- map = m;
- renderGoafMarkers(res); // 渲染标记
- } else {
- // const hide = message.loading('地图加载中...', 0);
- const [m, res] = await Promise.all([
- initMap(mapContainer.value!),
- getGeoJSON({
- deptId: mineStore.getRootId,
- pageSize: 9999,
- }),
- ]);
- const [geojson, __, markers] = res;
- // hide();
- map = m;
- initMapGeoJSON(map, geojson);
- initMapMarker(map, markers);
- }
- } finally {
- mapLoading.value = false;
- }
- }
- onMounted(() => {
- toggleCADMap(mineStore.getRoot?.isLeaf || false);
- });
- onUnmounted(() => {
- map?.remove();
- // app?.destroy();
- });
- </script>
- <style lang="less">
- .map-container {
- flex: 1;
- height: 100%;
- width: 100%;
- position: fixed;
- top: 0;
- left: 0;
- z-index: @simple-map-z-index;
- // 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);
- }
- .vjmapgis-popup {
- color: @white;
- // &-content-wrapper {
- // background-color: @map-popup-bg;
- // }
- &-anchor-bottom &-tip {
- border-top-color: @map-popup-bg;
- }
- &-content {
- // margin: 13px 20px;
- // min-width: 300px;
- background-color: @map-popup-bg;
- box-shadow: 0 0 10px #00000088;
- // &__popup {
- // }
- }
- }
- .map-reset-btn {
- position: absolute;
- right: 30%; /* 距离右边 20px */
- z-index: 2; /* 确保在地图控件之上 */
- top: @header-height;
- // padding: 10px 15px;
- margin: 10px 0;
- }
- </style>
|