| | |
| | | <script setup lang="ts" name="ThemeControl"> |
| | | import type { ElTree } from 'element-plus'; |
| | | import { chunk } from 'lodash-es'; |
| | | import Circle from 'ol/style/Circle'; |
| | | import Style from 'ol/style/Style'; |
| | | import type { PropType } from 'vue'; |
| | | import { computed, ref, watch } from 'vue'; |
| | | import { switchMapTheme } from '/@/api/map'; |
| | | import type { OLMap } from '/@/model/map/OLMap'; |
| | | import { formatDate } from '/@/utils/formatTime'; |
| | | import { travelTree } from '/@/utils/util'; |
| | | import Fill from 'ol/style/Fill'; |
| | | import Stroke from 'ol/style/Stroke'; |
| | | import { Text } from 'ol/style'; |
| | | import { ElLoadingService } from 'element-plus'; |
| | | |
| | | const props = defineProps(['olMap']); |
| | | const props = defineProps({ |
| | | olMap: { |
| | | type: Object as PropType<OLMap>, |
| | | required: true, |
| | | }, |
| | | }); |
| | | const emit = defineEmits(['close']); |
| | | |
| | | const defaultProps = { |
| | | children: 'children', |
| | | label: 'title', |
| | | }; |
| | | const closeClick = () => { |
| | | emit('close'); |
| | | }; |
| | | const checkTreeRef = ref<InstanceType<typeof ElTree>>(); |
| | | const parseLegends = (legends) => { |
| | | const result = legends.map((item) => { |
| | | const isEqual = item.operate === '='; |
| | | const result = { |
| | | ...item, |
| | | legend: item.legend.map((legendItem, index, array) => { |
| | | const preItem = array[index - 1]; |
| | | let label = ''; |
| | | if (isEqual) { |
| | | label = legendItem.value; |
| | | } else if (preItem) { |
| | | label = `>${preItem.value}且${item.operate}${legendItem.value}`; |
| | | } else { |
| | | label = `${item.operate}${legendItem.value}`; |
| | | } |
| | | return { |
| | | ...legendItem, |
| | | label: label, |
| | | }; |
| | | }), |
| | | }; |
| | | |
| | | result.legend.push({ |
| | | style: item.default, |
| | | value: '', |
| | | label: result.legend.length == 0 ? '默认' : `>${item.legend[item.legend.length - 1].value}`, |
| | | }); |
| | | return result; |
| | | }); |
| | | return result; |
| | | }; |
| | | let isHumanCheckTrigger = false; |
| | | const handleCheck = (data: any, node: any) => { |
| | | const checkedKeys = node.checkedKeys; |
| | | isHumanCheckTrigger = true; |
| | | |
| | | // 取消分组中旧的选项 |
| | | const excludeKeys = []; |
| | | for (const themeGroup of themeInfo.value) { |
| | | // 原来有多少个设置的 |
| | | const originSet = themeGroup.children.filter((item) => item.isSet); |
| | | // 现在有多少个设置的 |
| | | const newSet = themeGroup.children.filter((item) => checkedKeys.includes(item.id)); |
| | | if (originSet.length === 1 && newSet.length === 2) { |
| | | originSet[0].isSet = false; |
| | | excludeKeys.push(originSet[0].id); |
| | | } |
| | | } |
| | | |
| | | const realCheckedKeys = checkedKeys.filter((key) => !excludeKeys.includes(key)); |
| | | |
| | | travelTree(themeInfo.value, (theme, index, array, parent) => { |
| | | if (theme.type === 'theme') { |
| | | const id = theme.id; |
| | | if (!realCheckedKeys.includes(id)) { |
| | | theme.isSet = false; |
| | | } else { |
| | | theme.isSet = true; |
| | | } |
| | | } |
| | | }); |
| | | checkTreeRef.value?.setCheckedKeys(realCheckedKeys); |
| | | }; |
| | | |
| | | const handleNodeClick = () => {}; |
| | | const themeInfo = computed(() => { |
| | | const info = (props.olMap as OLMap).themeInfo.value; |
| | | // info.push({ |
| | |
| | | return result; |
| | | }); |
| | | |
| | | const styleMap: Record<string, Record<string, Style>> = { |
| | | junction: {}, |
| | | pipe: {}, |
| | | polygon: {}, |
| | | }; |
| | | const maxResolution = 1; |
| | | |
| | | const getText = function (feature, resolution) { |
| | | const oname = feature.get('oname'); |
| | | let text = `first-${oname[0]}`; |
| | | if (resolution > maxResolution) { |
| | | text = ''; |
| | | } |
| | | |
| | | // else if (type == 'hide') { |
| | | // text = ''; |
| | | // } else if (type == 'shorten') { |
| | | // text = text.trunc(12); |
| | | // } else if (type == 'wrap' && (!dom.placement || dom.placement.value != 'line')) { |
| | | // text = stringDivider(text, 16, '\n'); |
| | | // } |
| | | |
| | | return text; |
| | | }; |
| | | const createTextStyle = (feature, resolution) => { |
| | | return new Style({ |
| | | text: new Text({ |
| | | text: getText(feature, resolution), |
| | | font: '14px Arial', |
| | | fill: new Fill({ color: '#000' }), |
| | | stroke: new Stroke({ color: '#fff', width: 2 }), |
| | | offsetX: 10, // 文字相对于几何中心的水平偏移 |
| | | offsetY: 20, // 文字相对于几何中心的垂直偏移 |
| | | }), |
| | | }); |
| | | }; |
| | | |
| | | const legendList = ref([]); |
| | | const changeTheme = async (themeId: string) => { |
| | | const loadingInstance = ElLoadingService({ |
| | | text: '加载主题中...', |
| | | target: '.layout-parent', |
| | | }); |
| | | const res = await switchMapTheme({ |
| | | theme_id: themeId, |
| | | time: formatDate(new Date()), |
| | | }).finally(() => { |
| | | loadingInstance.close(); |
| | | }); |
| | | |
| | | // 加入主题之后的样式函数 |
| | | const themeLayerStyleFunc = (feature, resolution) => { |
| | | const otype = feature.get('otype'); |
| | | const oname = feature.get('oname'); |
| | | // oname 映射样式 |
| | | const onameStyleMap = res?.[`O_${otype}`] ?? {}; |
| | | const themeStyles = res?.styles ?? []; |
| | | const styleIndex = onameStyleMap[oname]?.style_id; |
| | | const themeStyle = styleIndex == null ? null : themeStyles[styleIndex]; |
| | | // if(themeStyle){ |
| | | // } |
| | | const shape = feature.getGeometry().getType(); |
| | | const styles = []; |
| | | switch (shape) { |
| | | case 'Point': |
| | | const pSize = themeStyle?.PSIZE ?? feature.get('psize'); |
| | | |
| | | const pcolor = themeStyle?.PCOLOR ?? feature.get('pcolor'); |
| | | |
| | | const pStyle = themeStyle?.PSTYLE ?? feature.get('pstyle'); |
| | | |
| | | const pointStyle = props.olMap?.getPointStyles({ |
| | | size: pSize, |
| | | color: pcolor, |
| | | style: pStyle, |
| | | }); |
| | | pointStyle && styles.push(pointStyle); |
| | | break; |
| | | case 'LineString': |
| | | const lSize = themeStyle?.LSIZE ?? feature.get('lsize'); |
| | | const lColor = themeStyle?.LCOLOR ?? feature.get('lcolor'); |
| | | const lStyle = themeStyle?.LSTYLE ?? feature.get('lstyle'); |
| | | |
| | | const pSize1 = themeStyle?.PSIZE ?? feature.get('psize'); |
| | | const pcolor1 = themeStyle?.PCOLOR ?? feature.get('pcolor'); |
| | | const pStyle1 = themeStyle?.PSTYLE ?? feature.get('pstyle'); |
| | | |
| | | const lineStyle = props.olMap?.getLineStyles({ |
| | | lsize: lSize, |
| | | lcolor: lColor, |
| | | lstyle: lStyle, |
| | | psize: pSize1, |
| | | pcolor: pcolor1, |
| | | pstyle: pStyle1, |
| | | }); |
| | | lineStyle && styles.push(...lineStyle); |
| | | |
| | | break; |
| | | case 'Polygon': |
| | | const pColor = themeStyle?.PCOLOR ?? feature.get('pcolor'); |
| | | const lSize1 = themeStyle?.LSIZE ?? feature.get('lsize'); |
| | | const lColor1 = themeStyle?.LCOLOR ?? feature.get('lcolor'); |
| | | const lstyle1 = themeStyle?.LSTYLE ?? feature.get('lstyle'); |
| | | const polygonStyle = props.olMap?.getPolygonStyles({ |
| | | pcolor: pColor, |
| | | lsize: lSize1, |
| | | lcolor: lColor1, |
| | | lstyle: lstyle1, |
| | | }); |
| | | polygonStyle && styles.push(...polygonStyle); |
| | | |
| | | break; |
| | | default: |
| | | break; |
| | | } |
| | | |
| | | // switch (otype) { |
| | | // case 'WDM_JUNCTIONS': |
| | | // const textStyle = createTextStyle(feature, resolution); |
| | | // styles.push(textStyle); |
| | | |
| | | // case 'WDM_PIPES': |
| | | // break; |
| | | // } |
| | | //#region ====================== 添加标注 ====================== |
| | | const tString = themeStyle?.TSTRING ?? feature.get('tstring'); |
| | | const tStringStyle = props.olMap?.getLabelStyles({ |
| | | textContent: tString, |
| | | resolution, |
| | | }); |
| | | tStringStyle && styles.push(tStringStyle); |
| | | //#endregion |
| | | |
| | | return styles; |
| | | }; |
| | | const allLayers = props.olMap.getAllLayers(); |
| | | for (const item of allLayers) { |
| | | if (props.olMap?.unsupportedLayers.includes(item.id)) { |
| | | continue; |
| | | } |
| | | item.model.setStyle(themeLayerStyleFunc); |
| | | } |
| | | return res?.legends ?? []; |
| | | }; |
| | | const legendList = computed(() => { |
| | | return props.olMap.legendList.value; |
| | | }); |
| | | |
| | | const handleThemeChange = async (val, themeGroup) => { |
| | | const allIds = []; |
| | | for (const item of themeInfo.value) { |
| | | if (item.activeTheme) { |
| | | allIds.push(item.activeTheme); |
| | | } |
| | | } |
| | | const ids = allIds.join(','); |
| | | |
| | | if (!ids) { |
| | | const allLayers = props.olMap.getAllLayerModels(); |
| | | for (const item of allLayers) { |
| | | const originStyle = item.get('originStyle'); |
| | | originStyle && item.setStyle(originStyle); |
| | | } |
| | | return; |
| | | } |
| | | const legends = await changeTheme(ids); |
| | | legendList.value = parseLegends(legends); |
| | | props.olMap.changeTheme(val); |
| | | }; |
| | | const cancelTheme = (themeId: string) => { |
| | | themeInfo.value.find((item) => item.id === themeId).activeTheme = null; |