先上图
一、数据准备
国家省界图来自天地图:天地图 服务中心 (tianditu.gov.cn),该地图下好就是GeoJSON格式,这方便了直接在Cesium中使用。当然里面是没有人口数据的,数据可以根据自己需要在GIS软件修改,比如QGIS,修改属性表的字段和值即可。我这里是添加的人口数据作为演示。
二、加载数据以及拉伸
这里的拉伸数据,参看前面的加载GeoJSON笔记,原理是一样的,只是这里增加了随机渲染颜色。
该部分代码
const dataSources = await Cesium.GeoJsonDataSource.load('src/assets/geojson/ceshi4.geojson')
// if (!viewer) return
viewer.dataSources.add(dataSources)
const entities = dataSources.entities.values
const colorHash = {}
for (let i = 0; i < entities.length; i++) {
const entity = entities[i]
const name = entity.properties.name
const totalPeople = entity.properties.total
const manNumber = entity.properties.man
const womanNumber = entity.properties.woman
const sexRatio = entity.properties.SexRatio
if (!peopleData.some(item => item.name._value === name._value)) {
peopleData.push({
name,
total: totalPeople,
man: manNumber,
woman: womanNumber,
SexRatio: sexRatio,
})
}
let color = colorHash[name]
if (!color) {
color = Cesium.Color.fromRandom({ alpha: 1.0 })
colorHash[name] = color
}
entity.polygon.material = color
entity.polygon.outline = false
entity.polygon.extrudedHeight = totalPeople / 200.0
}
viewer.zoomTo(dataSources)
三、鼠标移动到GeoJSON上时显示数据
//JS部分
const handleMouseMove = (event) => {
const pickedFeatureLocal = viewer.scene.pick(event.endPosition)
if (Cesium.defined(pickedFeatureLocal)) {
pickedFeature.value = pickedFeatureLocal.id
showNameOverlay.value = true
const nameOverlay = document.querySelector('.backdrop')
if (nameOverlay) {
nameOverlay.style.display = "block";
nameOverlay.style.bottom = `${viewer.canvas.clientHeight - event.endPosition.y}px`
nameOverlay.style.left = `${event.endPosition.x}px`
}
} else {
showNameOverlay.value = false
}
}
const initViewerEvents = () => {
if (!viewer) return
const screenSpaceEventHandler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas)
screenSpaceEventHandler.setInputAction(handleMouseMove, Cesium.ScreenSpaceEventType.MOUSE_MOVE)
}
//HTML部分
<!-- 鼠标悬停显示信息的容器 -->
<div v-if="showNameOverlay" class="backdrop" :style="{ display: showNameOverlay ? 'block' : 'none' }">
<!-- 鼠标悬停显示信息的内容 -->
<div>
<div>
<strong>{{ pickedFeature.properties.name._value }}</strong>
</div>
<div>
<span>总人口(人):{{ pickedFeature.properties.total._value }}</span>
<br>
<span>男性总人口(人):{{ pickedFeature.properties.man._value }}</span>
<br>
<span>女性总人口(人):{{ pickedFeature.properties.woman._value }}</span>
<br>
<span>性别比:{{ pickedFeature.properties.SexRatio._value }}</span>
</div>
</div>
</div>
注意:这里要将它的position设置为absolute
四、EChart显示和拖拽
拖拽是用了现成的轮子:vue3-draggable-resizablevue3-draggable-resizable/docs/document_zh.md at main · a7650/vue3-draggable-resizable (github.com)
//HTML部分
<Vue3DraggableResizable :initH="500" :initW="600" :minW="400" :minH="400" v-model:x="x" v-model:y="y"
:resizable="true">
<div class="chart-title">统计图</div>
<el-tabs type="border-card" class="demo-tabs">
<el-tab-pane>
<template #label>
<span class="custom-tabs-label">
<img src="@/assets/icon/pie.svg" style="width: 20px; height: 20px; margin-left: 4px;" />
</span>
</template>
<v-chart class="chart" :option="pieOption" autoresize> </v-chart>
</el-tab-pane>
<el-tab-pane>
<template #label>
<span class="custom-tabs-label">
<img src="@/assets/icon/line.svg" style="width: 20px; height: 20px; margin-left: 4px;" />
</span>
</template>
<v-chart class="chart" :option="lineOption" autoresize> </v-chart>
</el-tab-pane>
<el-tab-pane>
<template #label>
<span class="custom-tabs-label">
<img src="@/assets/icon/column.svg" style="width: 20px; height: 20px; margin-left: 4px;" />
</span>
</template>
<v-chart class="chart" :option="barOption" autoresize> </v-chart>
</el-tab-pane>
</el-tabs>
</Vue3DraggableResizable>
//JS部分,这里只展示一个表,因为基本类似
//柱状图配置
const barOption = ref({})
const barEchart = (data) => {
barOption.value = {
title: {
text: '人口数量'
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
}
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
xAxis: [
{
type: 'category',
data: data.map(item => item.name),
axisTick: {
alignWithLabel: true
},
axisLabel: {
rotate:-90
}
}
],
yAxis: [
{
type: 'value'
}
],
series: [
{
name: '人口数',
type: 'bar',
barWidth: '60%',
data:data
}
]
}