WholeProcessPlatform/frontend/src/components/gis/gisUtils.ts
2026-08-31 14:04:06 +08:00

469 lines
14 KiB
TypeScript
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.

// import { Session } from '@zebras/qgc-share/service/Session'
import domtoimage from 'dom-to-image';
import {
offset2,
drawDotImg2,
drawDotImg1,
offset1,
drawDotImg3,
offset3,
drawDotImg5,
offset5
} from '@/utils/GisUrlList';
import { LAYOUT_GRID_SKELETONS } from '@/views/dianZhanZhuanTi/layoutGridSkeletons';
import { useUiStore } from '@/store/modules/ui';
declare global {
interface Window {
__lyConfigs?: {
theme?: string;
[key: string]: any; // 根据实际配置结构补充具体字段,或使用索引签名兼容其他属性
};
__mapMode?: string; // 建议同时声明代码中用到的其他全局变量
}
}
/**
* 根据镜头高度获取地图级别
* @param {Number} height
*/
const A = 40487.57;
const B = 0.00007096758;
const C = 91610.74;
const D = -40467.74;
/**
* 图例数据转对象
* @param data 图例数据
* @returns 以nameEn为下标的图例数据
*/
export const legendData2Obj = (data: any[]) => {
const _tempData: any = {};
const f = (_data: any[]) => {
_data.forEach(item => {
// childrenList有值表示这是一个分组
if (item?.childrenList && item.childrenList?.length > 0) {
f(item.childrenList);
} else {
_tempData[item.nameEn] = item;
}
});
};
f(data);
return _tempData;
};
/**
* 添加标签偏移量等属性到item中
* @param item - 待添加属性的item
* @param index - item的索引
* @param labelType - 标签类型
*/
export const appendOffsetPropties = (item: any, index: any, labelType = 2) => {
let drawDotImg = null;
let offset = null;
if (labelType == 2) {
drawDotImg = drawDotImg1;
offset = offset1;
addItemProperty(item, index, drawDotImg, offset);
} else if (labelType == 3) {
drawDotImg = drawDotImg2;
offset = offset2;
addItemProperty(item, index, drawDotImg, offset);
} else if (labelType == 4) {
drawDotImg = drawDotImg3;
offset = offset3;
addItemProperty2(item, index, drawDotImg, offset);
} else if (labelType == 5) {
drawDotImg = drawDotImg5;
offset = offset5;
addItemProperty2(item, index, drawDotImg, offset);
}
};
const addItemProperty2 = (
item: any,
index: any,
drawDotImg: any,
offset: any
) => {
if (!drawDotImg || !offset) return;
item.icon_image =
index % 2 !== 0
? drawDotImg[item.anchoPointState]?.left || ''
: drawDotImg[item.anchoPointState]?.right || '';
item.text_anchor = index % 2 !== 0 ? 'right' : 'left';
item.text_offset = offset[item.icon_image]?.text_offset ?? [-10, -1.8];
item.text_offset2 = offset[item.icon_image]?.text_offset2 ?? [-10, -1.8];
item.icon_offset = [
offset[item.icon_image]?.icon_x ?? -200,
offset[item.icon_image]?.icon_y ?? -50
];
item.icon_offset2 = offset[item.icon_image]?.icon_offset2 ?? [-200, -50];
item.billboard_offset = [
offset[item.icon_image]?.billboard_x ?? -80,
offset[item.icon_image]?.billboard_y ?? -15
];
item.label_offset = offset[item.icon_image]?.labelOffset ?? [100, 41];
};
export const addItemProperty = (
item: any,
index: any,
drawDotImg: any,
offset: any
) => {
if (!drawDotImg || !offset) return;
item.icon_image =
index % 2 !== 0
? drawDotImg[item.anchoPointState]?.left || ''
: drawDotImg[item.anchoPointState]?.right || '';
item.text_offset = [
offset[item.icon_image]?.text_x ?? -10,
offset[item.icon_image]?.text_y ?? -1.8
];
item.icon_offset = [
offset[item.icon_image]?.icon_x ?? -200,
offset[item.icon_image]?.icon_y ?? -50
];
item.billboard_offset = [
offset[item.icon_image]?.billboard_x ?? -80,
offset[item.icon_image]?.billboard_y ?? -15
];
item.label_offset = offset[item.icon_image]?.labelOffset ?? [100, 41];
};
/**
* 设置popName属性
* @param item - 待设置popName的item
*/
export const setPopName = (item: any) => {
if (item.sttp === 'ENG') {
item.popName = item.ennm || item.titleName;
} else if (item.sttp === 'ylfb') {
if (item?.ftp?.length > 20) {
item.popName = item.ftp.slice(0, 20) + '...';
} else {
item.popName = item?.ftp;
}
} else if (item.sttp === 'WE_FISH') {
item.popName =
item.fishList?.[0]?.fishName + `(${item.fishList?.[0]?.ptypeName})`;
item.popName1 = item.total + '尾';
} else {
item.popName = item.stnm || item.titleName;
}
};
/**
* 获取图例配置中选中项的key
* @param data - 图例配置数据
* @returns 选中项的key数组
*/
export const getCheckedLayerConfigs = (data: any[]): any[] => {
const rs: any[] = [];
const f = (arr: any[] = []) => {
let count = 0;
arr.forEach((item: any) => {
if (item?.children && item.children.length > 0) {
const childrenCount = f(item.children);
if (childrenCount) {
rs.push(item.key);
}
} else if (item.checked) {
count++;
rs.push(item.key); // 对应图例的layerCode
}
});
return count;
};
f(data);
return rs;
};
// type mapType = "" | "pointMap" | "gisLayer"
/**
* 将图层配置数据转换为一维数组
* @param data - 图层配置数据
* @returns 一维数组
*/
export const layerConfig2Flat = (data: any): any[] => {
const rs: any[] = [];
const f = (arr: any[] = []) => {
arr.forEach((item: any) => {
const { type } = item;
if (type) {
if (type == 'GISMap' || type == 'geojson') {
if (item?.children && item.children.length > 0) {
f(item.children);
} else {
rs.push(item);
}
} else if (type == 'pointMap') {
if (
item.url ||
item.title === '国家水文站' ||
item.title === '自建水文站'
) {
rs.push(item);
} else if (item.children.length > 0) {
f(item.children);
}
}
} else if (item.children.length > 0) {
f(item.children);
}
});
};
f(data);
return rs;
};
/**
* 替换图层配置中的 URL
* @param layerConfigsArr - 图层配置数组
* @param urlList - URL 配置列表
* @returns 更新后的图层配置数组
*/
export const replaceUrl = (layerConfigsArr: any[], urlList: any[]): any[] => {
const bDict: Record<string, any[]> = {};
// 构建 URL 映射字典
for (let i = 0; i < urlList.length; i++) {
const key = urlList[i].url;
const title = urlList[i].title;
const keyType = urlList[i].keyType;
if (!bDict[key]) bDict[key] = [];
if (!bDict[title]) bDict[title] = [];
if (!bDict[keyType]) bDict[keyType] = [];
bDict[key].push(urlList[i]);
bDict[title].push(urlList[i]);
if (bDict[keyType]) {
bDict[keyType].push(urlList[i]);
}
}
// 替换图层配置中的 URL
for (let i = 0; i < layerConfigsArr.length; i++) {
const obj = layerConfigsArr[i];
const key = obj.url;
const title = obj.title;
const keyType = obj.key;
const bObjList = bDict[keyType] || bDict[title] || bDict[key];
if (bObjList && bObjList.length > 0) {
const bObj = bObjList[0];
obj.url = bObj.url;
obj.urlThd = bObj.url;
obj.params = bObj.params;
obj.orders = bObj.orders;
} else {
obj.url = '';
}
}
return layerConfigsArr;
};
/**
* 获取基础图层配置
* @param config - 接口获取的配置数据
* @returns 基础图层配置
*/
export const getMapConfig = (config: any) => {
const r = { ...config };
const baseUrlObj = import.meta.env.VITE_APP_MAP_URL;
if (baseUrlObj) {
r.url = baseUrlObj + r.url; // 'http://localhost:8088'
r.url_3d = baseUrlObj + r.url_3d;
// r.url = baseUrlObj.url + r.url //baseUrlObj.url
// r.url_3d = baseUrlObj.url + r.url_3d
if (r.geojson_url) {
r.geojson_url = baseUrlObj + r.geojson_url;
}
}
return r;
};
/**
* 重置地图元素位置
*/
export const resetMapElPos = () => {
const legend = document.querySelector('#qgc-legendtl') as HTMLElement; // 图例
// const filter = document.querySelector('#map-filter-container') as HTMLElement // 全局表单
const controller = document.querySelector('#map-controller') as HTMLElement; // 地图工具栏
const baselayer = document.querySelector('#map-baselayer') as HTMLElement; // 底图模式切换
if (legend) {
legend.style.left = '0';
legend.style.bottom = '0';
}
if (controller) {
controller.style.right = '480px';
controller.style.bottom = '114px';
}
if (baselayer) {
baselayer.style.right = '480px';
baselayer.style.bottom = '20px';
}
};
/**
* 根据位置获取布局数据列表
* @param data - 布局数据
* @param position - 位置
* @returns 布局数据列表
*/
const getListByPosition = (data: any, position: string) =>
data?.data?.filter((el: any) => el.position === position && el.code);
/**
* 设置地图组件位置
* @param layoutType - 布局类型
* @param data - 布局数据({ type, data: BclDataItem[] }
* @param offset - 面板宽度 + padding + gap默认 460440px + 10px + 10px
* @param bottomRowHeight - 底部行高度(如 '200px'),无底部模块时不传
*/
export const setMapLegendPos = (
layoutType: string,
data: any,
offset = 460,
bottomRowHeight?: string
) => {
const menuStateString = localStorage.getItem('menuState');
const menuState =
menuStateString !== null ? JSON.parse(menuStateString) : true;
const _theme = localStorage.getItem('ly-theme') || window.__lyConfigs?.theme;
const legend = document.querySelector('#qgc-legendtl') as HTMLElement;
const filter = document.querySelector('#map-filter-container') as HTMLElement;
const compassControl = document.querySelector('#map-compassControl') as HTMLElement;
const monitor = document.querySelector('#map-monitor') as HTMLElement;
const leftList = getListByPosition(data, 'left');
const rightList = getListByPosition(data, 'right');
const bottomList = getListByPosition(data, 'bottom');
const hasLeft = leftList?.length > 0;
const hasRight = rightList?.length > 0;
const hasBottom = bottomList?.length > 0;
const w = `${offset}px`;
const l = `${_theme === 'ly-8' ? (menuState ? 643 : 510) : offset}px`;
let b = `0px`;
if (_theme === 'ly-8') {
b = window.__mapMode === '3D' ? '200px' : `${menuState ? 200 : 50}px`;
}
// 底部偏移
// px 值:直接 + padding(10px)
// fr 值:按占比算,如 3 行各 1fr = calc((100% - 40px) / 3 + 10px)
let bottomOffset = '12px';
if (hasBottom && bottomRowHeight) {
const pxMatch = bottomRowHeight.match(/^(\d+)px$/);
if (pxMatch) {
bottomOffset = `${parseInt(pxMatch[1]) + 10}px`;
} else if (bottomRowHeight.endsWith('fr')) {
const rows = (LAYOUT_GRID_SKELETONS[layoutType]?.gridTemplateRows || '').split(' ').filter(Boolean);
const n = rows.length; // 总行数
const gaps = (n - 1) * 10; // 行间距
bottomOffset = `calc((100% - 20px - ${gaps}px) / ${n} + 10px)`;
}
}
if (legend) {
legend.style.left = hasLeft ? `calc(${l} - 10px)` : b;
legend.style.bottom = bottomOffset;
}
if (filter) {
filter.style.left = hasLeft ? l : b;
}
if (compassControl) {
compassControl.style.left = hasLeft ? l : b;
}
if (monitor) {
monitor.style.right = hasRight ? w : '0';
}
// 地图控制器/底图切换器:通过 store 发布位置覆盖,组件内联样式优先读取,
// 避免 JS 直写 el.style 与组件自身 :style 绑定互相覆盖(刷新后重叠问题)。
const uiStore = useUiStore();
if (hasBottom) {
// 有底部模块有右模块时整体左移避让两者同底bottomOffset
uiStore.setMapControlsPosition({
controllerRight: hasRight ? w : null,
controllerBottom: bottomOffset,
baselayerRight: hasRight ? `calc(${w} + 60px)` : null,
baselayerBottom: bottomOffset
});
} else {
// 无底部模块:完全回退组件自身默认样式(与非电站专题页面一致)
uiStore.setMapControlsPosition({
controllerRight: null,
controllerBottom: null,
baselayerRight: null,
baselayerBottom: null
});
}
};
export const altitudeToZoom = (height: number) => {
const lv =
Math.round(D + (A - D) / (1 + Math.pow(Number(height) / C, B))) + 1;
return lv > -1 ? lv : 0;
};
/**
* 根据地图级别获取镜头高度
* @param {Number} zoom
*/
export const zoomToAltitude = (zoom: number) => {
return Math.round(C * Math.pow((A - D) / (zoom - D) - 1, 1 / B));
};
export const mapOutPut = (imageUrl: string) => {
const canvas = document.createElement('canvas');
const downloadElement = document.createElement('a');
const mapElem = document.getElementById('mapContainer');
if (mapElem == null) {
return;
}
const context = canvas.getContext('2d')!;
canvas.width = mapElem.offsetWidth;
canvas.height = mapElem.offsetHeight;
const image = new Image();
image.src = imageUrl;
image.onload = () => {
context.drawImage(image, 0, 0);
const elem: any = document.getElementById('qgc-legendtl');
const l = elem?.style?.left === '' ? 0 : parseInt(elem?.style?.left);
if (elem) {
domtoimage
.toPng(elem, {
quality: 1.0,
width: elem.offsetWidth + (l + 24),
height: mapElem.offsetHeight - 20
})
.then((legendUrl: string) => {
const image = new Image();
image.src = legendUrl;
image.width = elem.offsetWidth;
image.onload = () => {
context.drawImage(image, 0, 0);
downloadElement.href = canvas.toDataURL('image/png');
downloadElement.download = '地图截图';
downloadElement.click();
};
})
.catch(() => {});
} else {
downloadElement.href = canvas.toDataURL('image/png');
downloadElement.download = 'download';
downloadElement.click();
}
};
};