diff --git a/src/views/residentAnalysis/index.vue b/src/views/residentAnalysis/index.vue
index 87af492..59c63ba 100644
--- a/src/views/residentAnalysis/index.vue
+++ b/src/views/residentAnalysis/index.vue
@@ -21,10 +21,10 @@
@@ -232,12 +232,8 @@ export default {
],
form: {
- leftTop: '',
- rightBottom: '',
- DEM: '',
- peopleGeoJson: '',
- soilGeoJson: '',
- plantGeoJson: '',
+ leftTop: '114.33,27.8',
+ rightBottom: '114.34, 27.79',
slopePer: 0.5,
peoplePer: 0.2,
plantPer: 0.2,
@@ -252,13 +248,6 @@ export default {
selectedRect: null,
rectangles: [],
- // 示例区域:矩形四个角点(经纬度)
- positions: [
- [114.33, 27.79],
- [114.34, 27.79],
- [114.34, 27.8],
- [114.33, 27.8],
- ],
peopleGeo: null,
plantGeo: null,
soilGeo: null,
@@ -273,11 +262,36 @@ export default {
_polyCache: null,
validBlocks: [],
colorList: [],
+ roadWaterLock: false,
}
},
created() {
this._polyCache = new WeakMap()
},
+
+ computed: {
+ // 示例区域:矩形四个角点
+ positions() {
+ let a = this.form.leftTop.split(',')
+ let b = this.form.rightBottom.split(',')
+ return [
+ [a[0], b[1]],
+ [b[0], b[1]],
+ [b[0], a[1]],
+ [a[0], a[1]],
+ ]
+ },
+ },
+
+ watch: {
+ positions: {
+ deep: true,
+ handler(val) {
+ this.drawInitialArea(val)
+ },
+ },
+ },
+
mounted() {
this.getMapJson()
this.getColorList()
@@ -335,50 +349,45 @@ export default {
loadGeoJson() {
// 延迟加载,按需显示
this.layers = {
- people: this.createLayerConfig('./config/people.geojson', '#ff000033'),
- plant: this.createLayerConfig('./config/plant.geojson', '#00ff0033'),
- soil: this.createLayerConfig('./config/soil.geojson', '#0000ff33'),
+ people: this.createLayerConfig('./config/people.geojson', '#ff0000'),
+ plant: this.createLayerConfig('./config/plant.geojson', '#00ff00'),
+ soil: this.createLayerConfig('./config/soil.geojson', '#0000ff'),
roadPoint: this.createLayerConfig(
'./config/road_points.geojson',
- '#ff0ff022'
+ '#ff0ff0',
+ 'point'
),
roadLine: this.createLayerConfig(
'./config/road_lines.geojson',
- '#ff0ff022'
+ '#ff0ff0',
+ 'polyline'
),
waterPoint: this.createLayerConfig(
'./config/water_points.geojson',
- '#ff0ff022'
+ '#ff0ff0',
+ 'point'
),
waterLine: this.createLayerConfig(
'./config/water_lines.geojson',
- '#ff0ff022'
+ '#ff0ff0',
+ 'polyline'
),
}
// 默认只加载一个,其他按需加载
- this.loadLayer('people')
- this.loadLayer('plant')
- this.loadLayer('soil')
+ this.loadLayers(['people', 'plant', 'soil'], (results) => {
+ console.log('所有图层加载完成', results)
+ })
+ // this.loadLayer('people')
},
- createLayerConfig(url, color) {
- return {
+ createLayerConfig(url, color, type = 'polygon') {
+ const baseConfig = {
layer: null,
config: {
url: url,
crs: 'EPSG:4326',
flyTo: true, // 关闭自动飞行
- symbol: {
- type: 'polygon',
- styleOptions: {
- color: Cesium.Color.fromCssColorString(color),
- opacity: 0.3,
- outline: false,
- // outlineColor: color,
- // outlineWidth: 1,
- },
- },
// 视域裁剪,只显示视野内的要素
cull: {
enabled: true,
@@ -391,6 +400,53 @@ export default {
},
},
}
+
+ // 根据不同类型设置不同的符号样式
+ switch (type) {
+ case 'point':
+ baseConfig.config.symbol = {
+ type: 'point',
+ styleOptions: {
+ color: Cesium.Color.fromCssColorString(color),
+ pixelSize: 8,
+ outlineColor: Cesium.Color.WHITE,
+ outlineWidth: 1,
+ scaleByDistance: new Cesium.NearFarScalar(1.5e2, 1.0, 1.5e6, 0.5),
+ heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
+ },
+ }
+ break
+
+ case 'polyline':
+ baseConfig.config.symbol = {
+ type: 'polyline',
+ styleOptions: {
+ color: Cesium.Color.fromCssColorString(color),
+ width: 3,
+ opacity: 0.8,
+ clampToGround: true,
+ },
+ }
+ break
+
+ case 'polygon':
+ default:
+ baseConfig.config.symbol = {
+ type: 'polygon',
+ styleOptions: {
+ color: Cesium.Color.fromCssColorString(color),
+ opacity: 0.3,
+ outline: false,
+ // 如果需要轮廓线可以取消注释
+ // outlineColor: color,
+ // outlineWidth: 1,
+ clampToGround: true, // 贴地显示
+ },
+ }
+ break
+ }
+
+ return baseConfig
},
async loadLayer(layerName) {
@@ -406,6 +462,33 @@ export default {
await window.viewer.addLayer(this.layers[layerName].layer)
},
+ // 新增方法:同时加载多个图层
+ async loadLayers(names = [], cb) {
+ const tasks = names.map((name) => {
+ const cfg = this.layers[name]
+ if (!cfg) return Promise.resolve(null) // 无配置直接过
+
+ // 已经加载过:只切换可见性
+ if (cfg.layer) {
+ cfg.layer.show = true
+ return Promise.resolve(cfg.layer)
+ }
+
+ // 首次加载
+ return new Promise((resolve) => {
+ const layer = new mars3d.layer.GeoJsonLayer(cfg.config)
+ layer.once(mars3d.EventType.load, () => resolve(layer))
+ window.viewer.addLayer(layer)
+ cfg.layer = layer // 缓存
+ })
+ })
+
+ return Promise.all(tasks).then((loadedLayers) => {
+ if (cb) cb(loadedLayers.filter(Boolean)) // 过滤空值
+ return loadedLayers.filter(Boolean)
+ })
+ },
+
// 算矩形到 geoJSONLayer 的最小距离(米),判断是否在其内部
calcMinDistance(rectPositions, geoJSONLayer) {
if (!geoJSONLayer || !rectPositions?.length) return Infinity
@@ -461,7 +544,8 @@ export default {
},
// 判断矩形与 mars3d GeoJSON 图层是否相交(不转 GeoJSON)
- getIntersectId(position, layer) {
+ getIntersectId(position, layer, bufferDistance = 0.001) {
+ console.log('position===>', position, layer)
if (!position || !layer || !layer.graphics) return null
const rectCoords = position.concat([position[0]]) // 闭合
@@ -469,64 +553,157 @@ export default {
const [minX, minY, maxX, maxY] = turf.bbox(rectPoly) // 矩形 bbox
let fc = this._polyCache.get(layer)
+
if (!fc) {
const features = []
layer.graphics.forEach((g) => {
- if (g.type !== 'polygonP') return // 只关心面
- const coords = g.positions.map((p) => {
- const carto = Cesium.Cartographic.fromCartesian(p)
- return [
+ // 处理面要素
+ if (g.type === 'polygon') {
+ const coords = g.positions.map((p) => {
+ const carto = Cesium.Cartographic.fromCartesian(p)
+ return [
+ Cesium.Math.toDegrees(carto.longitude),
+ Cesium.Math.toDegrees(carto.latitude),
+ ]
+ })
+ coords.push(coords[0]) // 闭合
+ features.push({
+ type: 'Feature',
+ geometry: {type: 'Polygon', coordinates: [coords]},
+ properties: {id: g.attr?.id ?? g.id},
+ })
+ }
+ // 处理线要素
+ else if (g.type === 'polyline') {
+ const coords = g.positions.map((p) => {
+ const carto = Cesium.Cartographic.fromCartesian(p)
+ return [
+ Cesium.Math.toDegrees(carto.longitude),
+ Cesium.Math.toDegrees(carto.latitude),
+ ]
+ })
+ features.push({
+ type: 'Feature',
+ geometry: {type: 'LineString', coordinates: coords},
+ properties: {id: g.attr?.id ?? g.id},
+ })
+ }
+ // 处理点要素
+ else if (g.type === 'point') {
+ const carto = Cesium.Cartographic.fromCartesian(g.position)
+ const coord = [
Cesium.Math.toDegrees(carto.longitude),
Cesium.Math.toDegrees(carto.latitude),
]
- })
- coords.push(coords[0]) // 闭合
- features.push({
- type: 'Feature',
- geometry: {type: 'Polygon', coordinates: [coords]},
- properties: {id: g.attr?.id ?? g.id}, // 挂 id
- })
+ features.push({
+ type: 'Feature',
+ geometry: {type: 'Point', coordinates: coord},
+ properties: {id: g.attr?.id ?? g.id},
+ })
+ }
})
+
fc = turf.featureCollection(features)
this._polyCache.set(layer, fc)
}
+ // 先进行边界框筛选
const candidates = fc.features.filter((f) => {
const [fminX, fminY, fmaxX, fmaxY] = turf.bbox(f)
return !(fmaxX < minX || fminX > maxX || fmaxY < minY || fminY > maxY)
})
+ // 精确相交检测
for (const f of candidates) {
- if (turf.booleanIntersects(rectPoly, f)) return String(f.properties.id)
+ let isIntersect = false
+
+ // 根据几何类型使用不同的相交检测方法
+ if (f.geometry.type === 'Polygon') {
+ isIntersect = turf.booleanIntersects(rectPoly, f)
+ } else if (f.geometry.type === 'LineString') {
+ // 线与面的相交检测
+ isIntersect = turf.booleanIntersects(rectPoly, f)
+ } else if (f.geometry.type === 'Point') {
+ // 点与面的包含检测
+ isIntersect = turf.booleanPointInPolygon(f, rectPoly)
+ }
+
+ if (isIntersect) return String(f.properties.id)
}
+
return null
},
- // 绘制矩形区域
- drawInitialArea() {
- const polygon = new mars3d.graphic.PolygonEntity({
- positions: this.positions.map((p) =>
- Cesium.Cartesian3.fromDegrees(p[0], p[1], 100)
- ),
+ // 手动绘制矩形
+ async drawRectangle(clampToGround) {
+ const graphic = await window.graphicLayer.startDraw({
+ type: isEntityGraphic ? 'rectangle' : 'rectangleP',
style: {
- color: '#00ff00',
- opacity: 0.3,
+ color: clampToGround ? '#ffff00' : '#3388ff',
+ opacity: 0.6,
outline: true,
outlineColor: '#ffffff',
- outlineWidth: 2,
- },
- label: {
- text: '分析区域',
- font: '16px sans-serif',
- color: '#ffffff',
- outline: true,
- outlineColor: '#000000',
- outlineWidth: 2,
- pixelOffset: new Cesium.Cartesian2(0, -40),
+ outlineWidth: 2.0,
+ clampToGround,
},
})
- window.graphicLayer.addGraphic(polygon)
+ console.log('标绘完成', graphic.toJSON())
+ },
+
+ // 绘制矩形区域
+ drawInitialArea(val) {
+ // 如果多边形尚未创建,则创建它
+ if (!this.polygon) {
+ this.polygon = new mars3d.graphic.PolygonEntity({
+ positions: this.positions.map((p) =>
+ Cesium.Cartesian3.fromDegrees(p[0], p[1], 0)
+ ),
+ style: {
+ color: '#00ff00',
+ opacity: 0.3,
+ outline: true,
+ outlineColor: '#ffffff',
+ outlineWidth: 2,
+ },
+ label: {
+ text: '分析区域',
+ font: '16px sans-serif',
+ color: '#ffffff',
+ outline: true,
+ outlineColor: '#000000',
+ outlineWidth: 2,
+ pixelOffset: new Cesium.Cartesian2(0, -40),
+ },
+ })
+
+ console.log(' this.polygon===>', this.polygon)
+
+ window.graphicLayer.addGraphic(this.polygon)
+ this.isInitialized = true
+ } else {
+ // 如果多边形已存在,则更新它的位置
+ this.updateArea(val)
+ }
+ },
+
+ updateArea(val) {
+ if (!this.polygon) return
+
+ // 将经纬度转换为笛卡尔坐标
+ const cartesianPositions = val.map((p) =>
+ Cesium.Cartesian3.fromDegrees(p[0], p[1], 0)
+ )
+
+ // 更新多边形位置
+ this.polygon.positions = cartesianPositions
+
+ // 触发更新(根据mars3d的具体API可能需要调用其他方法)
+ if (this.polygon.update) {
+ this.polygon.update()
+ }
+
+ console.log('区域已更新', val)
},
// 分析平均坡度
@@ -699,14 +876,27 @@ export default {
outline: true,
outlineColor: '#ffffff',
outlineWidth: 1,
+ // 关键设置:启用填充并设置填充颜色
+ fill: true,
+ material: color, // 使用相同的颜色作为填充材质
+ // 提高填充的优先级,确保可以点击
+ classificationType: Cesium.ClassificationType.BOTH,
},
- center: new mars3d.LngLatPoint(b.center[0], b.center[1], 100),
+ center: new mars3d.LngLatPoint(b.center[0], b.center[1], 0),
+ // 添加自定义属性,用于事件识别
+ attr: {
+ isRectangle: true,
+ originalData: b,
+ },
+ // 关键设置:启用深度测试和拾取
+ depthTestAgainstTerrain: false, // 禁用地形深度测试
+ allowPicking: true, // 确保允许拾取
})
/* 2.2 标签 options */
labelOpts.push({
id: `label_${b.id}`,
- position: new mars3d.LngLatPoint(b.center[0], b.center[1], 100),
+ position: new mars3d.LngLatPoint(b.center[0], b.center[1], 0),
style: {
text: String(b.totalScore), // 必须字符串
font_size: 24,
@@ -717,6 +907,13 @@ export default {
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
visibleDepth: false,
scaleByDistance: true,
+ // 禁用标签的拾取,让点击事件穿透到矩形
+ disablePicking: true, // 关键设置
+ },
+ // 添加自定义属性,用于事件识别
+ attr: {
+ isLabel: true,
+ relatedRectId: b.id,
},
})
}
@@ -733,18 +930,26 @@ export default {
window.graphicLayer.addGraphic(rectGraphics)
window.graphicLayer.addGraphic(labelGraphics)
- /* 5. 图层级事件委托:只监听一次 */
- window.graphicLayer.off(mars3d.EventType.click, _selectRect, this) // 先清旧监听
- window.graphicLayer.on(mars3d.EventType.click, _selectRect, this)
+ /* 5. 图层级事件委托:只监听矩形图形的点击事件 */
+ window.graphicLayer.off(mars3d.EventType.click, this._selectRect, this) // 先清旧监听
+
+ // 为每个矩形图形单独绑定点击事件
+ rectGraphics.forEach((rectGraphic) => {
+ rectGraphic.on(mars3d.EventType.click, (event) => {
+ this._selectRect(event)
+ })
+ })
/* 6. 保存引用 */
this.rectangles = rectGraphics
+ this.labels = labelGraphics
/* 7. 事件处理函数 */
- function _selectRect(e) {
- const graphic = e.graphic
- if (graphic && graphic.attr) {
- this.selectRectangle(graphic) // 你的原逻辑
+ this._selectRect = (event) => {
+ const graphic = event.graphic
+ // 确保只有矩形图形会触发选择
+ if (graphic && graphic.attr && graphic.attr.isRectangle) {
+ this.selectRectangle(graphic)
}
}
},
@@ -848,52 +1053,59 @@ export default {
// 选择矩形
selectRectangle(rect) {
console.log('rect===>', rect)
-
+ if (this.selectedRect?.id === rect.id) return
this.selectedRect = {
id: rect.id,
center: rect.center,
}
-
- if (
- !this.roadPointGeo ||
- !this.roadLineGeo ||
- !this.waterPointGeo ||
- !this.waterLineGeo
- ) {
+ if (!this.roadPointGeo) {
this.loadLayer('roadPoint')
+ } else if (!this.roadLineGeo) {
this.loadLayer('roadLine')
+ } else if (!this.waterPointGeo) {
this.loadLayer('waterPoint')
+ } else if (!this.waterLineGeo) {
this.loadLayer('waterLine')
}
- // 关闭之前的Popup(如果存在)
- if (this.selectedPopup) {
- this.selectedPopup.remove()
+ if (!this.roadWaterLock) {
+ this.loadLayers(
+ ['roadPoint', 'roadLine', 'waterPoint', 'waterLine'],
+ (results) => {
+ this.roadWaterLock = true
+ this.getRoadWaterIds(rect)
+ }
+ )
+ } else {
+ this.getRoadWaterIds(rect)
}
+ },
- const cartographic = Cesium.Cartographic.fromCartesian(rect.center)
- const positionArray = [
- Cesium.Math.toDegrees(cartographic.longitude),
- Cesium.Math.toDegrees(cartographic.latitude),
- 10,
- ]
+ getRoadWaterIds(rect) {
+ let roadPointId = this.getIntersectId(
+ rect.points,
+ this.layers['roadPoint'].layer
+ )
+ let roadLineId = this.getIntersectId(
+ rect.points,
+ this.layers['roadLine'].layer
+ )
+ let waterPointId = this.getIntersectId(
+ rect.points,
+ this.layers['waterPoint'].layer
+ )
+ let waterLineId = this.getIntersectId(
+ rect.points,
+ this.layers['waterLine'].layer
+ )
- // 创建新的Popup
- this.selectedPopup = new mars3d.graphic.DivGraphic({
- position: positionArray,
- style: {
- html: `id:${rect.id}
平均坡度:${rect.attr.slope}
`,
- offsetY: -60,
- horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
- verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
- distanceDisplayCondition: new Cesium.DistanceDisplayCondition(
- 0,
- 400000
- ), // 按视距距离显示
- },
- })
-
- window.graphicLayer.addGraphic(this.selectedPopup)
+ console.log(
+ 'roadPointId===>',
+ roadPointId,
+ roadLineId,
+ waterPointId,
+ waterLineId
+ )
},
// 清除所有矩形