ciyon_ai/aiskill/ciyon-web3d.md
2026-04-15 17:28:46 +08:00

1138 lines
30 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Ciyon Web3D 应用开发指南
## 概述
本文档为AI开发3D地图应用提供指导重点讲解如何基于 `cemap.html` 进行二次开发,实现资产点击交互和统计图表展示等功能。
## 技术栈
### 前端
- **核心引擎**: Cesium.js (基于WebGL的3D地球可视化引擎)
- **UI框架**: 自定义框架 (ciy.js, ciycmp.js)
- **图表库**: ECharts (可选,用于统计图表)
### 数据库
- MySQL
- **主要数据表**:
- `zc_cemap_data` - 地图配置数据
- `zc_cemap_bill` - 指示牌资源
- `zc_cemap_glb` - GLB模型资源
---
## 资产管理
### 资产说明
系统提供以下资产类型,可通过后台管理界面进行管理:
1. **GLB模型资源** - 3D建筑、设施等模型
- 管理界面: `glb.html`
- 数据表: `zc_cemap_glb`
- 支持路径分类管理
2. **指示牌资源** - 平面图片、标识牌等
- 管理界面: `bill.html`
- 数据表: `zc_cemap_bill`
- 支持路径分类管理
3. **3D Tile资源** - 实景航拍、大规模3D场景
- 管理界面: `ceeditor.html`(地编器)
- 可直接在编辑器中添加和配置
### 地图配置
地图配置存储在 `zc_cemap_data` 表的 `mapjson` 字段中,包含:
- 地图源设置(天地图、高德、腾讯、百度等)
- 3D Tile列表
- Entity列表GLB模型、指示牌等
- 飞行点列表
- 地形、遮罩等设置
---
## 核心API - ciyearth4.js
### 1. 初始化地图
```javascript
var ce = new ciyearth();
ce.init({
domid: 'ceContainer', // DOM容器ID或DOM对象
personheight: 1.8, // 眼睛到地面高度
timeline: 0, // 1显示时间轴
ion: 'your-ion-token', // Cesium Ion授权token
sunhourmin: '12:12', // 太阳时间
setin: 3, // 1地球飞入, 2中国飞入, 3直接进入
wmts_source: 1, // 地图源: 1默认, 2纯色, 3天地图, 4高德, 5腾讯, 6百度
wmts_style: 1, // 样式: 1卫星, 2卫星(标注), 3矢量
tiles: [], // 3DTile数组
entitys: [], // Entity数组
flys: [] // 快捷定位点数组
});
```
### 3. Entity管理
#### Entity类型
- `model` - 3D模型(GLB/GLTF)
- `billboard` - 永正面(始终朝向相机)
- `plane` - 墙面(平面贴图)
#### 添加Entity
```javascript
ce.addentity({
type: 'model', // 类型: model/billboard/plane
name: '建筑名称',
bind: 'building_123', // 资产编号,用于关联业务数据
lng: 116.39, // 经度
lat: 39.9, // 纬度
height: 10, // 高度
url: '/path/to/model.glb', // 模型URL
w: 10, // 宽度(米) - plane/billboard
h: 10, // 高度(米) - plane/billboard
sc: 1 // 缩放比例
});
```
#### 添加标记
```javascript
ce.addmarker({
lng: 116.39,
lat: 39.9,
img: '/path/to/icon.png',
width: 20,
height: 27,
autoheight: true
});
```
### 4. 相机控制
#### 飞行到指定位置
```javascript
ce.flyTo({
fd: {x, y, z}, // 目标位置
fo: {h, p, r} // h:heading, p:pitch, r:roll
}, 3); // 时间(秒)
```
#### 设置相机位置
```javascript
ce.setView({
fd: {x, y, z},
fo: {h, p, r}
});
```
#### 获取相机位置
```javascript
var camera = ce.getView();
// 返回: {fd: {x, y, z}, fo: {h, p, r}}
```
### 5. 事件系统
```javascript
ce.ciyevent = function(type, act, data, data2) {
if (type == 'entity') {
if (act == 'leftclick') {
// 左键点击Entity
var entity = data.entity;
var bindId = entity.ciydata.bind; // 获取资产编号
console.log('点击了资产:', bindId);
// 在这里处理资产点击事件
showAssetInfo(bindId);
}
} else if (type == 'tile') {
if (act == 'leftclick') {
// 左键点击3D Tile
var primitive = data.primitive;
console.log('点击了Tile');
}
} else if (type == 'control') {
if (act == 'op') {
// 控制操作中(飞行/行走)
// data: Cartographic相机位置
updateCameraInfo(data);
}
}
};
```
### 6. 飞行/行走模式
```javascript
// 开启飞行模式
ce.control_fly_open(false); // 飞行
ce.control_fly_open(true); // 行走
// 关闭飞行模式
ce.control_fly_close();
```
**键盘控制**:
- `W` - 前进
- `S` - 后退
- `A` - 左移
- `D` - 右移
- `Q` - 上升
- `E` - 下降
- `Z` - 左转
- `X` - 右转
- `空格` - 跳跃(行走模式)
- `F` - 减速
- `R` - 加速
- `ESC` - 退出飞行模式
### 7. 地形管理
```javascript
// 添加地形
ce.add_terrain('url', {
url: 'https://example.com/terrain',
requestVertexNormals: true,
requestWaterMask: true
});
// 获取高度
var height = await ce.getposheight(cartesian3);
var floorHeight = ce.getfloorheight();
```
---
## 地图应用开发
### 基础页面结构
```html
<!DOCTYPE html>
<html>
<head>
<title>3D地图应用</title>
<link href="/jscss/style.css" rel="stylesheet" type="text/css" />
<link href="/zces108/widgets.css" rel="stylesheet" type="text/css" />
<style type="text/css">
#ceContainer {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
/* 浮动面板样式 */
.float-panel {
position: absolute;
background: rgba(255, 255, 255, 0.95);
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
padding: 15px;
z-index: 1000;
}
.float-panel.top {
top: 20px;
left: 50%;
transform: translateX(-50%);
}
.float-panel.left {
top: 80px;
left: 20px;
width: 300px;
max-height: 80vh;
overflow-y: auto;
}
.float-panel.right {
top: 80px;
right: 20px;
width: 350px;
max-height: 80vh;
overflow-y: auto;
}
.float-panel.bottom {
bottom: 20px;
left: 50%;
transform: translateX(-50%);
}
/* 控制面板 */
.control-panel {
position: absolute;
right: 0;
top: 0;
background: rgba(255, 255, 255, 0.8);
border-radius: 0 0 0 8px;
padding: 10px;
}
/* 飞行点列表 */
.fly-points {
position: absolute;
bottom: 0;
left: 0;
right: 0;
display: flex;
justify-content: center;
flex-wrap: wrap;
gap: 10px;
padding-bottom: 30px;
}
.fly-points > div {
padding: 8px 20px;
background: rgba(255, 255, 255, 0.9);
border: 1px solid #ddd;
border-radius: 20px;
color: #333;
cursor: pointer;
transition: all 0.3s;
}
.fly-points > div:hover {
background: #fff;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}
.fly-points > div.select {
background: #007aff;
color: #fff;
border-color: #007aff;
}
/* 图表容器 */
.chart-container {
width: 100%;
height: 200px;
margin-top: 10px;
}
</style>
</head>
<body>
<div id="ceContainer"></div>
<!-- 控制面板 -->
<div class="control-panel">
<div class="flex">
<div class="tip flex1" id="cameraTip"></div>
<div class="btn xs def" onclick="ce.control_fly_open(false)">飞行</div>
<div class="btn xs def" onclick="ce.control_fly_open(true)">步行</div>
</div>
</div>
<!-- 飞行点列表 -->
<div class="fly-points" id="flyPoints"></div>
<!-- 左侧资产列表 -->
<div class="float-panel left" id="assetPanel" style="display:none;">
<h3>资产信息</h3>
<div id="assetInfo"></div>
<div id="assetCharts"></div>
</div>
<!-- 右侧统计面板 -->
<div class="float-panel right" id="statPanel">
<h3>统计数据</h3>
<div id="statContent"></div>
</div>
<!-- 加载脚本 -->
<script type="text/javascript" src="/jscss/ciy.js"></script>
<script type="text/javascript" src="/zces108/Cesium.js"></script>
<script type="text/javascript" src="/zces108/ciyearth.min.js"></script>
<script type="text/javascript" src="/zces108/map.min.js"></script>
<script type="text/javascript" src="/jscss/echarts.min.js"></script>
<script type="text/javascript">
'use strict';
var ce = new ciyearth();
var currentAssetId = null;
var statChart = null;
// 初始化地图
function initMap() {
ciyfn.callfunc('init', {}, function (json) {
var mapset = ciyfn.tojson(json.cemap.mapjson);
mapset.domid = 'ceContainer';
ce.init(mapset);
// 渲染飞行点
renderFlyPoints(mapset.flys);
// 初始化统计图表
initStatChart();
});
}
// 渲染飞行点
function renderFlyPoints(flys) {
if (!flys || flys.length === 0) return;
var container = $5('#flyPoints');
for (var i = 0; i < flys.length; i++) {
var html = $5('<div onclick="flyTo(this)">' + flys[i].name + '</div>');
html.attr('data-dat', flys[i].dat);
container.append(html);
}
}
// 飞行到指定点
function flyTo(dom) {
event.stopPropagation();
$5('.fly-points>div').removeClass('select');
$5(dom).addClass('select');
var dat = $5(dom).attr('data-dat');
ce.flyTo(ciyfn.tojson(dat), 3);
}
// 显示资产信息
function showAssetInfo(assetId) {
currentAssetId = assetId;
// 显示左侧面板
$5('#assetPanel').show();
// 获取资产详情
ciyfn.callfunc('getAssetDetail', {id: assetId}, function (json) {
var html = '<div class="asset-detail">';
html += '<p><strong>名称:</strong> ' + json.data.name + '</p>';
html += '<p><strong>类型:</strong> ' + json.data.type + '</p>';
html += '<p><strong>位置:</strong> ' + json.data.location + '</p>';
html += '<p><strong>状态:</strong> ' + json.data.status + '</p>';
html += '</div>';
$5('#assetInfo').html(html);
// 渲染资产相关图表
renderAssetCharts(json.data);
});
}
// 渲染资产图表
function renderAssetCharts(assetData) {
var chartsContainer = $5('#assetCharts');
chartsContainer.html('');
// 示例:渲染趋势图
var chart1 = $5('<div class="chart-container" id="chart1"></div>');
chartsContainer.append(chart1);
var option1 = {
title: { text: '近7天访问量', left: 'center', textStyle: {fontSize: 12} },
xAxis: { type: 'category', data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日'] },
yAxis: { type: 'value' },
series: [{
data: assetData.visits || [120, 200, 150, 80, 70, 110, 130],
type: 'line',
smooth: true,
areaStyle: { opacity: 0.3 }
}]
};
var chart1Instance = echarts.init(document.getElementById('chart1'));
chart1Instance.setOption(option1);
// 示例:渲染分布图
var chart2 = $5('<div class="chart-container" id="chart2"></div>');
chartsContainer.append(chart2);
var option2 = {
title: { text: '时段分布', left: 'center', textStyle: {fontSize: 12} },
xAxis: { type: 'category', data: ['00-06', '06-12', '12-18', '18-24'] },
yAxis: { type: 'value' },
series: [{
data: assetData.timeDist || [20, 150, 280, 90],
type: 'bar',
itemStyle: { color: '#5470c6' }
}]
};
var chart2Instance = echarts.init(document.getElementById('chart2'));
chart2Instance.setOption(option2);
// 监听窗口大小变化
window.addEventListener('resize', function() {
chart1Instance.resize();
chart2Instance.resize();
});
}
// 初始化统计图表
function initStatChart() {
var container = $5('#statContent');
container.html('<div class="chart-container" id="statChart"></div>');
statChart = echarts.init(document.getElementById('statChart'));
var option = {
title: { text: '区域统计', left: 'center', textStyle: {fontSize: 14} },
tooltip: { trigger: 'axis' },
legend: { bottom: 0 },
xAxis: { type: 'category', data: ['区域A', '区域B', '区域C', '区域D'] },
yAxis: { type: 'value' },
series: [
{ name: '建筑数', type: 'bar', data: [120, 200, 150, 80] },
{ name: '设备数', type: 'bar', data: [220, 182, 191, 234] }
]
};
statChart.setOption(option);
window.addEventListener('resize', function() {
statChart.resize();
});
}
// 更新相机信息
function updateCameraInfo(cartographic) {
var lng = Cesium.Math.toDegrees(cartographic.longitude);
var lat = Cesium.Math.toDegrees(cartographic.latitude);
var html = '经度:' + lng.toFixed(4) + ' 纬度:' + lat.toFixed(4) + ' 海拔:' + cartographic.height.toFixed(1) + '米';
$5('#cameraTip').html(html);
}
// 设置事件回调
ce.ciyevent = function (type, act, data, data2) {
if (type == 'entity') {
if (act == 'leftclick') {
// 点击Entity
var entity = data.entity;
var bindId = entity.ciydata.bind;
if (bindId) {
showAssetInfo(bindId);
}
}
} else if (type == 'control') {
if (act == 'op') {
// 控制操作中
updateCameraInfo(data);
}
}
};
// 页面加载完成后初始化
ciyfn.pageload(function () {
try {
initMap();
} catch (e) {
console.log('init:', e);
}
});
</script>
</body>
</html>
```
---
## 事件交互
### Entity点击事件
```javascript
ce.ciyevent = function(type, act, data, data2) {
if (type == 'entity' && act == 'leftclick') {
var entity = data.entity;
// 获取Entity信息
var entityInfo = {
id: entity.id,
name: entity.name,
type: entity.ciytype,
bind: entity.ciydata.bind, // 资产编号
position: entity.position._value,
customData: entity.ciydata // 自定义数据
};
console.log('点击Entity:', entityInfo);
// 处理点击事件
handleEntityClick(entityInfo);
}
};
```
### Tile点击事件
```javascript
if (type == 'tile' && act == 'leftclick') {
var primitive = data.primitive;
console.log('点击3D Tile:', primitive);
// 可以通过拾取获取Tile中的具体建筑信息
// 这需要3D Tile数据中包含属性信息
}
```
### 自定义点击事件
```javascript
// 添加自定义点击处理器
var handler = new Cesium.ScreenSpaceEventHandler(ce.viewer.canvas);
handler.setInputAction(function(click) {
var pickedObject = ce.viewer.scene.pick(click.position);
if (Cesium.defined(pickedObject)) {
if (pickedObject.id) {
// 点击了Entity
var entity = pickedObject.id;
console.log('Entity:', entity.name, entity.ciydata);
} else if (pickedObject.primitive) {
// 点击了Primitive如3D Tile
console.log('Primitive:', pickedObject.primitive);
}
} else {
// 点击了空白处
console.log('点击空白处');
// 可以关闭浮动面板
$5('#assetPanel').hide();
}
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
```
---
## 浮动面板
### 创建浮动面板
```javascript
// 左侧面板 - 资产信息
var leftPanel = document.createElement('div');
leftPanel.className = 'float-panel left';
leftPanel.style.cssText = 'top: 80px; left: 20px; width: 320px;';
leftPanel.innerHTML = '<h3>资产信息</h3><div id="assetContent"></div>';
document.body.appendChild(leftPanel);
// 右侧面板 - 统计图表
var rightPanel = document.createElement('div');
rightPanel.className = 'float-panel right';
rightPanel.style.cssText = 'top: 80px; right: 20px; width: 380px;';
rightPanel.innerHTML = '<h3>统计数据</h3><div id="statContent"></div>';
document.body.appendChild(rightPanel);
// 顶部面板 - 搜索/筛选
var topPanel = document.createElement('div');
topPanel.className = 'float-panel top';
topPanel.innerHTML = '<input type="text" placeholder="搜索资产..." />';
document.body.appendChild(topPanel);
// 底部面板 - 快捷操作
var bottomPanel = document.createElement('div');
bottomPanel.className = 'float-panel bottom';
bottomPanel.innerHTML = '<button onclick="resetView()">重置视角</button>';
document.body.appendChild(bottomPanel);
```
### 面板样式
```css
.float-panel {
position: absolute;
background: rgba(255, 255, 255, 0.95);
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
padding: 15px;
z-index: 1000;
transition: all 0.3s ease;
}
.float-panel.top {
top: 20px;
left: 50%;
transform: translateX(-50%);
}
.float-panel.left {
top: 80px;
left: 20px;
width: 320px;
max-height: calc(100vh - 100px);
overflow-y: auto;
}
.float-panel.right {
top: 80px;
right: 20px;
width: 380px;
max-height: calc(100vh - 100px);
overflow-y: auto;
}
.float-panel.bottom {
bottom: 20px;
left: 50%;
transform: translateX(-50%);
}
/* 面板折叠状态 */
.float-panel.collapsed {
transform: scale(0);
opacity: 0;
pointer-events: none;
}
```
### 面板显示/隐藏
```javascript
// 显示面板
function showPanel(selector) {
$5(selector).removeClass('collapsed');
}
// 隐藏面板
function hidePanel(selector) {
$5(selector).addClass('collapsed');
}
// 切换面板
function togglePanel(selector) {
$5(selector).toggleClass('collapsed');
}
```
---
## 统计图表
### 使用ECharts渲染图表
```javascript
// 渲染柱状图
function renderBarChart(containerId, data) {
var chart = echarts.init(document.getElementById(containerId));
var option = {
title: { text: data.title || '柱状图', left: 'center', textStyle: {fontSize: 12} },
tooltip: { trigger: 'axis' },
xAxis: { type: 'category', data: data.categories || [] },
yAxis: { type: 'value' },
series: [{
name: data.seriesName || '数值',
type: 'bar',
data: data.values || [],
itemStyle: { color: '#5470c6' }
}]
};
chart.setOption(option);
return chart;
}
// 渲染折线图
function renderLineChart(containerId, data) {
var chart = echarts.init(document.getElementById(containerId));
var option = {
title: { text: data.title || '折线图', left: 'center', textStyle: {fontSize: 12} },
tooltip: { trigger: 'axis' },
xAxis: { type: 'category', data: data.categories || [] },
yAxis: { type: 'value' },
series: [{
name: data.seriesName || '数值',
type: 'line',
data: data.values || [],
smooth: true,
areaStyle: { opacity: 0.3 }
}]
};
chart.setOption(option);
return chart;
}
// 渲染饼图
function renderPieChart(containerId, data) {
var chart = echarts.init(document.getElementById(containerId));
var option = {
title: { text: data.title || '饼图', left: 'center', textStyle: {fontSize: 12} },
tooltip: { trigger: 'item' },
legend: { bottom: 0 },
series: [{
type: 'pie',
radius: '50%',
data: data.values || [],
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
}]
};
chart.setOption(option);
return chart;
}
```
### 响应式图表
```javascript
// 监听窗口大小变化
var charts = [];
function addChart(chart) {
charts.push(chart);
}
window.addEventListener('resize', function() {
charts.forEach(function(chart) {
chart.resize();
});
});
```
---
## 完整示例
### 示例:智慧园区管理
```javascript
// 资产数据映射
var assetDataMap = {
'building_001': {
name: 'A栋办公楼',
type: '办公楼',
floors: 18,
area: 12000,
occupancy: 85,
status: '正常',
energy: { today: 4500, month: 120000 },
visits: [120, 200, 150, 80, 70, 110, 130],
timeDist: [20, 150, 280, 90]
},
'building_002': {
name: 'B栋研发中心',
type: '研发中心',
floors: 12,
area: 8000,
occupancy: 92,
status: '正常',
energy: { today: 3800, month: 98000 },
visits: [90, 150, 180, 100, 60, 130, 140],
timeDist: [15, 120, 250, 80]
}
};
// 处理Entity点击
function handleEntityClick(entityInfo) {
var assetId = entityInfo.bind;
if (!assetId || !assetDataMap[assetId]) {
console.log('未知资产:', assetId);
return;
}
var asset = assetDataMap[assetId];
// 显示资产信息面板
showAssetPanel(asset);
// 更新统计图表
updateStatCharts(asset);
// 飞行到资产位置
if (entityInfo.position) {
ce.viewer.flyTo(ce.viewer.entities.getById(entityInfo.id), {
offset: new Cesium.HeadingPitchRange(1.57, -0.6, 50)
});
}
}
// 显示资产信息面板
function showAssetPanel(asset) {
var html = '<div class="asset-info">';
html += '<h4>' + asset.name + '</h4>';
html += '<div class="info-grid">';
html += '<div><span>类型:</span>' + asset.type + '</div>';
html += '<div><span>楼层:</span>' + asset.floors + '层</div>';
html += '<div><span>面积:</span>' + asset.area + '㎡</div>';
html += '<div><span>入住率:</span>' + asset.occupancy + '%</div>';
html += '<div><span>状态:</span><span class="status ' + asset.status + '">' + asset.status + '</span></div>';
html += '</div>';
html += '<div class="energy-info">';
html += '<div><span>今日能耗:</span>' + asset.energy.today + ' kWh</div>';
html += '<div><span>本月能耗:</span>' + asset.energy.month + ' kWh</div>';
html += '</div>';
html += '</div>';
$5('#assetContent').html(html);
}
// 更新统计图表
function updateStatCharts(asset) {
// 更新访问量趋势图
var visitsChart = echarts.init(document.getElementById('visitsChart'));
visitsChart.setOption({
series: [{ data: asset.visits }]
});
// 更新时段分布图
var timeDistChart = echarts.init(document.getElementById('timeDistChart'));
timeDistChart.setOption({
series: [{ data: asset.timeDist }]
});
}
// 初始化页面
function initPage() {
// 初始化地图
ce.init({
domid: 'ceContainer',
wmts_source: 4,
wmts_style: 3,
setin: 3,
entitys: [
{
type: 'model',
name: 'A栋办公楼',
bind: 'building_001',
lng: 116.39,
lat: 39.9,
height: 0,
url: '/models/building_a.glb'
},
{
type: 'model',
name: 'B栋研发中心',
bind: 'building_002',
lng: 116.40,
lat: 39.9,
height: 0,
url: '/models/building_b.glb'
}
]
});
// 设置事件回调
ce.ciyevent = function(type, act, data) {
if (type == 'entity' && act == 'leftclick') {
var entity = data.entity;
handleEntityClick({
id: entity.id,
bind: entity.ciydata.bind,
position: entity.position._value
});
}
};
}
// 页面加载完成后执行
ciyfn.pageload(initPage);
```
---
## 最佳实践
### 1. 性能优化
```javascript
// 使用requestRenderMode按需渲染
ce.init({
domid: 'ceContainer',
requestRenderMode: true,
maximumRenderTimeChange: Infinity
});
// 距离优化只加载视野内的Entity
ce.reloadentity(); // 自动优化加载
// 减少Entity数量
// 对于大量相似Entity考虑使用3D Tile或PrimitiveCollection
```
### 2. 事件处理
```javascript
// 使用节流防止频繁触发
function throttle(func, delay) {
var lastTime = 0;
return function() {
var now = Date.now();
if (now - lastTime >= delay) {
lastTime = now;
func.apply(this, arguments);
}
};
}
// 应用节流
ce.ciyevent = throttle(function(type, act, data) {
// 处理事件
}, 100);
```
### 3. 内存管理
```javascript
// 销毁图表实例
function disposeCharts() {
charts.forEach(function(chart) {
chart.dispose();
});
charts = [];
}
// 页面卸载时清理
window.addEventListener('beforeunload', function() {
disposeCharts();
ce.destroy();
});
```
### 4. 响应式设计
```javascript
// 监听窗口大小变化
window.addEventListener('resize', function() {
// 调整图表大小
charts.forEach(function(chart) {
chart.resize();
});
// 调整面板位置
updatePanelPositions();
});
// 移动端适配
if (ciyfn.inmobile()) {
// 隐藏部分面板
$5('.control-panel').hide();
// 调整面板样式
$5('.float-panel.left').css('width', '80%');
}
```
---
## 常见问题
### 1. 如何获取点击的Entity详细信息
```javascript
ce.ciyevent = function(type, act, data) {
if (type == 'entity' && act == 'leftclick') {
var entity = data.entity;
console.log('Entity ID:', entity.id);
console.log('Entity Name:', entity.name);
console.log('Entity Type:', entity.ciytype);
console.log('Custom Data:', entity.ciydata);
console.log('Position:', entity.position._value);
}
};
```
### 2. 如何在点击时高亮显示Entity
```javascript
// 使用轮廓高亮
ce.silhouette.selected = [entity];
// 使用颜色高亮
entity.model.color = Cesium.Color.fromCssColorString('#ffff00');
// 重置高亮
ce.silhouette.selected = [];
entity.model.color = Cesium.Color.WHITE;
```
### 3. 如何加载大量Entity而不影响性能
```javascript
// 分批加载
var batchSize = 100;
var currentIndex = 0;
function loadBatch() {
var batch = entities.slice(currentIndex, currentIndex + batchSize);
batch.forEach(function(entityData) {
ce.addentity(entityData);
});
currentIndex += batchSize;
if (currentIndex < entities.length) {
setTimeout(loadBatch, 100);
}
}
loadBatch();
```
### 4. 如何实现图层的显示/隐藏?
```javascript
// 给Entity添加分组属性
ce.addentity({
type: 'model',
name: '建筑1',
category: 'building', // 分类
// ...
});
// 控制图层显示
function toggleLayer(category, visible) {
for (var id in ce.entitys) {
var entity = ce.entitys[id];
if (entity.ciydata.category === category) {
entity.show = visible;
}
}
}
// 使用
toggleLayer('building', false); // 隐藏建筑层
toggleLayer('building', true); // 显示建筑层
```
### 5. 如何实现搜索定位功能?
```javascript
// 搜索Entity
function searchEntity(keyword) {
for (var id in ce.entitys) {
var entity = ce.entitys[id];
if (entity.name && entity.name.indexOf(keyword) > -1) {
// 找到匹配的Entity
flyToEntity(id);
return;
}
}
}
// 飞行到Entity
function flyToEntity(entityId) {
var entity = ce.entitys[entityId];
ce.viewer.flyTo(entity, {
offset: new Cesium.HeadingPitchRange(1.57, -0.6, 50)
});
// 高亮显示
ce.silhouette.selected = [entity];
}
```
---
## 参考资料
- Cesium官方文档: https://cesium.com/docs/
- Cesium Ion: https://cesium.com/ion/
- ECharts文档: https://echarts.apache.org/zh/index.html
- 开源作者: 众产®
- 官网: http://ciy.cn/code