| | |
| | | import * as Cesium from 'cesium'; |
| | | import aggregationImg from '@/assets/images/home/useUavHome/aggregation.png'; |
| | | import uavImg from '@/assets/images/home/useUavHome/uavImg.png'; |
| | | import MapPopUpBox from '@/views/Home/useUavHome/MapPopUpBox.vue'; |
| | | |
| | | import eventImg from '@/assets/images/home/useEventOperate/event.png'; |
| | | |
| | | import DevicePopUpBox from '@/views/Home/useUavHome/DevicePopUpBox.vue'; |
| | | import EventPopUpBox from '@/views/Home/useEventOperate/EventPopUpBox.vue'; |
| | | |
| | | import { render } from 'vue'; |
| | | import { useStore } from 'vuex'; |
| | | import { getCenterPoint } from '@/utils/cesium/mapUtil'; |
| | | import cesiumOperation from '@/utils/cesium-tsa'; |
| | | import { HeadingPitchRange } from 'cesium'; |
| | | import { getDeviceRegion, getDeviceRegionCount } from '@/api/home/aggregation'; |
| | | |
| | | import { getDeviceRegion, getDeviceRegionCount, getEventDetails, getMapEvents } from '@/api/home/aggregation'; |
| | | |
| | | /** |
| | | * 机巢聚合功能 |
| | | */ |
| | | export const useUavHome = () => { |
| | | export const useUavHome = type => { |
| | | const { flyTo } = cesiumOperation(); |
| | | |
| | | const singleImg = type === 'device' ? uavImg : eventImg; |
| | | const mergeImg = type === 'device' ? aggregationImg : aggregationImg; |
| | | const MapPopUpBox = type === 'device' ? DevicePopUpBox : EventPopUpBox; |
| | | const styleTransform = type === 'device' ? 'translateY(-50%)' : 'translate(-50%,-110%)'; |
| | | |
| | | let scalingJudgment = [ |
| | | { name: '县', splashedList: [], gJson: null, show: false,outline:{}, value: [0, 48651], height: 31753 }, |
| | | { name: '市', splashedList: [], gJson: null, show: false,outline:{}, value: [48651, 314863], height: 257731 }, |
| | | { name: '省', splashedList: [], gJson: null, show: false,outline:{}, value: [314863, 3796280000], height: 1987280 }, |
| | | { name: '县', splashedList: [], gJson: null, show: false, outline: {}, value: [0, 48651], height: 31753 }, |
| | | { name: '市', splashedList: [], gJson: null, show: false, outline: {}, value: [48651, 314863], height: 257731 }, |
| | | { |
| | | name: '省', |
| | | splashedList: [], |
| | | gJson: null, |
| | | show: false, |
| | | outline: {}, |
| | | value: [314863, 3796280000], |
| | | height: 1987280, |
| | | }, |
| | | ]; |
| | | let viewer = null; |
| | | let active = null; |
| | | let handler = null; |
| | | let positionC3 = null; |
| | | let currentEntity = null; |
| | | |
| | | const store = useStore(); |
| | | const userAreaCode = computed(() => store.state.user.userInfo.detail.areaCode); |
| | | const selectedAreaCode = computed(() => store.state.user.selectedAreaCode); |
| | | const listenerHeight = () => { |
| | | determineScaling(); |
| | | viewer.camera.moveEnd.addEventListener(determineScaling); |
| | |
| | | active = item.name; |
| | | removeEntities(); |
| | | removeLabel(); |
| | | item.gJson ? aggregation(item) : splashed(item) |
| | | renderOutline(item) |
| | | item.gJson ? aggregation(item) : splashed(item); |
| | | renderOutline(item); |
| | | break; |
| | | } |
| | | } |
| | |
| | | return [provinceCode, cityCode, code]; |
| | | } |
| | | |
| | | const store = useStore(); |
| | | const selectedAreaCode = computed(() => store.state.user.selectedAreaCode); |
| | | |
| | | function getDeviceCount(areaCode) { |
| | | return getDeviceRegionCount({areaCode}).then(res => { |
| | | return res?.data?.data || []; |
| | | return getDeviceRegionCount({ areaCode }).then(res => { |
| | | return (res?.data?.data || []).map(i=>({...i,type:'deviceAggregation'})); |
| | | }); |
| | | } |
| | | |
| | | function getDeviceList(areaCode) { |
| | | return getDeviceRegion({areaCode}).then(res => { |
| | | return res?.data?.data || []; |
| | | return getDeviceRegion({ areaCode }).then(res => { |
| | | return (res?.data?.data || []).map(i =>({...i,type})); |
| | | }); |
| | | } |
| | | |
| | | let eventList = [] |
| | | function processChildren(childrens) { |
| | | return (childrens || []).map(item => { |
| | | const arr = processChildren(item.childrens); |
| | | if (item.data){ |
| | | eventList = eventList.concat(item.data) |
| | | } |
| | | const returnObj = { |
| | | total_device_count: item.number, |
| | | region_code: item.id, |
| | | region_name: item.name, |
| | | type:'eventAggregation' |
| | | }; |
| | | if (arr.length !== 0) { |
| | | returnObj.childrens = arr; |
| | | } |
| | | return returnObj; |
| | | }); |
| | | } |
| | | |
| | | function getMapEventCount(areaCode) { |
| | | return getMapEvents({ areaCode }).then(res => { |
| | | return processChildren(res?.data?.data?.childrens || []); |
| | | }); |
| | | } |
| | | function getEventDetailsFun(areaCode){ |
| | | return getEventDetails({areaCode}).then(res => { |
| | | console.log(res.data.data,'getEventDetailsFun'); |
| | | }); |
| | | } |
| | | |
| | | const findFun = (featItem, numItem) => Number(featItem.region_code.slice(0, 6)) === numItem.properties.adcode; |
| | | const { VITE_APP_BASE } = import.meta.env; |
| | | const defaultDir = `${VITE_APP_BASE}public/geoJson/100000/`; |
| | | |
| | | const getFiler = async (url) => { |
| | | const getFiler = async url => { |
| | | const gJson = await import(/* @vite-ignore */ url); |
| | | return JSON.parse(JSON.stringify(gJson)); |
| | | } |
| | | const getOutLine = async (jsonPathPre,hierarchy) => { |
| | | const parentGJson = await getFiler(`${defaultDir}${jsonPathPre}/index.json`) |
| | | }; |
| | | const getOutLine = async (jsonPathPre, hierarchy) => { |
| | | const parentGJson = await getFiler(`${defaultDir}${jsonPathPre}/index.json`); |
| | | let features = parentGJson.features.find( |
| | | item => item.properties.adcode === Number(hierarchy[hierarchy.length - 1]) |
| | | ); |
| | | return { type: "FeatureCollection", features: [features] } |
| | | } |
| | | return { type: 'FeatureCollection', features: [features] }; |
| | | }; |
| | | |
| | | const injectData = (gJson,dataList) => { |
| | | const injectData = (gJson, dataList) => { |
| | | return { |
| | | ...gJson, |
| | | features: gJson.features.map(item => ({ ...item, data: dataList.find(item1 => findFun(item1, item)) })), |
| | | }; |
| | | }; |
| | | |
| | | const initMapData = async areaCode => { |
| | | if (!areaCode) return; |
| | | const list = type === 'device' ? await getDeviceCount(areaCode) : await getMapEventCount(areaCode); |
| | | const splashedList = type === 'device' |
| | | ? await getDeviceList(areaCode) |
| | | : eventList.map(i=>({eventId:i.id,latitude:Number(i.latitude),longitude:Number(i.longitude),type:'event'})) |
| | | console.log(list, 'list'); |
| | | console.log(splashedList, 'splashedList'); |
| | | const hierarchy = convertToHierarchy(areaCode.slice(0, 6)); |
| | | const jsonPath = hierarchy.join('/'); |
| | | const jsonPathPre = hierarchy.slice(0, hierarchy.length - 1).join('/'); |
| | | scalingJudgment = scalingJudgment.map(item => ({ ...item, show: true })); |
| | | scalingJudgment[0].gJson = null; |
| | | scalingJudgment[0].splashedList = splashedList; |
| | | active = null; |
| | | console.log(hierarchy); |
| | | |
| | | // 省 |
| | | if (hierarchy.length === 1) { |
| | | const gJson1 = await getFiler(`${defaultDir}${jsonPath}/indexDistrict.json`); |
| | | const gJson2 = await getFiler(`${defaultDir}${jsonPath}/index.json`); |
| | | scalingJudgment[1].gJson = { |
| | | ...gJson1, |
| | | features: gJson1.features.map(item => ({ |
| | | ...item, |
| | | data: list.flatMap(item => item.childrens || []).find(item1 => findFun(item1, item)), |
| | | })), |
| | | }; |
| | | scalingJudgment[2].gJson = injectData(gJson2, list); |
| | | const { lng, lat } = getCenterPoint(gJson2.features.map(item => item.properties.center)); |
| | | flyTo({ longitude: lng, latitude: lat }, 0, scalingJudgment[2].height); |
| | | } |
| | | } |
| | | |
| | | |
| | | // 市 |
| | | if (hierarchy.length === 2) { |
| | | scalingJudgment[2].gJson = null; |
| | | scalingJudgment[2].show = false; |
| | | const gJson1 = await getFiler(`${defaultDir}${jsonPath}/index.json`); |
| | | scalingJudgment[1].gJson = injectData(gJson1, list); |
| | | const center = getCenterPoint(gJson1.features.map(item => item.properties.center)); |
| | | flyTo({ longitude: center.lng, latitude: center.lat }, 0, scalingJudgment[1].height); |
| | | } |
| | | // 区县 |
| | | if (hierarchy.length === 3) { |
| | | scalingJudgment[1].gJson = null; |
| | | scalingJudgment[1].show = false; |
| | | scalingJudgment[2].gJson = null; |
| | | scalingJudgment[2].show = false; |
| | | const outlineGJson = await getOutLine(jsonPathPre, hierarchy); |
| | | const center = outlineGJson.features[0].properties.center; |
| | | flyTo({ longitude: center[0], latitude: center[1] }, 0, scalingJudgment[0].height); |
| | | } |
| | | // 轮廓 |
| | | const outlineGJson = await getOutLine(jsonPathPre, hierarchy); |
| | | scalingJudgment.forEach(item => item.show && (item.outline = outlineGJson)); |
| | | }; |
| | | |
| | | watch( |
| | | selectedAreaCode, |
| | | async (newValue, oldValue) => { |
| | | if (newValue) { |
| | | const list = await getDeviceCount(newValue); |
| | | const splashedList = await getDeviceList(newValue); |
| | | console.log(list); |
| | | console.log(splashedList); |
| | | const hierarchy = convertToHierarchy(newValue.slice(0, 6)); |
| | | const jsonPath = hierarchy.join('/'); |
| | | const jsonPathPre = hierarchy.slice(0, hierarchy.length - 1).join('/'); |
| | | scalingJudgment = scalingJudgment.map(item => ({ ...item, show: true })); |
| | | scalingJudgment[0].gJson = null; |
| | | scalingJudgment[0].splashedList = splashedList; |
| | | active = null |
| | | // 省 |
| | | if (hierarchy.length === 1) { |
| | | const gJson1 = await getFiler(`${defaultDir}${jsonPath}/indexDistrict.json`) |
| | | const gJson2 = await getFiler(`${defaultDir}${jsonPath}/index.json`) |
| | | scalingJudgment[1].gJson = { |
| | | ...gJson1, |
| | | features: gJson1.features.map(item => ({ |
| | | ...item, |
| | | data: list.flatMap(item => item.childrens || []).find(item1 => findFun(item1, item)), |
| | | })), |
| | | }; |
| | | scalingJudgment[2].gJson = injectData(gJson2,list); |
| | | const { lng, lat } = getCenterPoint(gJson2.features.map(item => item.properties.center)); |
| | | flyTo({ longitude: lng, latitude: lat }, 0, scalingJudgment[2].height); |
| | | } |
| | | // 市 |
| | | if (hierarchy.length === 2) { |
| | | scalingJudgment[2].gJson = null; |
| | | scalingJudgment[2].show = false; |
| | | const gJson1 = await getFiler(`${defaultDir}${jsonPath}/index.json`) |
| | | scalingJudgment[1].gJson = injectData(gJson1,list); |
| | | const center = getCenterPoint(gJson1.features.map(item => item.properties.center)); |
| | | flyTo({ longitude: center.lng, latitude: center.lat }, 0, scalingJudgment[1].height); |
| | | } |
| | | // 区县 |
| | | if (hierarchy.length === 3) { |
| | | scalingJudgment[1].gJson = null; |
| | | scalingJudgment[1].show = false; |
| | | scalingJudgment[2].gJson = null; |
| | | scalingJudgment[2].show = false; |
| | | const outlineGJson = await getOutLine(jsonPathPre,hierarchy) |
| | | const center = outlineGJson.features[0].properties.center; |
| | | flyTo({ longitude: center[0], latitude: center[1] }, 0, scalingJudgment[0].height); |
| | | } |
| | | // 轮廓 |
| | | const outlineGJson = await getOutLine(jsonPathPre,hierarchy) |
| | | scalingJudgment.forEach(item => item.show &&(item.outline = outlineGJson)) |
| | | } |
| | | initMapData(newValue); |
| | | }, |
| | | { immediate: true, deep: true } |
| | | { deep: true } |
| | | ); |
| | | |
| | | //散点机巢 |
| | |
| | | pixelOffset: new Cesium.Cartesian2(0, -9), |
| | | }, |
| | | billboard: { |
| | | image: new Cesium.ConstantProperty(uavImg), |
| | | image: new Cesium.ConstantProperty(singleImg), |
| | | width: 24, |
| | | height: 24, |
| | | }, |
| | |
| | | } |
| | | |
| | | // 渲染轮廓 |
| | | const renderOutline = (item) => { |
| | | item.outline && Cesium.GeoJsonDataSource.load(item.outline).then(dataSource => { |
| | | viewer.dataSources.add(dataSource); |
| | | const entities = dataSource.entities.values; |
| | | entities.forEach(entity => { |
| | | // 隐藏多边形填充 |
| | | entity.polygon.material = Cesium.Color.TRANSPARENT; |
| | | entity.polygon.outline = false; // 关闭原生轮廓 |
| | | // 创建独立折线作为轮廓 |
| | | const positions = entity.polygon.hierarchy.getValue().positions; |
| | | viewer.entities.add({ |
| | | polyline: { |
| | | positions: positions, |
| | | width: 5, // 直接设置宽度 |
| | | material: new Cesium.PolylineGlowMaterialProperty({ |
| | | glowPower: 0.5, |
| | | color: Cesium.Color.AQUA |
| | | }), |
| | | clampToGround: true // 贴地显示 |
| | | } |
| | | const renderOutline = item => { |
| | | item.outline && |
| | | Cesium.GeoJsonDataSource.load(item.outline).then(dataSource => { |
| | | viewer.dataSources.add(dataSource); |
| | | const entities = dataSource.entities.values; |
| | | entities.forEach(entity => { |
| | | // 隐藏多边形填充 |
| | | entity.polygon.material = Cesium.Color.TRANSPARENT; |
| | | entity.polygon.outline = false; // 关闭原生轮廓 |
| | | // 创建独立折线作为轮廓 |
| | | const positions = entity.polygon.hierarchy.getValue().positions; |
| | | viewer.entities.add({ |
| | | polyline: { |
| | | positions: positions, |
| | | width: 5, // 直接设置宽度 |
| | | material: new Cesium.PolylineGlowMaterialProperty({ |
| | | glowPower: 0.5, |
| | | color: Cesium.Color.AQUA, |
| | | }), |
| | | clampToGround: true, // 贴地显示 |
| | | }, |
| | | }); |
| | | }); |
| | | }); |
| | | }); |
| | | }; |
| | | |
| | | // 聚合机巢 |
| | |
| | | style: Cesium.LabelStyle.FILL_AND_OUTLINE, |
| | | verticalOrigin: Cesium.VerticalOrigin.BOTTOM, |
| | | pixelOffset: new Cesium.Cartesian2(0, -9), |
| | | } |
| | | }, |
| | | }); |
| | | viewer.entities.add({ |
| | | id: feature.id, |
| | | position: position, |
| | | label: { |
| | | text: feature.data.total_device_count, |
| | | text: feature.data.total_device_count.toString(), |
| | | font: '12pt Source Han Sans CN', |
| | | fillColor: Cesium.Color.BLACK, |
| | | style: Cesium.LabelStyle.FILL_AND_OUTLINE, |
| | | eyeOffset: new Cesium.Cartesian3(0, 0, -10), // 让label "浮" 在广告牌前面 |
| | | }, |
| | | billboard: { |
| | | image: new Cesium.ConstantProperty(aggregationImg), |
| | | image: new Cesium.ConstantProperty(mergeImg), |
| | | width: 35, |
| | | height: 35, |
| | | }, |
| | |
| | | Cesium.Color.YELLOW.withAlpha(0) // 透明填充 |
| | | ); |
| | | entity.polygon.outline = new Cesium.ConstantProperty(true); // 显示边框 |
| | | entity.polygon.outlineColor = new Cesium.ConstantProperty(Cesium.Color.AQUAMARINE ); |
| | | entity.polygon.outlineColor = new Cesium.ConstantProperty(Cesium.Color.AQUAMARINE); |
| | | }); |
| | | flyTo && |
| | | viewer.flyTo(dataSource, { |
| | |
| | | const tooltipContainer = document.createElement('div'); |
| | | tooltipContainer.id = 'mapPopUpBox'; |
| | | tooltipContainer.style.position = 'absolute'; |
| | | tooltipContainer.style.transform = 'translateY(-50%)'; |
| | | tooltipContainer.style.transform = styleTransform; |
| | | tooltipContainer.style.pointerEvents = 'none'; |
| | | document.querySelector('.page-index').append(tooltipContainer); |
| | | render(vNode, tooltipContainer); |
| | |
| | | positionC3 = entity?.position?._value; |
| | | if (!positionC3) return; |
| | | removeLabel(); |
| | | const customData = entity.properties.customData._value.data |
| | | console.log(customData); |
| | | if (customData.device_sn){ |
| | | store.commit('setSingleUavHome', { id: '123' }); |
| | | return |
| | | const customData = entity.properties.customData._value.data; |
| | | |
| | | switch (customData.type) { |
| | | case 'deviceAggregation': |
| | | viewer.scene.postRender.addEventListener(labelBoxRender); |
| | | break; |
| | | case 'device': |
| | | store.commit('setSingleUavHome', { id: '123' }); |
| | | break; |
| | | case 'eventAggregation': |
| | | break; |
| | | case 'event': |
| | | viewer.scene.postRender.addEventListener(labelBoxRender); |
| | | break; |
| | | default: |
| | | break; |
| | | } |
| | | viewer.scene.postRender.addEventListener(labelBoxRender); |
| | | } |
| | | }; |
| | | |
| | |
| | | currentEntity = null; |
| | | }; |
| | | const init = () => { |
| | | initMapData(selectedAreaCode.value || userAreaCode.value); |
| | | viewer = window.$viewer; |
| | | handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas); |
| | | handler.setInputAction(singleMachineEvent, Cesium.ScreenSpaceEventType.LEFT_CLICK); |
| | | listenerHeight(); |
| | | }; |
| | | onBeforeUnmount(() => {}); |
| | | // onMounted(() => { |
| | | // nextTick(() => { |
| | | // viewer = window.$viewer; |