diff --git a/src/api/gisManagement/configStyle.js b/src/api/gisManagement/configStyle.js new file mode 100644 index 0000000..2870af0 --- /dev/null +++ b/src/api/gisManagement/configStyle.js @@ -0,0 +1,85 @@ +import request from '@/utils/request' +import { parseStrEmpty } from "@/utils/ruoyi"; +import { createUniqueString } from "@/utils/index"; + +const tempTypeList = [ + { value: 'point', label: '点' }, + { value: 'polyline', label: '线' }, + { value: 'polygon', label: '面' }, + { value: 'billboard', label: '图标' }, + { value: 'label', label: '标签' }, +] +const tempList = [] + +// 查询样式类型信息 +export function getStyleType() { + return Promise.resolve(tempTypeList) +} + +// 查询样式列表 +export function listStyle(query) { + const list = tempList.filter(item => { + if(query.styleName && item.styleName.indexOf(query.styleName) === -1) { + return false + } + if(query.styleType && item.styleType.indexOf(query.styleType) === -1) { + return false + } + return true + }) + return Promise.resolve({ + rows: list, + total: list.length, + }) +} + +// 查询样式详细 +export function getStyle(styleId) { + return Promise.resolve({ + data: tempList.find(item => item.id === parseStrEmpty(styleId)) + }) +} + +// 新增样式 +export function addStyle(data) { + data.id = createUniqueString() + tempList.push(data) + return Promise.resolve({ + code: 200, + msg: '新增成功', + data: data + }) +} + +// 修改样式 +export function updateStyle(data) { + for (const v of tempList) { + if (v.id === data.id) { + v.styleName = data.styleName + v.styleType = data.styleType + v.style = data.style + break + } + } + return Promise.resolve({ + code: 200, + msg: '修改成功', + }) +} + +// 删除样式 +export function delStyle(styleId) { + let idList = styleId + if(typeof styleId === 'string') { + idList = [styleId] + } + for (let index = tempList.length - 1; index >= 0; index--) { + if(idList.includes(tempList[index].id)) { + tempList.splice(index, 1) + } + } + return Promise.resolve({ + code: 200, + msg: '删除成功', + }) +} \ No newline at end of file diff --git a/src/assets/icons/example/analysis_around.png b/src/assets/icons/example/analysis_around.png new file mode 100644 index 0000000..38feaef Binary files /dev/null and b/src/assets/icons/example/analysis_around.png differ diff --git a/src/assets/icons/example/analysis_coordination_location.png b/src/assets/icons/example/analysis_coordination_location.png new file mode 100644 index 0000000..b7cdf38 Binary files /dev/null and b/src/assets/icons/example/analysis_coordination_location.png differ diff --git a/src/assets/icons/example/analysis_map_location.png b/src/assets/icons/example/analysis_map_location.png new file mode 100644 index 0000000..b44f42e Binary files /dev/null and b/src/assets/icons/example/analysis_map_location.png differ diff --git a/src/assets/icons/example/analysis_sandbox.png b/src/assets/icons/example/analysis_sandbox.png new file mode 100644 index 0000000..0e6d138 Binary files /dev/null and b/src/assets/icons/example/analysis_sandbox.png differ diff --git a/src/assets/icons/example/analysis_spread.png b/src/assets/icons/example/analysis_spread.png new file mode 100644 index 0000000..4c11880 Binary files /dev/null and b/src/assets/icons/example/analysis_spread.png differ diff --git a/src/assets/icons/example/check_point.png b/src/assets/icons/example/check_point.png new file mode 100644 index 0000000..312d146 Binary files /dev/null and b/src/assets/icons/example/check_point.png differ diff --git a/src/assets/icons/example/sandbox_explosive.png b/src/assets/icons/example/sandbox_explosive.png new file mode 100644 index 0000000..c888707 Binary files /dev/null and b/src/assets/icons/example/sandbox_explosive.png differ diff --git a/src/assets/icons/example/sandbox_fire.png b/src/assets/icons/example/sandbox_fire.png new file mode 100644 index 0000000..467cf16 Binary files /dev/null and b/src/assets/icons/example/sandbox_fire.png differ diff --git a/src/assets/icons/example/sandbox_firefighter.png b/src/assets/icons/example/sandbox_firefighter.png new file mode 100644 index 0000000..95e05e1 Binary files /dev/null and b/src/assets/icons/example/sandbox_firefighter.png differ diff --git a/src/assets/icons/example/sandbox_firepoint.png b/src/assets/icons/example/sandbox_firepoint.png new file mode 100644 index 0000000..9ee985c Binary files /dev/null and b/src/assets/icons/example/sandbox_firepoint.png differ diff --git a/src/assets/icons/example/sandbox_flame.png b/src/assets/icons/example/sandbox_flame.png new file mode 100644 index 0000000..182b606 Binary files /dev/null and b/src/assets/icons/example/sandbox_flame.png differ diff --git a/src/assets/icons/example/sandbox_trapped.png b/src/assets/icons/example/sandbox_trapped.png new file mode 100644 index 0000000..7ec3f36 Binary files /dev/null and b/src/assets/icons/example/sandbox_trapped.png differ diff --git a/src/assets/icons/example/sandbox_water.png b/src/assets/icons/example/sandbox_water.png new file mode 100644 index 0000000..29a493f Binary files /dev/null and b/src/assets/icons/example/sandbox_water.png differ diff --git a/src/components/CesiumMap/index.vue b/src/components/CesiumMap/index.vue index da6368a..9306a77 100644 --- a/src/components/CesiumMap/index.vue +++ b/src/components/CesiumMap/index.vue @@ -16,6 +16,7 @@ const props = defineProps({ } } }) +const emits = defineEmits(['init']) let viewer = null; @@ -91,6 +92,8 @@ const initMap = async () => { // 取消左键双击 viewer.cesiumWidget.screenSpaceEventHandler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK); + + emits('init', viewer); } // 设置初始值 @@ -177,6 +180,10 @@ const mapSetView = (options) => { // 设置模型 const setModel = async (options) => { + if (!options.modelList || options.modelList.length === 0) { + return; + } + // 3d模型参数 const tilesetOption = { maximumScreenSpaceError: 1, // 应对大疆一键生成的模型问题;如模型能正常显示但文件加载太过频繁,可增大数值 diff --git a/src/components/CesiumMap/utils/calcFn.js b/src/components/CesiumMap/utils/calcFn.js new file mode 100644 index 0000000..edec970 --- /dev/null +++ b/src/components/CesiumMap/utils/calcFn.js @@ -0,0 +1,32 @@ +import * as Cesium from "cesium"; + +const getCenterPosition = (positions) => { + if(positions.length === 0) { + console.warn("positions is empty"); + return Cesium.Cartesian3.ZERO; + } + + let maxX = Cesium.Math.toRadians(-180), + minX = Cesium.Math.toRadians(180); + let maxY = Cesium.Math.toRadians(-90), + minY = Cesium.Math.toRadians(90); + + for (let i = 0; i < positions.length; i++) { + const cartographic = Cesium.Cartographic.fromCartesian(positions[i]); + if (cartographic.longitude < minX) { + minX = cartographic.longitude; + } else if (cartographic.longitude > maxX) { + maxX = cartographic.longitude; + } + if (cartographic.latitude < minY) { + minY = cartographic.latitude; + } else if (cartographic.latitude > maxY) { + maxY = cartographic.latitude; + } + } + return Cesium.Cartesian3.fromRadians((minX + maxX) / 2, (minY + maxY) / 2) +}; + +export { + getCenterPosition +} diff --git a/src/components/CesiumMap/utils/layerFn.js b/src/components/CesiumMap/utils/layerFn.js new file mode 100644 index 0000000..6b451cb --- /dev/null +++ b/src/components/CesiumMap/utils/layerFn.js @@ -0,0 +1,167 @@ +import * as Cesium from "cesium"; +import { getCenterPosition } from "./calcFn"; + +const createFeature = (style, position, text, layer) => { + if (!style) { + return null; + } + + switch (style.properties?.type) { + case "point": + case "billboard": + case "label": + return createPointFeature(style, position, text, layer); + case "polyline": + return createPolylineFeature(style, position, text, layer); + case "polygon": + return createPolygonFeature(style, position, text, layer); + default: + return null; + } +}; + +/** + * 生成点要素 + * 目前图标、标签没有额外操作,故共享该方法 + * @param {Object} style 处理后的样式对象 + * @param {Cesium.Cartesian3} position 点位置 + * @param {String} text 标签文本,可选 + * @param {Cesium.DataSource} layer 图层 + * @returns {Cesium.Entity} 点对象 + */ +const createPointFeature = (style, position, text, layer) => { + if (!position) { + return null; + } + + const entity = new Cesium.Entity({ + position: position, + ...cloneStyle(style), + }); + // 添加标签文本 + // if(text !== null && text !== undefined) { + // if(Cesium.defined(entity.label)) { + // entity.label.text = new Cesium.ConstantProperty(text) + // } else { + // entity.label = new Cesium.LabelGraphics({ + // text, + // font: '16px sans-serif', + // }) + // } + // } + if (Cesium.defined(entity.label) && text !== null && text !== undefined) { + entity.label.text = new Cesium.ConstantProperty(text); + } + // 加入图层 + if (layer) { + layer.entities.add(entity); + } + return entity; +}; + +/** + * 生成线要素 + * @param {Object} style 处理后的样式对象 + * @param {Array} position 位置数组 + * @param {String} text 标签文本,可选 + * @param {Cesium.DataSource} layer 图层 + * @returns {Cesium.Entity} 线对象 + */ +const createPolylineFeature = (style, position, text, layer) => { + if (!position || position.length < 2) { + return null; + } + + const entity = new Cesium.Entity(cloneStyle(style)); + // 添加线坐标 + if (Cesium.defined(style.polyline)) { + entity.polyline.positions = new Cesium.ConstantProperty( + style.properties.closed ? [...position, position[0]] : position + ); + } else { + entity.polyline = new Cesium.PolylineGraphics({ + positions: position, + }); + } + // 添加标签文本 + if (Cesium.defined(entity.label) && text !== null && text !== undefined) { + entity.label.text = new Cesium.ConstantProperty(text) + // 添加label坐标 + entity.position = getCenterPosition(position) + } + // 加入图层 + if (layer) { + layer.entities.add(entity); + } + return entity; +}; + +/** + * 生成面要素 + * @param {Object} style 处理后的样式对象 + * @param {Array} position 位置数组 + * @param {String} text 标签文本,可选 + * @param {Cesium.DataSource} layer 图层 + * @returns {Cesium.Entity} 面对象 + */ +const createPolygonFeature = (style, position, text, layer) => { + if (!position || position.length < 3) { + return null; + } + + const entity = new Cesium.Entity(cloneStyle(style)); + // 添加面坐标 + if (Cesium.defined(style.polygon)) { + entity.polygon.hierarchy = new Cesium.PolygonHierarchy(position); + } else { + entity.polyline = new Cesium.PolygonGraphics({ + hierarchy: new Cesium.PolygonHierarchy(position), + }); + } + // 添加轮廓线坐标 + // 这里消极的判断,仅当存在polyline时才添加,且必定是闭合线 + if (Cesium.defined(style.polyline)) { + entity.polyline.positions = new Cesium.ConstantProperty([ + ...position, + position[0], + ]); + } + // 添加标签文本 + if (Cesium.defined(entity.label) && text !== null && text !== undefined) { + entity.label.text = new Cesium.ConstantProperty(text) + // 添加label坐标 + entity.position = getCenterPosition(position) + } + // 加入图层 + if (layer) { + layer.entities.add(entity) + } + return entity; +}; + +const cloneStyle = (style) => { + const clone = {}; + for (let key in style) { + console.log(key); + if (key === "id") { + clone[key] = style[key]; + } else if (key === "properties") { + // 浅拷贝属性 + clone[key] = {}; + for (let prop in style[key]) { + clone[key][prop] = style[key][prop]; + } + } else { + // 用cesium提供方法拷贝 + clone[key] = style[key].clone(); + } + } + return clone; +}; + +export { + createFeature, + createPointFeature, + createPolylineFeature, + createPolygonFeature, +}; diff --git a/src/components/CesiumMap/utils/styleFn.js b/src/components/CesiumMap/utils/styleFn.js new file mode 100644 index 0000000..28fcdcb --- /dev/null +++ b/src/components/CesiumMap/utils/styleFn.js @@ -0,0 +1,330 @@ +import * as Cesium from 'cesium'; + +let _clampToGround = false; + +const getStyle = (options) => { + // 将配置项转为cesium内部类,提供复用 + const _options = {} + // 判断类型(option提供了则套用,未提供测推断) + if(options.type) { + _options.type = options.type + } else if(options.point) { + _options.type = 'point' + } else if(options.polygon) { + _options.type = 'polygon' + } else if(options.polyline) { + _options.type = 'polyline' + } else if(options.billboard) { + _options.type = 'billboard' + } else if(options.label) { + _options.type = 'label' + } else { + // 什么配置都没提供,则返回空对象 + return _options + } + + // 转通用配置 + const common = parseCommonOptions(_options.type, options.common); + // 属性配置项 + const property = options.property || {}; + property.type = _options.type; + + switch (_options.type) { + case 'point': + return parsePointOptions(options, common, property) + case 'polyline': + return parsePolylineOptions(options, common, property) + case 'polygon': + return parsePolygonOptions(options, common, property) + case 'billboard': + return parseBillboardOptions(options, common, property) + case 'label': + return parseLabelOptions(options, common, property) + default: + console.warn('不支持的样式类型:', _options.type); + return {} + } +} + +// 解析通用配置 +const parseCommonOptions = (type, options) => { + const _options = {} + if(!options) { + return _options + } + // 贴地 + if(options.clampToGround) { + _clampToGround = true; + } + // 按视距缩放 + // 线和面没有按视距缩放 + if(options.scaleByDistance && type !== 'polyline' && type !== 'polygon') { + _options.scaleByDistance = new Cesium.NearFarScalar( + options.scaleNear, + options.scaleNearValue, + options.scaleFar, + options.scaleFarValue + ); + } + return _options +} + +/** + * 解析点相关配置为对象 + * @param {Object} options 总配置项 + * @param {Object} common 通用配置对象 + * @param {Object} property 属性配置对象 + * @returns 点样式对象 + */ +const parsePointOptions = (options, common, property) => { + const style = { + point: createPointByOptions(options.point, common), + properties: property || {} + } + // 添加图标、标签 + if(options.billboard) { + style.billboard = createBillboardByOptions(options.billboard, common) + } + if(options.label) { + style.label = createLabelByOptions(options.label, common) + } + return style +} + +/** + * 解析点配置项 + * @param {Object} options 点配置项 + * @param {Object} common 通用配置对象 + * @returns cesium点对象 + */ +const createPointByOptions = (options, common) => { + if(!options) { + return undefined + } + + const _options = { + pixelSize: parseFloat(options.pixelSize) || 10, + color: Cesium.Color.fromCssColorString(options.color) || Cesium.Color.WHITE, + ...common + } + if(options.showOutline) { + _options.outlineWidth = parseFloat(options.outlineWidth) || 1 + _options.outlineColor = Cesium.Color.fromCssColorString(options.outlineColor) || Cesium.Color.BLACK + } + if(_clampToGround) { + _options.heightReference = Cesium.HeightReference.CLAMP_TO_GROUND + } + return new Cesium.PointGraphics(_options) +} + +/** + * 解析线相关配置为对象 + * @param {Object} options 总配置项 + * @param {Object} common 通用配置对象 + * @param {Object} property 属性配置对象 + * @returns 线样式对象 + */ +const parsePolylineOptions = (options, common, property) => { + const style = { + polyline: createPolylineByOptions(options.polyline, common), + properties: property || {} + } + // 添加闭合属性 + if(options.polyline.closed) { + property.closed = true + } + // 添加标签 + if(options.label) { + style.label = createLabelByOptions(options.label, common) + } + return style +} + +/** + * 解析线配置项 + * @param {Object} options 线配置项 + * @param {Object} common 通用配置对象 + * @param {Object} property 属性配置对象 + * @returns cesium线对象 + */ +const createPolylineByOptions = (options, common) => { + if(!options) { + return undefined + } + + const _options = { + width: parseFloat(options.width) || 1, + material: Cesium.Color.fromCssColorString(options.color) || Cesium.Color.WHITE, + ...common + } + if(_clampToGround) { + _options.clampToGround = true + } + return new Cesium.PolylineGraphics(_options) +} + +/** + * 解析面相关配置为对象 + * @param {Object} options 总配置项 + * @param {Object} common 通用配置对象 + * @param {Object} property 属性配置对象 + * @returns 面样式对象 + */ +const parsePolygonOptions = (options, common, property) => { + const style = { + polygon: createPolygonByOptions(options.polygon, common), + properties: property || {} + } + // 添加面的轮廓线 + if(options.polygon.showOutline) { + property.closed = true + style.polyline = createPolygonOutlineByOptions(options.polygon, common) + } + // 添加标签 + if(options.label) { + style.label = createLabelByOptions(options.label, common) + } + return style +} + +/** + * 解析面的轮廓线配置项 + * 因面的自带相关属性不支持贴地形,所以生成cesium线对象 + * @param {Object} options 面配置项 + * @param {Object} common 通用配置对象 + * @returns cesium线对象 + */ +const createPolygonOutlineByOptions = (options, common) => { + if(!options) { + return undefined + } + + const _options = { + width: parseFloat(options.outlineWidth) ?? 1, + material: Cesium.Color.fromCssColorString(options.outlineColor) || Cesium.Color.BLACK, + ...common + } + if(_clampToGround) { + _options.clampToGround = true + } + return new Cesium.PolylineGraphics(_options) +} + +/** + * 解析面配置项 + * @param {Object} options 面配置项 + * @param {Object} common 通用配置对象 + * @returns cesium面对象 + */ +const createPolygonByOptions = (options, common) => { + if(!options) { + return undefined + } + + const _options = { + material: Cesium.Color.fromCssColorString(options.color) || Cesium.Color.WHITE, + ...common + } + if(_clampToGround) { + _options.heightReference = Cesium.HeightReference.CLAMP_TO_GROUND + } + return new Cesium.PolygonGraphics(_options) +} + +/** + * 解析图标相关配置为对象 + * @param {Object} options 总配置项 + * @param {Object} common 通用配置对象 + * @param {Object} property 属性配置对象 + * @returns 图标样式对象 + */ +const parseBillboardOptions = (options, common, property) => { + const style = { + billboard: createBillboardByOptions(options.billboard, common), + properties: property || {} + } + // 添加标签 + if(options.label) { + style.label = createLabelByOptions(options.label, common) + } + return style +} + +/** + * 解析图标配置项 + * @param {Object} options 图标配置项 + * @param {Object} common 通用配置对象 + * @returns cesium图标对象 + */ +const createBillboardByOptions = (options, common) => { + if(!options) { + return undefined + } + + const _options = { + image: options.image, + scale: parseFloat(options.scale) ?? 1, + rotation: Cesium.Math.toRadians(parseFloat(options.rotation) || 0), + horizontalOrigin: parseInt(options.horizontalOrigin) ?? Cesium.HorizontalOrigin.CENTER, + verticalOrigin: parseInt(options.verticalOrigin) ?? Cesium.VerticalOrigin.BOTTOM, + pixelOffset: new Cesium.Cartesian2(parseFloat(options.horizontalOffset) || 0, parseFloat(options.verticalOffset) || 0), + ...common + } + if(_clampToGround) { + _options.heightReference = Cesium.HeightReference.CLAMP_TO_GROUND + } + return new Cesium.BillboardGraphics(_options) +} + +/** + * 解析标签相关配置为对象 + * @param {Object} options 总配置项 + * @param {Object} common 通用配置对象 + * @param {Object} property 属性配置对象 + * @returns 标签样式对象 + */ +const parseLabelOptions = (options, common, property) => { + return { + label: createLabelByOptions(options.label, common), + properties: property || {} + } +} + +/** + * 解析标签配置项 + * @param {Object} options 标签配置项 + * @param {Object} common 通用配置对象 + * @returns cesium标签对象 + */ +const createLabelByOptions = (options, common) => { + if(!options) { + return undefined + } + + const _options = { + font: `${options.font ?? 16}px sans-serif`, + fillColor: Cesium.Color.fromCssColorString(options.fillColor) || Cesium.Color.WHITE, + horizontalOrigin: parseInt(options.horizontalOrigin) ?? Cesium.HorizontalOrigin.CENTER, + verticalOrigin: parseInt(options.verticalOrigin) ?? Cesium.VerticalOrigin.BOTTOM, + pixelOffset: new Cesium.Cartesian2(parseFloat(options.horizontalOffset) ?? 0, parseFloat(options.verticalOffset) ?? 0), + ...common + } + if(options.showOutline) { + _options.style = Cesium.LabelStyle.FILL_AND_OUTLINE + _options.outlineWidth = parseFloat(options.outlineWidth) || 1 + _options.outlineColor = Cesium.Color.fromCssColorString(options.outlineColor) || Cesium.Color.BLACK + } + if(options.showBackground) { + _options.showBackground = true + _options.backgroundColor = Cesium.Color.fromCssColorString(options.backgroundColor) || new Cesium.Color(0.165, 0.165, 0.165, 0.8) + _options.backgroundPadding = new Cesium.Cartesian2(parseFloat(options.horizontalPadding) ?? 7, parseFloat(options.verticalPadding) ?? 5) + } + if(_clampToGround) { + _options.heightReference = Cesium.HeightReference.CLAMP_TO_GROUND + } + return new Cesium.LabelGraphics(_options) +} + +export { + getStyle +} diff --git a/src/router/index.js b/src/router/index.js index 4f57d6a..37a167b 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -99,6 +99,12 @@ export const constantRoutes = [ component: () => import('@/views/gisManagement/configSetting/index.vue'), name: 'configSetting', meta: { title: '地图配置' } + }, + { + path: 'configStyle', + component: () => import('@/views/gisManagement/configStyle/index.vue'), + name: 'configStyle', + meta: { title: '样式配置' } } ] } diff --git a/src/views/gisManagement/configStyle/iconDialog.vue b/src/views/gisManagement/configStyle/iconDialog.vue new file mode 100644 index 0000000..5f2e7c1 --- /dev/null +++ b/src/views/gisManagement/configStyle/iconDialog.vue @@ -0,0 +1,170 @@ + + + + + \ No newline at end of file diff --git a/src/views/gisManagement/configStyle/imageLibrary.vue b/src/views/gisManagement/configStyle/imageLibrary.vue new file mode 100644 index 0000000..ef37f45 --- /dev/null +++ b/src/views/gisManagement/configStyle/imageLibrary.vue @@ -0,0 +1,234 @@ + + + + + diff --git a/src/views/gisManagement/configStyle/index.vue b/src/views/gisManagement/configStyle/index.vue new file mode 100644 index 0000000..de4afdf --- /dev/null +++ b/src/views/gisManagement/configStyle/index.vue @@ -0,0 +1,155 @@ + + + + + \ No newline at end of file diff --git a/src/views/gisManagement/configStyle/styleDialog.vue b/src/views/gisManagement/configStyle/styleDialog.vue new file mode 100644 index 0000000..48b3962 --- /dev/null +++ b/src/views/gisManagement/configStyle/styleDialog.vue @@ -0,0 +1,728 @@ + + + + + \ No newline at end of file