|
|
|
@ -168,6 +168,7 @@ export default { |
|
|
|
// 实体管理 |
|
|
|
allEntities: [], // 所有绘制的实体 |
|
|
|
entityCounter: 0, |
|
|
|
loadingDrawingsFromRoom: false, |
|
|
|
selectedEntity: null, // 当前选中的实体 |
|
|
|
// 测量结果 |
|
|
|
measurementResult: null, |
|
|
|
@ -198,7 +199,7 @@ export default { |
|
|
|
circle: { color: '#800080', opacity: 0, width: 4 }, |
|
|
|
sector: { color: '#FF6347', opacity: 0, width: 3 }, |
|
|
|
arrow: { color: '#FF0000', width: 6 }, |
|
|
|
text: { color: '#000000', font: '48px Microsoft YaHei, PingFang SC, sans-serif', backgroundColor: 'rgba(255, 255, 255, 0.8)' }, |
|
|
|
text: { color: '#000000', font: '14px PingFang SC, Microsoft YaHei, Helvetica Neue, sans-serif', backgroundColor: 'rgba(255, 255, 255, 0.92)' }, |
|
|
|
image: { width: 150, height: 150 } |
|
|
|
}, |
|
|
|
// 鼠标经纬度 |
|
|
|
@ -2030,6 +2031,7 @@ export default { |
|
|
|
this.initHoverHandler() |
|
|
|
this.initMouseCoordinates() |
|
|
|
console.log('Cesium离线二维地图已加载') |
|
|
|
this.$emit('viewer-ready') |
|
|
|
|
|
|
|
// 1. 定义全局拾取处理器(含防抖,避免双击误触导致相机高度剧烈变化) |
|
|
|
this.viewer.scene.postProcessStages.fxaa.enabled = true |
|
|
|
@ -2999,6 +3001,7 @@ export default { |
|
|
|
this.viewer.entities.remove(this.tempEntity) |
|
|
|
this.tempEntity = null |
|
|
|
} |
|
|
|
this.notifyDrawingEntitiesChanged() |
|
|
|
return entity |
|
|
|
}, |
|
|
|
// 绘制矩形(优化版:两点定矩形,实时预览) |
|
|
|
@ -3146,6 +3149,7 @@ export default { |
|
|
|
}; |
|
|
|
// 6. 重置状态,保持绘制状态以继续绘制 |
|
|
|
this.drawingPoints = []; |
|
|
|
this.notifyDrawingEntitiesChanged(); |
|
|
|
}, |
|
|
|
// 计算矩形面积(辅助方法) |
|
|
|
calculateRectangleArea(rectangle) { |
|
|
|
@ -3377,6 +3381,7 @@ export default { |
|
|
|
// 6. 重置状态,保持绘制状态以继续绘制 |
|
|
|
this.drawingPoints = []; |
|
|
|
this.activeCursorPosition = null; |
|
|
|
this.notifyDrawingEntitiesChanged(); |
|
|
|
}, |
|
|
|
ellipseHeadingFromCenterAndMajor(center, majorEnd) { |
|
|
|
const ellipsoid = this.viewer.scene.globe.ellipsoid; |
|
|
|
@ -3407,11 +3412,12 @@ export default { |
|
|
|
if (this.tempPreviewEntity) this.viewer.entities.remove(this.tempPreviewEntity); |
|
|
|
this.tempEntity = null; |
|
|
|
this.tempPreviewEntity = null; |
|
|
|
// 2. 鼠标移动事件 |
|
|
|
// 2. 鼠标移动事件(requestRender 保证 requestRenderMode 下实时预览会刷新) |
|
|
|
this.drawingHandler.setInputAction((movement) => { |
|
|
|
const newPosition = this.getClickPosition(movement.endPosition); |
|
|
|
if (newPosition) { |
|
|
|
this.activeCursorPosition = newPosition; |
|
|
|
if (this.viewer.scene.requestRenderMode) this.viewer.scene.requestRender(); |
|
|
|
} |
|
|
|
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE); |
|
|
|
// 3. 鼠标点击事件 |
|
|
|
@ -3557,6 +3563,7 @@ export default { |
|
|
|
this.allEntities.push(entityData); |
|
|
|
// 5. 重置状态,保持绘制状态以继续绘制 |
|
|
|
this.drawingPoints = []; |
|
|
|
this.notifyDrawingEntitiesChanged(); |
|
|
|
}, |
|
|
|
// 生成圆形的点,用于绘制边框线 |
|
|
|
generateCirclePositions(center, radius, numPoints = 1024) { |
|
|
|
@ -3671,11 +3678,12 @@ export default { |
|
|
|
if (this.tempPreviewEntity) this.viewer.entities.remove(this.tempPreviewEntity); |
|
|
|
this.tempEntity = null; |
|
|
|
this.tempPreviewEntity = null; |
|
|
|
// 2. 鼠标移动事件 |
|
|
|
// 2. 鼠标移动事件(requestRender 保证 requestRenderMode 下实时预览会刷新) |
|
|
|
this.drawingHandler.setInputAction((movement) => { |
|
|
|
const newPosition = this.getClickPosition(movement.endPosition); |
|
|
|
if (newPosition) { |
|
|
|
this.activeCursorPosition = newPosition; |
|
|
|
if (this.viewer.scene.requestRenderMode) this.viewer.scene.requestRender(); |
|
|
|
} |
|
|
|
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE); |
|
|
|
// 3. 鼠标点击事件 |
|
|
|
@ -3737,6 +3745,7 @@ export default { |
|
|
|
const entity = this.addArrowEntity([...this.drawingPoints]); |
|
|
|
// 重置绘制点数组,保持绘制状态以继续绘制 |
|
|
|
this.drawingPoints = []; |
|
|
|
this.notifyDrawingEntitiesChanged(); |
|
|
|
return entity; |
|
|
|
} else { |
|
|
|
this.cancelDrawing(); |
|
|
|
@ -3815,28 +3824,17 @@ export default { |
|
|
|
text: text, |
|
|
|
font: this.defaultStyles.text.font, |
|
|
|
fillColor: Cesium.Color.fromCssColorString(this.defaultStyles.text.color), |
|
|
|
outlineColor: Cesium.Color.BLACK, |
|
|
|
outlineWidth: 2, |
|
|
|
outlineColor: Cesium.Color.fromCssColorString('#e5e5e5'), |
|
|
|
outlineWidth: 1, |
|
|
|
style: Cesium.LabelStyle.FILL_AND_OUTLINE, |
|
|
|
verticalOrigin: Cesium.VerticalOrigin.CENTER, |
|
|
|
horizontalOrigin: Cesium.HorizontalOrigin.CENTER, |
|
|
|
backgroundColor: Cesium.Color.fromCssColorString(this.defaultStyles.text.backgroundColor), |
|
|
|
backgroundPadding: new Cesium.Cartesian2(10, 5), |
|
|
|
backgroundPadding: new Cesium.Cartesian2(8, 5), |
|
|
|
pixelOffset: new Cesium.Cartesian2(0, 0), |
|
|
|
// 随地图缩放调整大小 |
|
|
|
scaleByDistance: new Cesium.NearFarScalar( |
|
|
|
1000, // 近距离(米) |
|
|
|
1.0, // 近距离时的缩放比例 |
|
|
|
500000, // 远距离(米) |
|
|
|
0.1 // 远距离时的缩放比例(不为0,保持可见) |
|
|
|
), |
|
|
|
// 随地图缩放调整透明度 |
|
|
|
translucencyByDistance: new Cesium.NearFarScalar( |
|
|
|
1000, // 近距离(米) |
|
|
|
1.0, // 近距离时的透明度 |
|
|
|
500000, // 远距离(米) |
|
|
|
0.3 // 远距离时的透明度 |
|
|
|
) |
|
|
|
// 模仿高德:常用缩放下几乎不变,拉远时略缩小、拉近时略放大,过渡柔和 |
|
|
|
scaleByDistance: new Cesium.NearFarScalar(200, 1.12, 1200000, 0.72), |
|
|
|
translucencyByDistance: new Cesium.NearFarScalar(300, 1.0, 600000, 0.88) |
|
|
|
} |
|
|
|
}) |
|
|
|
const entityData = { |
|
|
|
@ -3857,6 +3855,7 @@ export default { |
|
|
|
this.selectEntity(entityData) |
|
|
|
e.stopPropagation() |
|
|
|
} |
|
|
|
this.notifyDrawingEntitiesChanged() |
|
|
|
return entityData |
|
|
|
}, |
|
|
|
// 绘制图片 |
|
|
|
@ -3954,20 +3953,8 @@ export default { |
|
|
|
height: this.defaultStyles.image.height, |
|
|
|
verticalOrigin: Cesium.VerticalOrigin.CENTER, |
|
|
|
horizontalOrigin: Cesium.HorizontalOrigin.CENTER, |
|
|
|
// 随地图缩放调整大小 |
|
|
|
scaleByDistance: new Cesium.NearFarScalar( |
|
|
|
1000, // 近距离(米) |
|
|
|
1.0, // 近距离时的缩放比例 |
|
|
|
500000, // 远距离(米) |
|
|
|
0.1 // 远距离时的缩放比例(不为0,保持可见) |
|
|
|
), |
|
|
|
// 随地图缩放调整透明度 |
|
|
|
translucencyByDistance: new Cesium.NearFarScalar( |
|
|
|
1000, // 近距离(米) |
|
|
|
1.0, // 近距离时的透明度 |
|
|
|
500000, // 远距离(米) |
|
|
|
0.3 // 远距离时的透明度 |
|
|
|
) |
|
|
|
scaleByDistance: new Cesium.NearFarScalar(200, 1.12, 1200000, 0.72), |
|
|
|
translucencyByDistance: new Cesium.NearFarScalar(300, 1.0, 600000, 0.88) |
|
|
|
} |
|
|
|
}) |
|
|
|
const entityData = { |
|
|
|
@ -3987,6 +3974,7 @@ export default { |
|
|
|
this.selectEntity(entityData) |
|
|
|
e.stopPropagation() |
|
|
|
} |
|
|
|
this.notifyDrawingEntitiesChanged() |
|
|
|
return entityData |
|
|
|
}, |
|
|
|
// ================== 实体创建方法 ================== |
|
|
|
@ -4103,6 +4091,7 @@ export default { |
|
|
|
this.selectEntity(entityData) |
|
|
|
e.stopPropagation() |
|
|
|
} |
|
|
|
this.notifyDrawingEntitiesChanged() |
|
|
|
return entityData |
|
|
|
}, |
|
|
|
addRectangleEntity(coordinates) { |
|
|
|
@ -4509,6 +4498,10 @@ export default { |
|
|
|
} |
|
|
|
// 更新实体样式 |
|
|
|
this.updateEntityStyle(entityData) |
|
|
|
// 若修改的是空域/威力区图形的样式,触发自动保存到房间,避免刷新后样式丢失 |
|
|
|
if (this.getDrawingEntityTypes().includes(entityData.type)) { |
|
|
|
this.notifyDrawingEntitiesChanged() |
|
|
|
} |
|
|
|
// 隐藏右键菜单 |
|
|
|
this.contextMenu.visible = false |
|
|
|
} |
|
|
|
@ -4611,11 +4604,13 @@ export default { |
|
|
|
this.viewer.entities.remove(entity.centerEntity) |
|
|
|
} |
|
|
|
// 从数组中移除 |
|
|
|
const wasDrawingType = this.getDrawingEntityTypes().includes(entity.type) |
|
|
|
this.allEntities.splice(index, 1) |
|
|
|
// 如果删除的是选中的实体,清空选中状态 |
|
|
|
if (this.selectedEntity && (this.selectedEntity.id === id || (this.selectedEntity.entity && this.selectedEntity.entity.id === id))) { |
|
|
|
this.selectedEntity = null |
|
|
|
} |
|
|
|
if (wasDrawingType) this.notifyDrawingEntitiesChanged() |
|
|
|
} |
|
|
|
}, |
|
|
|
/** 根据房间平台图标记录 ID(serverId)移除地图上对应的平台图标(用于该平台已创建航线后删除其“占位”图标) */ |
|
|
|
@ -4629,6 +4624,25 @@ export default { |
|
|
|
this.allEntities = this.allEntities.filter(e => !(e.type === 'platformIcon' && e.serverId === serverId)) |
|
|
|
}, |
|
|
|
clearAll(showConfirm = true) { |
|
|
|
// 空域模式:只清除空域/威力区图形,不清除摆放的平台与航线 |
|
|
|
if (this.toolMode === 'airspace') { |
|
|
|
if (showConfirm) { |
|
|
|
this.$confirm('是否清除所有空域图形?(平台与航线将保留)', '提示', { |
|
|
|
confirmButtonText: '确定', |
|
|
|
cancelButtonText: '取消', |
|
|
|
type: 'warning' |
|
|
|
}).then(() => { |
|
|
|
this.clearDrawingEntities(); |
|
|
|
this.notifyDrawingEntitiesChanged(); |
|
|
|
this.$message({ type: 'success', message: '已清除空域图形' }); |
|
|
|
}).catch(() => {}); |
|
|
|
} else { |
|
|
|
this.clearDrawingEntities(); |
|
|
|
this.notifyDrawingEntitiesChanged(); |
|
|
|
} |
|
|
|
return; |
|
|
|
} |
|
|
|
// 测距等其他模式:保持原“清除所有编辑内容”行为 |
|
|
|
if (showConfirm) { |
|
|
|
this.$confirm('是否清除所有编辑内容?', '提示', { |
|
|
|
confirmButtonText: '确定', |
|
|
|
@ -4728,11 +4742,174 @@ export default { |
|
|
|
this.measurementResult = null; |
|
|
|
this.stopDrawing(); |
|
|
|
|
|
|
|
this.notifyDrawingEntitiesChanged(); |
|
|
|
this.$message({ |
|
|
|
type: 'success', |
|
|
|
message: '清除成功!' |
|
|
|
}); |
|
|
|
}, |
|
|
|
// ================== 空域/威力区图形持久化 ================== |
|
|
|
/** 需要持久化到方案的空域图形类型(不含平台图标、航线、测距点线) */ |
|
|
|
getDrawingEntityTypes() { |
|
|
|
return ['polygon', 'rectangle', 'circle', 'sector', 'arrow', 'text', 'image', 'powerZone'] |
|
|
|
}, |
|
|
|
/** 空域/威力区图形增删时通知父组件,用于自动保存到房间(从房间加载时不触发) */ |
|
|
|
notifyDrawingEntitiesChanged() { |
|
|
|
if (this.loadingDrawingsFromRoom) return |
|
|
|
this.$emit('drawing-entities-changed') |
|
|
|
}, |
|
|
|
/** 将单个实体序列化为可存储的 JSON 结构 */ |
|
|
|
serializeEntityForSave(entity) { |
|
|
|
const base = { id: entity.id, type: entity.type, label: entity.label || '', color: entity.color || '#008aff' } |
|
|
|
let data = {} |
|
|
|
switch (entity.type) { |
|
|
|
case 'point': |
|
|
|
data = { lat: entity.lat, lng: entity.lng }; break |
|
|
|
case 'line': |
|
|
|
data = { points: entity.points || [] }; break |
|
|
|
case 'polygon': |
|
|
|
data = { |
|
|
|
points: entity.points || [], |
|
|
|
opacity: entity.opacity != null ? entity.opacity : 0, |
|
|
|
width: entity.width != null ? entity.width : 4, |
|
|
|
borderColor: entity.borderColor || entity.color |
|
|
|
}; break |
|
|
|
case 'rectangle': |
|
|
|
if (entity.points && entity.points.length >= 2) { |
|
|
|
const lngs = entity.points.map(p => p.lng) |
|
|
|
const lats = entity.points.map(p => p.lat) |
|
|
|
data = { |
|
|
|
coordinates: { west: Math.min(...lngs), south: Math.min(...lats), east: Math.max(...lngs), north: Math.max(...lats) }, |
|
|
|
points: entity.points, |
|
|
|
opacity: entity.opacity != null ? entity.opacity : 0, |
|
|
|
width: entity.width != null ? entity.width : 4, |
|
|
|
borderColor: entity.borderColor || entity.color |
|
|
|
} |
|
|
|
} else { |
|
|
|
data = { |
|
|
|
coordinates: entity.coordinates || {}, |
|
|
|
points: entity.points || [], |
|
|
|
opacity: entity.opacity != null ? entity.opacity : 0, |
|
|
|
width: entity.width != null ? entity.width : 4, |
|
|
|
borderColor: entity.borderColor || entity.color |
|
|
|
} |
|
|
|
} |
|
|
|
break |
|
|
|
case 'circle': |
|
|
|
case 'hold_circle': |
|
|
|
data = { |
|
|
|
center: entity.points && entity.points[0] ? entity.points[0] : (entity.positions && entity.positions[0] ? this.cartesianToLatLng(entity.positions[0]) : (entity.center && typeof entity.center.lat === 'number' ? entity.center : null)), |
|
|
|
radius: entity.radius, |
|
|
|
opacity: entity.opacity != null ? entity.opacity : 0, |
|
|
|
width: entity.width != null ? entity.width : 4, |
|
|
|
borderColor: entity.borderColor || entity.color |
|
|
|
}; break |
|
|
|
case 'ellipse': |
|
|
|
case 'hold_ellipse': |
|
|
|
data = { |
|
|
|
center: entity.points && entity.points[0] ? entity.points[0] : (entity.positions && entity.positions[0] ? this.cartesianToLatLng(entity.positions[0]) : null), |
|
|
|
semiMajorAxis: entity.semiMajorAxis, |
|
|
|
semiMinorAxis: entity.semiMinorAxis, |
|
|
|
headingDeg: entity.headingDeg != null ? entity.headingDeg : 0 |
|
|
|
}; break |
|
|
|
case 'sector': |
|
|
|
data = { |
|
|
|
center: entity.center, |
|
|
|
radius: entity.radius, |
|
|
|
startAngle: entity.startAngle, |
|
|
|
endAngle: entity.endAngle, |
|
|
|
opacity: entity.opacity != null ? entity.opacity : 0, |
|
|
|
width: entity.width != null ? entity.width : 3, |
|
|
|
borderColor: entity.borderColor || entity.color |
|
|
|
}; break |
|
|
|
case 'arrow': |
|
|
|
data = { points: entity.points || [] }; break |
|
|
|
case 'text': |
|
|
|
data = { |
|
|
|
lat: entity.lat, |
|
|
|
lng: entity.lng, |
|
|
|
text: entity.text, |
|
|
|
font: entity.font, |
|
|
|
backgroundColor: entity.backgroundColor |
|
|
|
}; break |
|
|
|
case 'image': |
|
|
|
data = { |
|
|
|
lat: entity.lat, |
|
|
|
lng: entity.lng, |
|
|
|
imageUrl: entity.imageUrl, |
|
|
|
width: entity.width, |
|
|
|
height: entity.height |
|
|
|
}; break |
|
|
|
case 'powerZone': { |
|
|
|
const center = entity.center && typeof entity.center.lat === 'number' ? entity.center : (entity.entity && entity.entity.position ? this.cartesianToLatLng(entity.entity.position.getValue(Cesium.JulianDate.now())) : null) |
|
|
|
data = { |
|
|
|
center, |
|
|
|
radius: entity.radius, |
|
|
|
name: entity.name, |
|
|
|
color: entity.color, |
|
|
|
opacity: entity.opacity, |
|
|
|
borderColor: entity.borderColor, |
|
|
|
width: entity.width |
|
|
|
}; break |
|
|
|
} |
|
|
|
default: |
|
|
|
data = entity.center != null ? { center: entity.center, radius: entity.radius } : {} |
|
|
|
} |
|
|
|
return { ...base, data } |
|
|
|
}, |
|
|
|
/** 供父组件/方案保存时调用:仅返回空域与威力区图形数据(不含平台、航线等) */ |
|
|
|
getFrontendDrawingsData() { |
|
|
|
const types = this.getDrawingEntityTypes() |
|
|
|
const entities = (this.allEntities || []) |
|
|
|
.filter(e => e && types.includes(e.type)) |
|
|
|
.map(e => this.serializeEntityForSave(e)) |
|
|
|
return { version: '1.0', date: new Date().toISOString(), entities } |
|
|
|
}, |
|
|
|
/** 仅清除空域/威力区图形(不删平台图标、航线) */ |
|
|
|
clearDrawingEntities() { |
|
|
|
if (!this.allEntities || !this.viewer) return |
|
|
|
const types = this.getDrawingEntityTypes() |
|
|
|
const toRemove = this.allEntities.filter(item => types.includes(item.type)) |
|
|
|
toRemove.forEach(item => { |
|
|
|
try { |
|
|
|
let entity = item.entity || (item instanceof Cesium.Entity ? item : null) |
|
|
|
if (!entity && item.id) entity = this.viewer.entities.getById(item.id) |
|
|
|
if (entity) this.viewer.entities.remove(entity) |
|
|
|
if (item.type === 'powerZone' && item.centerEntity) this.viewer.entities.remove(item.centerEntity) |
|
|
|
} catch (e) { console.warn('clearDrawingEntities:', e) } |
|
|
|
}) |
|
|
|
this.allEntities = this.allEntities.filter(item => !types.includes(item.type)) |
|
|
|
}, |
|
|
|
/** 从房间/方案加载的 frontend_drawings JSON 恢复空域图形(先清空当前图形再导入;加载期间不触发自动保存) */ |
|
|
|
loadFrontendDrawings(data) { |
|
|
|
if (!this.viewer) return |
|
|
|
let payload = data |
|
|
|
if (typeof data === 'string') { |
|
|
|
try { |
|
|
|
payload = JSON.parse(data) |
|
|
|
} catch (e) { |
|
|
|
console.warn('loadFrontendDrawings parse error', e) |
|
|
|
return |
|
|
|
} |
|
|
|
} |
|
|
|
this.loadingDrawingsFromRoom = true |
|
|
|
try { |
|
|
|
if (!payload || !Array.isArray(payload.entities) || payload.entities.length === 0) { |
|
|
|
this.clearDrawingEntities() |
|
|
|
return |
|
|
|
} |
|
|
|
this.clearDrawingEntities() |
|
|
|
payload.entities.forEach(entityData => { |
|
|
|
try { |
|
|
|
this.importEntity(entityData) |
|
|
|
} catch (err) { |
|
|
|
console.warn('loadFrontendDrawings import entity failed', entityData?.type, err) |
|
|
|
} |
|
|
|
}) |
|
|
|
} finally { |
|
|
|
this.loadingDrawingsFromRoom = false |
|
|
|
} |
|
|
|
}, |
|
|
|
// ================== 其他方法 ================== |
|
|
|
getTypeName(type) { |
|
|
|
const names = { |
|
|
|
@ -4747,7 +4924,8 @@ export default { |
|
|
|
sector: '扇形', |
|
|
|
arrow: '箭头', |
|
|
|
text: '文本', |
|
|
|
image: '图片' |
|
|
|
image: '图片', |
|
|
|
powerZone: '威力区' |
|
|
|
} |
|
|
|
return names[type] || type |
|
|
|
}, |
|
|
|
@ -4755,31 +4933,7 @@ export default { |
|
|
|
const data = { |
|
|
|
version: '1.0', |
|
|
|
date: new Date().toISOString(), |
|
|
|
entities: this.allEntities.map(entity => ({ |
|
|
|
id: entity.id, |
|
|
|
type: entity.type, |
|
|
|
label: entity.label, |
|
|
|
color: entity.color, |
|
|
|
data: entity.type === 'point' ? { |
|
|
|
lat: entity.lat, |
|
|
|
lng: entity.lng |
|
|
|
} : entity.type === 'line' || entity.type === 'polygon' ? { |
|
|
|
points: entity.points |
|
|
|
} : entity.type === 'rectangle' ? { |
|
|
|
coordinates: entity.coordinates |
|
|
|
} : entity.type === 'ellipse' || entity.type === 'hold_ellipse' ? { |
|
|
|
center: entity.points && entity.points[0] ? entity.points[0] : (entity.positions && entity.positions[0] ? this.cartesianToLatLng(entity.positions[0]) : null), |
|
|
|
semiMajorAxis: entity.semiMajorAxis, |
|
|
|
semiMinorAxis: entity.semiMinorAxis, |
|
|
|
headingDeg: entity.headingDeg |
|
|
|
} : (entity.type === 'circle' || entity.type === 'hold_circle') ? { |
|
|
|
center: entity.points && entity.points[0] ? entity.points[0] : (entity.positions && entity.positions[0] ? this.cartesianToLatLng(entity.positions[0]) : null), |
|
|
|
radius: entity.radius |
|
|
|
} : { |
|
|
|
center: entity.center, |
|
|
|
radius: entity.radius |
|
|
|
} |
|
|
|
})) |
|
|
|
entities: (this.allEntities || []).map(entity => this.serializeEntityForSave(entity)) |
|
|
|
} |
|
|
|
const blob = new Blob([JSON.stringify(data, null, 2)], {type: 'application/json'}) |
|
|
|
const url = URL.createObjectURL(blob) |
|
|
|
@ -4864,77 +5018,96 @@ export default { |
|
|
|
} |
|
|
|
}) |
|
|
|
break |
|
|
|
case 'polygon': |
|
|
|
case 'polygon': { |
|
|
|
const polygonPositions = entityData.data.points.map(p => Cesium.Cartesian3.fromDegrees(p.lng, p.lat)) |
|
|
|
const polyOpacity = entityData.data.opacity != null ? entityData.data.opacity : 0 |
|
|
|
const polyWidth = entityData.data.width != null ? entityData.data.width : 4 |
|
|
|
const polyBorderColor = entityData.data.borderColor || color |
|
|
|
entity = this.viewer.entities.add({ |
|
|
|
polygon: { |
|
|
|
hierarchy: polygonPositions, |
|
|
|
material: Cesium.Color.fromCssColorString(color).withAlpha(0.5), |
|
|
|
outline: true, |
|
|
|
outlineColor: Cesium.Color.fromCssColorString(color), |
|
|
|
outlineWidth: 2 |
|
|
|
material: Cesium.Color.fromCssColorString(color).withAlpha(polyOpacity) |
|
|
|
}, |
|
|
|
label: { |
|
|
|
text: entityData.label || '面', |
|
|
|
font: '14px sans-serif', |
|
|
|
fillColor: Cesium.Color.WHITE, |
|
|
|
outlineColor: Cesium.Color.BLACK, |
|
|
|
outlineWidth: 2, |
|
|
|
style: Cesium.LabelStyle.FILL_AND_OUTLINE, |
|
|
|
position: polygonPositions[0] |
|
|
|
polyline: { |
|
|
|
positions: [...polygonPositions, polygonPositions[0]], |
|
|
|
width: polyWidth, |
|
|
|
material: Cesium.Color.fromCssColorString(polyBorderColor), |
|
|
|
arcType: Cesium.ArcType.NONE |
|
|
|
} |
|
|
|
}) |
|
|
|
break |
|
|
|
case 'rectangle': |
|
|
|
const rectCoords = entityData.data.coordinates |
|
|
|
} |
|
|
|
case 'rectangle': { |
|
|
|
let rectCoords = entityData.data.coordinates |
|
|
|
if (!rectCoords && entityData.data.points && entityData.data.points.length >= 2) { |
|
|
|
const lngs = entityData.data.points.map(p => p.lng) |
|
|
|
const lats = entityData.data.points.map(p => p.lat) |
|
|
|
rectCoords = { west: Math.min(...lngs), south: Math.min(...lats), east: Math.max(...lngs), north: Math.max(...lats) } |
|
|
|
} |
|
|
|
if (!rectCoords) break |
|
|
|
const rectOpacity = entityData.data.opacity != null ? entityData.data.opacity : 0 |
|
|
|
const rectWidth = entityData.data.width != null ? entityData.data.width : 4 |
|
|
|
const rectBorderColor = entityData.data.borderColor || color |
|
|
|
const rectColor = Cesium.Color.fromCssColorString(color).withAlpha(rectOpacity) |
|
|
|
const southwest = Cesium.Cartesian3.fromDegrees(rectCoords.west, rectCoords.south) |
|
|
|
const southeast = Cesium.Cartesian3.fromDegrees(rectCoords.east, rectCoords.south) |
|
|
|
const northeast = Cesium.Cartesian3.fromDegrees(rectCoords.east, rectCoords.north) |
|
|
|
const northwest = Cesium.Cartesian3.fromDegrees(rectCoords.west, rectCoords.north) |
|
|
|
const borderPositions = [southwest, southeast, northeast, northwest, southwest] |
|
|
|
entity = this.viewer.entities.add({ |
|
|
|
rectangle: { |
|
|
|
coordinates: Cesium.Rectangle.fromDegrees(rectCoords.west, rectCoords.south, rectCoords.east, rectCoords.north), |
|
|
|
material: Cesium.Color.fromCssColorString(color).withAlpha(0.5), |
|
|
|
outline: true, |
|
|
|
outlineColor: Cesium.Color.fromCssColorString(color), |
|
|
|
outlineWidth: 2 |
|
|
|
material: rectColor |
|
|
|
}, |
|
|
|
label: { |
|
|
|
text: entityData.label || '矩形', |
|
|
|
font: '14px sans-serif', |
|
|
|
fillColor: Cesium.Color.WHITE, |
|
|
|
outlineColor: Cesium.Color.BLACK, |
|
|
|
outlineWidth: 2, |
|
|
|
style: Cesium.LabelStyle.FILL_AND_OUTLINE, |
|
|
|
position: Cesium.Cartesian3.fromDegrees((rectCoords.west + rectCoords.east) / 2, (rectCoords.south + rectCoords.north) / 2) |
|
|
|
polyline: { |
|
|
|
positions: borderPositions, |
|
|
|
width: rectWidth, |
|
|
|
material: Cesium.Color.fromCssColorString(rectBorderColor), |
|
|
|
arcType: Cesium.ArcType.NONE |
|
|
|
} |
|
|
|
}) |
|
|
|
break |
|
|
|
case 'circle': |
|
|
|
// 检查半径是否有效 |
|
|
|
this.allEntities.push({ |
|
|
|
id: entity.id, |
|
|
|
type: 'rectangle', |
|
|
|
points: entityData.data.points || [], |
|
|
|
coordinates: rectCoords, |
|
|
|
entity, |
|
|
|
color, |
|
|
|
borderColor: rectBorderColor, |
|
|
|
opacity: rectOpacity, |
|
|
|
width: rectWidth, |
|
|
|
label: entityData.label || '矩形' |
|
|
|
}) |
|
|
|
return |
|
|
|
} |
|
|
|
case 'circle': { |
|
|
|
const radius = entityData.data.radius || 1000 |
|
|
|
if (radius <= 0) { |
|
|
|
this.$message.error('圆形半径必须大于0') |
|
|
|
return |
|
|
|
} |
|
|
|
const circleCenter = Cesium.Cartesian3.fromDegrees(entityData.data.center.lng, entityData.data.center.lat) |
|
|
|
const circlePositions = this.generateCirclePositions(circleCenter, radius) |
|
|
|
const circleOpacity = entityData.data.opacity != null ? entityData.data.opacity : 0 |
|
|
|
const circleWidth = entityData.data.width != null ? entityData.data.width : 4 |
|
|
|
const circleBorderColor = entityData.data.borderColor || color |
|
|
|
entity = this.viewer.entities.add({ |
|
|
|
position: Cesium.Cartesian3.fromDegrees(entityData.data.center.lng, entityData.data.center.lat), |
|
|
|
position: circleCenter, |
|
|
|
ellipse: { |
|
|
|
semiMinorAxis: radius, |
|
|
|
semiMajorAxis: radius, |
|
|
|
material: Cesium.Color.fromCssColorString(color).withAlpha(0.5), |
|
|
|
outline: true, |
|
|
|
outlineColor: Cesium.Color.fromCssColorString(color), |
|
|
|
outlineWidth: 2 |
|
|
|
semiMinorAxis: radius, |
|
|
|
material: Cesium.Color.fromCssColorString(color).withAlpha(circleOpacity), |
|
|
|
arcType: Cesium.ArcType.NONE |
|
|
|
}, |
|
|
|
label: { |
|
|
|
text: entityData.label || '圆形', |
|
|
|
font: '14px sans-serif', |
|
|
|
fillColor: Cesium.Color.WHITE, |
|
|
|
outlineColor: Cesium.Color.BLACK, |
|
|
|
outlineWidth: 2, |
|
|
|
style: Cesium.LabelStyle.FILL_AND_OUTLINE, |
|
|
|
verticalOrigin: Cesium.VerticalOrigin.BOTTOM, |
|
|
|
pixelOffset: new Cesium.Cartesian2(0, -10) |
|
|
|
polyline: { |
|
|
|
positions: circlePositions, |
|
|
|
width: circleWidth, |
|
|
|
material: Cesium.Color.fromCssColorString(circleBorderColor), |
|
|
|
arcType: Cesium.ArcType.NONE |
|
|
|
} |
|
|
|
}) |
|
|
|
break |
|
|
|
} |
|
|
|
case 'hold_circle': { |
|
|
|
const hcRadius = entityData.data.radius || 1000 |
|
|
|
if (hcRadius <= 0) { |
|
|
|
@ -4999,6 +5172,182 @@ export default { |
|
|
|
}) |
|
|
|
break |
|
|
|
} |
|
|
|
case 'sector': { |
|
|
|
const d = entityData.data |
|
|
|
if (!d || !d.center || d.radius == null) break |
|
|
|
const center = Cesium.Cartesian3.fromDegrees(d.center.lng, d.center.lat) |
|
|
|
const startAngle = d.startAngle != null ? d.startAngle : 0 |
|
|
|
const endAngle = d.endAngle != null ? d.endAngle : Math.PI * 0.5 |
|
|
|
const sectorOpacity = d.opacity != null ? d.opacity : 0 |
|
|
|
const sectorWidth = d.width != null ? d.width : 3 |
|
|
|
const sectorBorderColor = d.borderColor || color |
|
|
|
const positions = this.generateSectorPositions(center, d.radius, startAngle, endAngle) |
|
|
|
entity = this.viewer.entities.add({ |
|
|
|
polygon: { |
|
|
|
hierarchy: new Cesium.PolygonHierarchy(positions), |
|
|
|
material: Cesium.Color.fromCssColorString(color).withAlpha(sectorOpacity) |
|
|
|
}, |
|
|
|
polyline: { |
|
|
|
positions: positions, |
|
|
|
width: sectorWidth, |
|
|
|
material: Cesium.Color.fromCssColorString(sectorBorderColor), |
|
|
|
arcType: Cesium.ArcType.NONE |
|
|
|
} |
|
|
|
}) |
|
|
|
this.allEntities.push({ |
|
|
|
id: entity.id, |
|
|
|
type: 'sector', |
|
|
|
center: d.center, |
|
|
|
radius: d.radius, |
|
|
|
startAngle, |
|
|
|
endAngle, |
|
|
|
positions, |
|
|
|
entity, |
|
|
|
color, |
|
|
|
borderColor: sectorBorderColor, |
|
|
|
opacity: sectorOpacity, |
|
|
|
width: sectorWidth, |
|
|
|
label: entityData.label || '扇形' |
|
|
|
}) |
|
|
|
this.notifyDrawingEntitiesChanged() |
|
|
|
return |
|
|
|
} |
|
|
|
case 'arrow': { |
|
|
|
const pts = entityData.data.points |
|
|
|
if (!pts || pts.length < 2) break |
|
|
|
const arrowPositions = pts.map(p => Cesium.Cartesian3.fromDegrees(p.lng, p.lat)) |
|
|
|
entity = this.viewer.entities.add({ |
|
|
|
polyline: { |
|
|
|
positions: arrowPositions, |
|
|
|
width: 12, |
|
|
|
material: new Cesium.PolylineArrowMaterialProperty(Cesium.Color.fromCssColorString(color)), |
|
|
|
arcType: Cesium.ArcType.NONE, |
|
|
|
widthInMeters: false |
|
|
|
} |
|
|
|
}) |
|
|
|
this.allEntities.push({ |
|
|
|
id: entity.id, |
|
|
|
type: 'arrow', |
|
|
|
points: pts, |
|
|
|
positions: arrowPositions, |
|
|
|
entity, |
|
|
|
color, |
|
|
|
label: entityData.label || '箭头', |
|
|
|
width: entityData.data.width |
|
|
|
}) |
|
|
|
this.notifyDrawingEntitiesChanged() |
|
|
|
return |
|
|
|
} |
|
|
|
case 'text': { |
|
|
|
const td = entityData.data |
|
|
|
if (!td || td.lat == null || td.lng == null) break |
|
|
|
const textPos = Cesium.Cartesian3.fromDegrees(td.lng, td.lat) |
|
|
|
entity = this.viewer.entities.add({ |
|
|
|
position: textPos, |
|
|
|
label: { |
|
|
|
text: td.text != null ? td.text : (entityData.label || '文本'), |
|
|
|
font: td.font || this.defaultStyles.text.font, |
|
|
|
fillColor: Cesium.Color.fromCssColorString(color), |
|
|
|
outlineColor: Cesium.Color.fromCssColorString('#e5e5e5'), |
|
|
|
outlineWidth: 1, |
|
|
|
style: Cesium.LabelStyle.FILL_AND_OUTLINE, |
|
|
|
verticalOrigin: Cesium.VerticalOrigin.CENTER, |
|
|
|
horizontalOrigin: Cesium.HorizontalOrigin.CENTER, |
|
|
|
backgroundColor: td.backgroundColor ? Cesium.Color.fromCssColorString(td.backgroundColor) : Cesium.Color.fromCssColorString(this.defaultStyles.text.backgroundColor), |
|
|
|
backgroundPadding: new Cesium.Cartesian2(8, 5), |
|
|
|
scaleByDistance: new Cesium.NearFarScalar(200, 1.12, 1200000, 0.72), |
|
|
|
translucencyByDistance: new Cesium.NearFarScalar(300, 1.0, 600000, 0.88) |
|
|
|
} |
|
|
|
}) |
|
|
|
this.allEntities.push({ |
|
|
|
id: entity.id, |
|
|
|
type: 'text', |
|
|
|
lat: td.lat, |
|
|
|
lng: td.lng, |
|
|
|
text: td.text, |
|
|
|
position: textPos, |
|
|
|
entity, |
|
|
|
color, |
|
|
|
font: td.font, |
|
|
|
backgroundColor: td.backgroundColor, |
|
|
|
label: entityData.label || '文本' |
|
|
|
}) |
|
|
|
this.notifyDrawingEntitiesChanged() |
|
|
|
return |
|
|
|
} |
|
|
|
case 'image': { |
|
|
|
const imgData = entityData.data |
|
|
|
if (!imgData || imgData.lat == null || imgData.lng == null || !imgData.imageUrl) break |
|
|
|
const imgPos = Cesium.Cartesian3.fromDegrees(imgData.lng, imgData.lat) |
|
|
|
entity = this.viewer.entities.add({ |
|
|
|
position: imgPos, |
|
|
|
billboard: { |
|
|
|
image: imgData.imageUrl, |
|
|
|
width: imgData.width != null ? imgData.width : this.defaultStyles.image.width, |
|
|
|
height: imgData.height != null ? imgData.height : this.defaultStyles.image.height, |
|
|
|
verticalOrigin: Cesium.VerticalOrigin.CENTER, |
|
|
|
horizontalOrigin: Cesium.HorizontalOrigin.CENTER, |
|
|
|
scaleByDistance: new Cesium.NearFarScalar(200, 1.12, 1200000, 0.72), |
|
|
|
translucencyByDistance: new Cesium.NearFarScalar(300, 1.0, 600000, 0.88) |
|
|
|
} |
|
|
|
}) |
|
|
|
this.allEntities.push({ |
|
|
|
id: entity.id, |
|
|
|
type: 'image', |
|
|
|
lat: imgData.lat, |
|
|
|
lng: imgData.lng, |
|
|
|
imageUrl: imgData.imageUrl, |
|
|
|
position: imgPos, |
|
|
|
entity, |
|
|
|
width: imgData.width, |
|
|
|
height: imgData.height, |
|
|
|
label: entityData.label || '图片' |
|
|
|
}) |
|
|
|
this.notifyDrawingEntitiesChanged() |
|
|
|
return |
|
|
|
} |
|
|
|
case 'powerZone': { |
|
|
|
const pd = entityData.data |
|
|
|
if (!pd || !pd.center || pd.radius == null) break |
|
|
|
const pzCenter = Cesium.Cartesian3.fromDegrees(pd.center.lng, pd.center.lat) |
|
|
|
const pzRadius = Math.max(1, pd.radius) |
|
|
|
const circlePositions = this.generateCirclePositions(pzCenter, pzRadius) |
|
|
|
entity = this.viewer.entities.add({ |
|
|
|
polygon: { |
|
|
|
hierarchy: new Cesium.PolygonHierarchy(circlePositions), |
|
|
|
material: Cesium.Color.TRANSPARENT, |
|
|
|
outline: true, |
|
|
|
outlineColor: Cesium.Color.fromCssColorString(pd.color || '#FF0000'), |
|
|
|
outlineWidth: (pd.width != null ? pd.width : 2) |
|
|
|
}, |
|
|
|
polyline: { |
|
|
|
positions: circlePositions, |
|
|
|
width: 2, |
|
|
|
material: Cesium.Color.RED, |
|
|
|
arcType: Cesium.ArcType.NONE |
|
|
|
} |
|
|
|
}) |
|
|
|
const centerEntity = this.viewer.entities.add({ |
|
|
|
position: pzCenter, |
|
|
|
point: { pixelSize: 8, color: Cesium.Color.RED, outlineColor: Cesium.Color.WHITE, outlineWidth: 2 }, |
|
|
|
label: { text: pd.name || '威力区', font: '14px sans-serif', fillColor: Cesium.Color.WHITE, outlineColor: Cesium.Color.BLACK, outlineWidth: 2, style: Cesium.LabelStyle.FILL_AND_OUTLINE, verticalOrigin: Cesium.VerticalOrigin.BOTTOM, pixelOffset: new Cesium.Cartesian2(0, -12) } |
|
|
|
}) |
|
|
|
this.allEntities.push({ |
|
|
|
id: entity.id, |
|
|
|
type: 'powerZone', |
|
|
|
entity, |
|
|
|
centerEntity, |
|
|
|
center: pd.center, |
|
|
|
radius: pzRadius, |
|
|
|
name: pd.name, |
|
|
|
color: pd.color || '#FF0000', |
|
|
|
opacity: pd.opacity, |
|
|
|
borderColor: pd.borderColor, |
|
|
|
width: pd.width |
|
|
|
}) |
|
|
|
this.notifyDrawingEntitiesChanged() |
|
|
|
return |
|
|
|
} |
|
|
|
} |
|
|
|
if (entity) { |
|
|
|
this.allEntities.push({ |
|
|
|
@ -5006,8 +5355,10 @@ export default { |
|
|
|
type: entityData.type, |
|
|
|
label: entityData.label, |
|
|
|
color: color, |
|
|
|
entity, |
|
|
|
...entityData.data |
|
|
|
}) |
|
|
|
if (this.getDrawingEntityTypes().includes(entityData.type)) this.notifyDrawingEntitiesChanged() |
|
|
|
} |
|
|
|
}, |
|
|
|
handleLocate() { |
|
|
|
@ -5515,6 +5866,7 @@ export default { |
|
|
|
borderColor: '#FF0000', |
|
|
|
width: 2 |
|
|
|
}); |
|
|
|
this.notifyDrawingEntitiesChanged(); |
|
|
|
|
|
|
|
if (this.powerZoneCenterEntity && this.powerZoneCenterEntity.label) { |
|
|
|
this.powerZoneCenterEntity.label.text = radiusData.name; |
|
|
|
|