<template>
|
<div id="gis-view" ref="mapRef"></div>
|
</template>
|
|
<script setup>
|
import { onMounted, onUnmounted, ref, watch } from "vue"
|
import { createPoint, initHandler, initView, addTileset, addTerrain } from "@/utils/map.js"
|
import { loadAreaPolygon } from "@/utils/area.js"
|
import { loadAreaPolygonAll } from "@/utils/area_all.js"
|
import { isVisibleDistance } from "@/utils/customEntity"
|
import { getDistrictCount, getDistrictCountByCity } from "@/api/index"
|
import { useRoute } from "vue-router"
|
const route = useRoute()
|
let handler = null
|
function initMap () {
|
window.Cesium = SmartEarth.Cesium
|
window.earthCtrl = new SmartEarth.EarthCtrl("gis-view")
|
window.viewer = earthCtrl.viewer;
|
const date = new Date(2025, 3, 11, 12, 0, 0, 0);
|
const julianDate = SmartEarth.Cesium.JulianDate.fromDate(date);
|
earthCtrl.viewer.clock.currentTime = julianDate;
|
//显示fps
|
earthCtrl.showFPS = true
|
earthCtrl.factory.createImageryLayer({
|
sourceType: "mapworld",
|
url: "https://t0.tianditu.gov.cn/img_w/wmts?service=wmts&request=GetTile&version=1.0.0&LAYER=img&tileMatrixSet=w&TileMatrix={TileMatrix}&TileRow={TileRow}&TileCol={TileCol}&style=default&format=tiles&tk=3ec79cf7a9dcc6bb18411a5414b148cb",
|
layers: "tdtBasicLayer",
|
style: "default",
|
format: "image/jpeg",
|
maximumLevel: 18,
|
layer: "",
|
tileMatrixSetID: "",
|
})
|
// 关闭地形深度检测
|
// viewer.scene.globe.depthTestAgainstTerrain = false;
|
}
|
|
function addCityPolygon () {
|
const url = `/json/110000.geo.json`
|
let wallLayer = earthCtrl.factory.createTrailWallLayer({
|
url: "/json/110000.geojson",
|
color: "LIGHTSTEELBLUE", //颜色
|
height: 2000, //高度
|
speed: 3,
|
})
|
const dataSourcePromise = Cesium.GeoJsonDataSource.load(url, {
|
clampToGround: true,
|
})
|
return dataSourcePromise.then(function (dataSource) {
|
viewer.dataSources.add(dataSource)
|
const polygonEntity = dataSource.entities.values
|
console.log("polygonEntity", polygonEntity)
|
const distanceDisplayCondition = new Cesium.DistanceDisplayCondition(1000, 50000000)
|
polygonEntity.forEach(entity => {
|
// console.log("entity", entity)
|
|
entity.polygon.material = new Cesium.ColorMaterialProperty(
|
Cesium.Color.LIGHTSTEELBLUE.withAlpha(0)
|
// new Cesium.Color.fromCssColorString("#0f2636b3")
|
// Cesium.Color.fromRandom({
|
// alpha: 0.5,
|
// minimumAlpha: 0.2,
|
// maximumAlpha: 0.9,
|
// })
|
)
|
|
entity.polygon.distanceDisplayCondition = distanceDisplayCondition
|
|
const properties = entity.properties
|
const center = properties.centroid.getValue()
|
const fullname = properties.fullname.getValue()
|
const districtCount = properties.districtCount.getValue() || 0
|
|
const position = Cesium.Cartesian3.fromDegrees(center[0], center[1])
|
const positions = entity.polygon.hierarchy._value.positions
|
|
entity.position = position
|
// 判断是否为东城区或西城区
|
let labelText = fullname || "默认标签"
|
if (fullname === "东城区" || fullname === "西城区") {
|
// 将文本拆分为竖列
|
labelText = fullname.split("").join("\n")
|
}
|
entity.label = {
|
// 文本。支持显式换行符“ \ n”
|
text: labelText,
|
// 字体样式,以CSS语法指定字体
|
font: "22pt Source Han Sans CN",
|
// 字体颜色
|
|
fillColor: Cesium.Color.fromCssColorString("#FD9B00"),
|
// 背景颜色
|
backgroundColor: Cesium.Color.BLACK.withAlpha(0.8),
|
// 是否显示背景颜色
|
showBackground: false,
|
// 字体边框
|
outline: true,
|
// 字体边框颜色
|
outlineColor: Cesium.Color.WHITE,
|
// 字体边框尺寸
|
outlineWidth: 0,
|
// 应用于图像的统一比例。比例大于会1.0放大标签,而比例小于会1.0缩小标签。
|
scale: 1.0,
|
scaleByDistance: new Cesium.NearFarScalar(1.5e2, 1.0, 1.5e7, 0.5),
|
// 设置样式:FILL:填写标签的文本,但不要勾勒轮廓;OUTLINE:概述标签的文本,但不要填写;FILL_AND_OUTLINE:填写并概述标签文本。
|
style: Cesium.LabelStyle.FILL_AND_OUTLINE,
|
// 相对于坐标的水平位置
|
verticalOrigin: Cesium.VerticalOrigin.CENTER,
|
// 相对于坐标的水平位置
|
horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
|
// 该属性指定标签在屏幕空间中距此标签原点的像素偏移量
|
pixelOffset: new Cesium.Cartesian2(0, 0),
|
// pixelOffset: new Cesium.Cartesian2(0, 0),
|
// 显示在距相机的距离处的属性,多少区间内是可以显示的
|
distanceDisplayCondition: distanceDisplayCondition,
|
// : new Cesium.DistanceDisplayCondition(0, 50000),
|
heightReference: Cesium.HeightReference.RELATIVE_TO_GROUND,
|
disableDepthTestDistance: Number.POSITIVE_INFINITY,
|
// 是否显示
|
show: true,
|
}
|
entity.polyline = {
|
positions: positions,
|
width: 5,
|
material: new Cesium.ColorMaterialProperty(
|
Cesium.Color.SKYBLUE.withAlpha(0.9)
|
// Cesium.Color.fromRandom({
|
// alpha: 0.5,
|
// minimumAlpha: 0.2,
|
// maximumAlpha: 0.9,
|
// })
|
),
|
clampToGround: true,
|
distanceDisplayCondition: distanceDisplayCondition,
|
}
|
|
viewer.entities.add(entity)
|
})
|
|
// 获取 GeoJSON 中的第一个 Polygon feature
|
})
|
}
|
|
function flyToHomeView () {
|
const view = {
|
destination: {
|
x: -2355432.569004413,
|
y: 4687573.191838412,
|
z: 4098726.315265574,
|
},
|
orientation: {
|
pitch: -0.9541030830183503,
|
roll: 0.00031421159527500464,
|
heading: 6.140424766644804,
|
},
|
}
|
viewer.scene.camera.flyTo(view)
|
}
|
|
let htmlEntityList = []
|
function initDistrictCount () {
|
getDistrictCount().then(res => {
|
res.data.forEach(item => {
|
const { districtName, count, lat, lon } = item
|
item.name = `${item.districtName}\n${item.count}`
|
item.longitude = item.lon
|
item.latitude = item.lat
|
item.showBillboard = false
|
item.showLabel = true
|
item.label = {
|
text: item.name,
|
backgroundColor: SmartEarth.Cesium.Color.SKYBLUE.withAlpha(0.8),
|
font: "14pt Source Han Sans CN",
|
fillColor: SmartEarth.Cesium.Color.WHITE,
|
showBackground: true,
|
}
|
// createPoint(item)
|
const html = earthCtrl.view.createScreenDialog({
|
html: `
|
<div class="district-count">
|
<div class="name">${districtName}</div>
|
<div class="value">${count}</div>
|
</div>
|
`,
|
lon: item.lon,
|
lat: item.lat,
|
height: 0,
|
})
|
html.maxVisibleDistance = 69000
|
html.minVisibleDistance = 20000
|
html.element.addEventListener("click", () => {
|
viewer.camera.flyTo({
|
destination: Cesium.Cartesian3.fromDegrees(item.longitude, item.latitude, 12000),
|
orientation: {
|
pitch: Cesium.Math.toRadians(-90),
|
heading: Cesium.Math.toRadians(0),
|
roll: 0,
|
},
|
duration: 2,
|
})
|
})
|
|
htmlEntityList.push(html)
|
})
|
})
|
}
|
function initDistrictCountByCity () {
|
getDistrictCountByCity().then(res => {
|
res.data.forEach(item => {
|
const { districtName, count, lat, lon } = item
|
item.name = `${item.districtName}\n${item.count}`
|
item.longitude = item.lon
|
item.latitude = item.lat
|
item.showBillboard = false
|
item.showLabel = true
|
item.label = {
|
text: item.name,
|
backgroundColor: SmartEarth.Cesium.Color.SKYBLUE.withAlpha(0.8),
|
font: "14pt Source Han Sans CN",
|
fillColor: SmartEarth.Cesium.Color.WHITE,
|
showBackground: true,
|
}
|
// createPoint(item)
|
const html = earthCtrl.view.createScreenDialog({
|
html: `
|
<div class="district-count">
|
<div class="name">${districtName}</div>
|
<div class="value">${count}</div>
|
</div>
|
`,
|
lon: item.lon,
|
lat: item.lat,
|
height: 0,
|
})
|
html.maxVisibleDistance = 50000000
|
html.minVisibleDistance = 70000
|
html.element.addEventListener("click", () => {
|
viewer.camera.flyTo({
|
destination: Cesium.Cartesian3.fromDegrees(item.longitude, item.latitude, 45000),
|
orientation: {
|
pitch: Cesium.Math.toRadians(-90),
|
heading: Cesium.Math.toRadians(0),
|
roll: 0,
|
},
|
duration: 2,
|
})
|
})
|
|
htmlEntityList.push(html)
|
})
|
})
|
}
|
watch(
|
() => route.fullPath,
|
val => {
|
if (val != "/") {
|
// clusterLayer.dataSource.show = false
|
htmlEntityList.forEach(item => {
|
item.show = false
|
})
|
removeCameraChange()
|
} else {
|
handleCameraChange()
|
// clusterLayer.dataSource.show = true
|
htmlEntityList.forEach(item => {
|
item.show = true
|
})
|
}
|
}
|
)
|
function handleCameraChange () {
|
viewer.camera.changed.addEventListener(toggleHtmlLayerByVisibleDistance)
|
}
|
function removeCameraChange () {
|
viewer.camera.changed.removeEventListener(toggleHtmlLayerByVisibleDistance)
|
}
|
let cameraChangeTimer = null
|
|
function toggleHtmlLayerByVisibleDistance () {
|
if (cameraChangeTimer) {
|
clearTimeout(cameraChangeTimer)
|
cameraChangeTimer = null
|
return
|
}
|
cameraChangeTimer = setTimeout(() => {
|
htmlEntityList.forEach(item => {
|
item.show = isVisibleDistance(item.minVisibleDistance, item.maxVisibleDistance)
|
})
|
}, 100)
|
}
|
|
onMounted(() => {
|
initMap()
|
addCityPolygon()
|
initHandler()
|
// initView()
|
loadAreaPolygon("/json/nsl_area.geojson")
|
loadAreaPolygonAll("/json/geometry.json", true)
|
flyToHomeView()
|
initDistrictCount()
|
initDistrictCountByCity()
|
handleCameraChange()
|
// 设置 billboard 点击事件
|
})
|
onUnmounted(() => {
|
removeCameraChange()
|
})
|
</script>
|
|
<style lang="less" scoped>
|
#gis-view {
|
width: 100vw;
|
height: 100vh;
|
position: absolute;
|
}
|
</style>
|