Cesium+ECharts 实现矿山数据双端联动可视化

Cesium+ECharts 实现矿山数据双端联动可视化

核心需求

矿山可视化系统中,需要实现:

  1. 点击 Cesium 中的矿山区域,ECharts 图表同步显示该区域的详细数据
  2. 点击 ECharts 图表中的数据项,Cesium 场景定位到对应的矿山区域并高亮
  3. 筛选 ECharts 数据时,Cesium 中的对应实体同步隐藏 / 显示

实现方案

1. 初始化 Cesium 和 ECharts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
// 初始化Cesium
const viewer = new Cesium.Viewer('cesiumContainer', {
terrainProvider: Cesium.createWorldTerrain(),
imageryProvider: new Cesium.UrlTemplateImageryProvider({
url: 'http://localhost:8080/map/{z}/{x}/{y}.png' // 本地矿山底图
})
});

// 初始化ECharts
const chart = echarts.init(document.getElementById('echartsContainer'));
const chartOption = {
title: { text: '矿山产量统计' },
xAxis: { type: 'category', data: ['采区1', '采区2', '采区3', '采区4'] },
yAxis: { type: 'value' },
series: [{
name: '产量',
type: 'bar',
data: [120, 200, 150, 80]
}]
};
chart.setOption(chartOption);

// 存储区域数据映射关系
const areaMap = {
'采区1': { id: 'area1', lng: 116.98, lat: 39.78, color: Cesium.Color.RED },
'采区2': { id: 'area2', lng: 116.99, lat: 39.79, color: Cesium.Color.GREEN },
'采区3': { id: 'area3', lng: 117.00, lat: 39.77, color: Cesium.Color.BLUE },
'采区4': { id: 'area4', lng: 116.97, lat: 39.80, color: Cesium.Color.YELLOW }
};

// 初始化Cesium区域实体
function initCesiumAreas() {
Object.values(areaMap).forEach(area => {
// 创建区域多边形
const entity = viewer.entities.add({
id: area.id,
name: area.name,
polygon: {
hierarchy: Cesium.Cartesian3.fromDegreesArray([
area.lng - 0.01, area.lat - 0.01,
area.lng + 0.01, area.lat - 0.01,
area.lng + 0.01, area.lat + 0.01,
area.lng - 0.01, area.lat + 0.01
]),
material: area.color.withAlpha(0.3),
outline: true,
outlineColor: area.color
},
properties: {
name: area.name,
production: 0 // 产量数据
}
});
// 存储实体引用
area.entity = entity;
});
}
initCesiumAreas();

2. Cesium→ECharts 联动(点击区域显示数据)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// 监听Cesium实体点击事件
viewer.screenSpaceEventHandler.setInputAction(function onLeftClick(event) {
// 获取点击的实体
const pickedObject = viewer.scene.pick(event.position);
if (Cesium.defined(pickedObject) && pickedObject.id) {
const entity = pickedObject.id;
const areaName = entity.properties.name.getValue();

// 1. ECharts定位到对应数据项
chart.dispatchAction({
type: 'highlight',
seriesIndex: 0,
dataIndex: Object.keys(areaMap).indexOf(areaName)
});

// 2. ECharts显示该区域详细数据
fetch(`/api/mine/production?area=${areaName}`)
.then(res => res.json())
.then(data => {
const detailOption = {
title: { text: `${areaName}产量详情` },
xAxis: { type: 'category', data: data.dates },
yAxis: { type: 'value' },
series: [{ type: 'line', data: data.values }]
};
// 更新ECharts
chart.setOption(detailOption);
});

// 3. 相机定位到该区域
viewer.camera.flyTo({
destination: Cesium.Cartesian3.fromDegrees(
areaMap[areaName].lng,
areaMap[areaName].lat,
1000
),
duration: 2 // 飞行时长2秒
});
}
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);

3. ECharts→Cesium 联动(点击图表定位区域)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
// 监听ECharts点击事件
chart.on('click', function(params) {
const areaName = params.name;
const area = areaMap[areaName];
if (!area) return;

// 1. Cesium定位到该区域
viewer.camera.flyTo({
destination: Cesium.Cartesian3.fromDegrees(area.lng, area.lat, 1000),
duration: 2
});

// 2. 高亮该区域实体
Object.values(areaMap).forEach(a => {
a.entity.polygon.material = a.color.withAlpha(0.3); // 恢复默认透明度
});
area.entity.polygon.material = area.color.withAlpha(0.8); // 高亮

// 3. 添加标签显示详细信息
viewer.entities.add({
position: Cesium.Cartesian3.fromDegrees(area.lng, area.lat, 100),
label: {
text: `${areaName}\n产量: ${params.value}吨`,
font: '16pt monospace',
fillColor: Cesium.Color.WHITE,
outlineColor: Cesium.Color.BLACK,
outlineWidth: 2,
pixelOffset: new Cesium.Cartesian2(0, -50)
}
});
});

// ECharts筛选数据时,同步更新Cesium实体
chart.on('datazoom', function(params) {
// 获取筛选后的x轴数据
const filteredAreas = chart.getOption().xAxis[0].data;
// 显示筛选后的区域,隐藏其他区域
Object.entries(areaMap).forEach(([name, area]) => {
area.entity.show = filteredAreas.includes(name);
});
});

4. 双向数据同步(实时更新)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// WebSocket实时同步数据
const ws = new WebSocket('ws://localhost:8080/mine/realtime');
ws.onmessage = function(event) {
const data = JSON.parse(event.data);
// 1. 更新ECharts数据
chart.setOption({
series: [{
data: data.production.map(item => item.value)
}]
});
// 2. 更新Cesium实体属性
data.production.forEach(item => {
const area = areaMap[item.name];
if (area) {
area.entity.properties.production = item.value;
// 产量超过阈值时变色
if (item.value > 150) {
area.entity.polygon.material = Cesium.Color.RED.withAlpha(0.5);
}
}
});
};

小结

  1. Cesium 与 ECharts 联动核心是维护区域数据映射关系,通过事件监听实现双向交互
  2. Cesium 端通过screenSpaceEventHandler监听点击,ECharts 端通过on('click')监听点击
  3. 联动操作包括数据高亮、相机定位、数据更新、实体显隐等,提升用户交互体验
  4. WebSocket 实现实时数据同步,确保双端数据一致性

Cesium+ECharts 实现矿山数据双端联动可视化
http://owoah.com/blog/2026/03/17/Cesium+ECharts 实现矿山数据双端联动可视化/
作者
owoah
发布于
2026年3月17日
许可协议