业务需求:同一个页面能够打开多个弹框,分别绘制对应的点位或图形,关闭某个弹框清除对应的图层,不影响其他图层的正常使用。
1.初始化onMounted的时候执行获取数据的操作,请求list数据获取需要撒点的所有图标以及经纬度信息
2.执行list接口,采用回调函数的方式,获取到数据后,在vue里进行预处理图标样式
3.stores封装全局地图图层公用方法(可复制,Util方法可复制也可自行定义)
Util.d.ts文件中的公用工具
export default class Util {
/**
* 阻止事件冒泡
* @param e
*/
static stopEventPop(e: any): void;
/**
* 重复绑定函数,只执行最后一次
* @param func
* @param wait
* @param options
*/
static debounce(func: any, wait?: number, options?: {
leading?: boolean | undefined;
/**
* @see maxWait
*/
maxWait?: number | undefined;
/**
* @see trailing
*/
trailing?: boolean | undefined;
}): any;
/**
*移除数组中predicate(断言)返回为真值的所有元素,并返回移除元素组成的数组
* @param array
* @param func
* @returns {Array}
*/
static remove(array: any[], func: any): any;
/**
* 判断数据中是否存在某一元素
* @param array
* @param item
* @returns {boolean}
*/
static includes(array: any[], item: any): any;
/**
* 通过fn函数返回值进行分组
* @param data
* @param fn
*/
static groupBy(data: any[], fn: any): any;
/**
* 数组元素去重
* @param array
* @returns {Array}
*/
static uniq(array: any): any;
/**
* 比较source中的对象在target中是否有修改
* @param source
* @param target
*/
static compileObj(source: any, target: any): boolean;
/**
* 数组对象中的特定属性的去重数组
* @param data
* @param field
*/
static unionByField(data?: never[], field?: string): any;
/**
* 转换表单为多行数据对象,rowKey为行记录主键(如:人员编号)
* @param data
* @param splitStr
* @param suffixStr
*/
static convertFormValueToMultiObj(data?: any, splitStr?: string, suffixStr?: string): any;
/**
* 创建虚拟key,从1开始避免有判断key是否存在时布尔值异常
* @param data
* @param key
* @param keyNum
*/
static virtualKey(data?: never[], key?: string, keyNum?: number): any[];
/**
* 返回固定数量的0字符串
* @param num
*/
static fillZeroStr(num: number): any;
/**
* 返回固定数量的字符串,用join连接
* @param num
* @param char
* @param join
*/
static fillStr(num: number, char?: string, join?: string): any;
/**
* join 值添加单引号包裹
* @param arr
* @param sep
*/
static joinSingleQuote(arr?: never[], sep?: string): string;
/**
* 将文本转换为数组,使用','切分, 去重
* @param str
*/
static textToArr(str?: string): string[];
/**
* 将字符串文本转换为数组,使用','切分,不去重
* @param str
*/
static stringToArr(str?: string): string[];
/**
* 数组中存在移除,不存在添加
* @param data
* @param key
*/
static exitRemoveOrNoExitAdd(data: any[], key: any): any[];
/**
* 合并数组通过属性
* @param objects
* @param others
* @param key
*/
static mergeBy(objects: any[], others: any[], key: any): any[];
static stringToMultiCheckBox(field: any, data: any): any;
/**
* 树型组件转换数据
* @param data
* @param callback
*/
static convertTreeData({ data, callback }: {
data: any[];
callback: any;
}): any[];
/**
* 为表格数据中添加key虚字段(用于表格编辑行标识)
* @param data
* @param rowKey
*/
static tableRowKeyFormat(data: any[], rowKey: any): any[] | undefined;
/**
* 是否url地址
* @param path
* @returns {boolean}
*/
static isUrl(path: any): boolean;
/**
* 路径转换
* 示例:/userinfo/2144/id => ['/userinfo','/useinfo/2144,'/userindo/2144/id']
* @param url
* @returns {*}
*/
static urlToList(url: string): string[];
/**
* 是否日期类型
* @param value
* @returns {boolean}
*/
static isDate(value: any): boolean;
/**
* 是否日期时间类型
* @param value
* @returns {boolean}
*/
static isDatetime(value: any): boolean;
/**
* 是否时间类型
* @param value
* @returns {boolean}
*/
static isTime(value: any): boolean;
/**
* 获取日期匹配的正则
* @param value
*/
static getDateMatch(value: any): RegExpMatchArray | null;
/**
* 是否可以匹配日期格式
* @param value
*/
static isDateMatch(value: any): boolean;
/**
* 转换为一个 dayjs 日期类型
* @param value
* @returns {*}
*/
static convertDate(value: any): any;
/**
* 校验是否为日期对象
* @param val
* @returns {*}
*/
static validDate(val: any): any;
/**
* 转换值为对应类型
* @param val
* @returns {*}
*/
static convertBaseValue(val: any): any;
/**
* 转换表单数据
* @param data
*/
static convertValueTemplate(data: any, convertValueCallback: Function, field: string[]): any;
/**
* 转换表单数据
* @param data
*/
static convertValue(data: any): any;
/**
* 转换值为对应类型
* @param val
* @returns {*}
*/
static convertBaseValueDate(val: any): any;
/**
* 转换表单数据
* @param data
*/
static convertValueDate(data: any): any;
static formatDayjs(value: any, format?: string): any;
/**
* 将日期转换成对应的格式,不传默认为YYYY-MM-DD
* @param value
* @param format
*/
static format(value: any, format?: string): any;
static formatDate(d: any): string;
static formatToMonDay(d: any): string;
/**
* 将日期格式化成YYYY-MM-DD HH:mm
* @param value
*/
static formatToDateMin(value: any): any;
/**
* 将日期格式化成YYYY-MM-DD
* @param value
*/
static formatToDate(value: any): any;
/**
* 将日期格式化成HH:mm:ss
* @param value
*/
static formatToTime(value: any): any;
/**
* 将日期格式化成YYYY-MM-DD HH:mm:ss
* @param value
*/
static formatToDateTime(value: any): any;
/**
* 判断传入参数是否为数据
* isArray([1, 2, 3]) => true
* isArray(document.body.children); => false
* isArray('abc'); => false
* @param value
*/
static isArray(value: any): any;
/**
* 判断传入参数是否为boolean
* isBoolean(false); => true
* isBoolean(null); => false
* @param value
*/
static isBoolean(value: any): any;
/**
* 判断传入参数是否为null, '', undefined,{}
* 数字和boolean行返回都是true
* isEmpty(); => true
* isEmpty({}); => true
* isEmpty([]); => true
* isEmpty(true); => true
* isEmpty(false); => true
* isEmpty(undefined); => true
* isEmpty(null); => true
* isEmpty(1); => true
* isEmpty(''); => true
* @param value
*/
static isEmpty(value: any): any;
/**
* 判断传入参数不为空,说明见isEmpty
* @param value
* @returns {boolean}
*/
static isNotEmpty(value: any): boolean;
/**
* 判断传入参数是否为方法
*/
static isFunction(value: any): any;
/**
* 判断传入参数是否NaN
* isNaN(NaN); => true
* isNaN(new Number(NaN)); => true
* isNaN(undefined); => false
* @param value
*/
static isNaN(value: any): any;
/**
* 判断传入参数是否为null
* isNull(null); => true
* isNull(''); => false
* @param value
*/
static isNull(value: any): any;
/**
* 判断传入参数是否为数字
* isNumber(3); => true
* isNumber('3'); => false
* isNumber(Infinity); => true
* isNumber(Number.MIN_VALUE); => true
* @param value
*/
static isNumber(value: any): any;
/**
* 判断传入参数是否纯对象
* isPlainObject(new Foo) => false
* isPlainObject([1, 2, 3]); => false
* isPlainObject({}); => true
* isPlainObject({ 'x': 0, 'y': 0 }); => true
* isPlainObject(Object.create(null)); => true
* @param value
*/
static isPlainObject(value: any): any;
/**
* 判断传入参数是否为纯字符串
* isString('abc'); => true
* isString(1); => false
* isString({}); => false
* @param value
*/
static isString(value: any): any;
/**
* 判断是否已target参数结尾,如果position有值,则从position位置开始
* endsWith('abc', 'c'); => true
* endsWith('abc', 'b'); => false
* endsWith('abc', 'b', 2); => true
* @param value 目标string字符串
* @param target 需要判断的字符串
* @param position 末尾起始位置判断 默认值string.length
*/
static endsWith(value: any, target: any, position?: any): any;
/**
* 判断是否已target参数开始,如果position有值,则从position位置开始
* startsWith('abc', 'a'); => true
* startsWith('abc', 'b'); => false
* startsWith('abc', 'b', 1); => true
* @param value
* @param target
* @param position
*/
static startsWith(value: any, target: any, position: any): any;
/**
* value后补全chars字符串,直至整体长度达到length
* padEnd('abc', 6); => 'abc '
* padEnd('abc', 6, '_-'); => 'abc_-_'
* padEnd('abc', 3); => 'abc'
* @param value
* @param length
* @param chars 默认为' '
*/
static padEnd(value: any, length: any, chars: any): any;
/**
* value前补全chars字符串,直至整体长度达到length
* padStart('abc', 6); => ' abc'
* padStart('abc', 6, '_-'); => '_-_abc'
* padStart('abc', 3); => 'abc'
* @param value
* @param length
* @param chars
* @returns {*|string}
*/
static padStart(value: any, length: any, chars: any): any;
/**
* 将value值前后的chars移除,chars默认值为whitespace
* trim(' abc '); => 'abc'
* @param value
* @param chars
*/
static trim(value: any, chars: any): any;
/**
* 将value值末尾的chars移除,chars默认值为whitespace
* trimEnd(' abc '); => ' abc'
* @param value
* @param chars
*/
static trimEnd(value: any, chars: any): any;
/**
* 将value值开始的chars移除,chars默认值为whitespace
* trimStart(' abc '); => 'abc '
* @param value
* @param chars
* @returns {*|string}
*/
static trimStart(value: any, chars: any): any;
/**
* 是否手机号
* 以1开头后跟10位数字
* @param str
* @return {boolean}
*/
static isMobile(str: string): boolean;
static isFixedLine(str: string): boolean;
static pureString(str: string): boolean;
static isFax(str: string): boolean;
/**
* 是否Email 地址
* @param str
* @return {boolean}
*/
static isEmail(str: string): boolean;
/**
* 是否 邮编
* @param str
* @return {boolean}
*/
static isZipCode(str: string): boolean;
/**
* 判断是否为身份证号码
* @param str
* @returns {boolean}
*/
static isIdCard(str: string): boolean;
/**
* 删除字符串结尾的字符串,不传默认为','
* @param value
* @param char
* @returns {*}
*/
static deleteEndChar(value: any, char?: string): any;
/**
* 删除字符串开头的字符, 不传默认为','
* deleteStartChar('test', 't'); => 'est'
* deleteStartChar('test', 'te'); => 'st'
* deleteStartChar('test'); => 'test'
* deleteStartChar(',test'); => 'test'
* @param value
* @param char
* @returns {string}
*/
static deleteStartChar(value: any, char?: string): any;
/**
* 是否对象
* @param value
*/
static isObject(value: any): any;
/**
* 删除字符串结尾出现的指定字符串
* @param str
* @param deleteChar
* @returns {*}
*/
static deleteAllEndChar(str: any, deleteChar: any): any;
/**
* 可比较字符串,数字,数组,对象,布尔是否相等
* 比较数组时,内部已经忽略数组顺序,将传入数组参数进行排序.sort()
* @param value
* @param other
*/
static isEqual(value: any, other: any): any;
static cloneDeep(value: any): any;
/**
* 数组转对象,按field取值作为key
* @param array
* @param field
*/
static keyBy(array: any, field: any): any;
/**
* 是否不相同
* @param value
* @param other
*/
static isNotEqual(value: any, other: any): boolean;
/**
* 转换成驼峰
* @param str
*/
static toCamel(str: string): any;
/**
* 日期时间比较 val1 是否早于 val2 dayjs('2010-10-20').isBefore('2010-10-21') // true
* @param val1
* @param val2
* @returns {boolean}
*/
static isBefore(val1: any, val2: any): boolean;
/**
* 日期时间判断
* 时间val1和时间val2 是否相等 dayjs('2010-10-20').isSame('2010-10-20') // true
* @param val1
* @param val2
* @returns {boolean}
*/
static isSame(val1: any, val2: any): boolean;
/**
* 日期时间判断
* 时间val1是否晚于时间val2 dayjs('2010-10-20').isAfter('2010-10-19') // true
* @param val1
* @param val2
* @returns {boolean}
*/
static isAfter(val1: any, val2: any): boolean;
/**
* 时间 val1 是否在时间val2和val3范围内,在时间范围内返回true dayjs('2010-10-20').isBetween('2010-10-19', '2010-10-25') // true
* @param val1
* @param val2
* @param val3
* @returns {boolean}
*/
static isBetween(val1: any, val2: any, val3: any): boolean;
/**
* 返回数组重复项
* [1,2,3,4,4,2] => [2,4]
* @param data
*/
static selfRepeat(data: any[]): any[];
/**
* 数组去重
* @param data
* @returns {Array}
*/
static union(data: any[]): any[];
/**
* 获取字符串中特殊字符的长度
*/
static speLen(text: any, len: any): any;
/**
* 获取字符串中数字字符的长度
*/
static numLen(text: any, len: any): any;
/**
* 获取需要显示字符串长度
*/
static columnLen(text: any, len: any): any;
/**
* 清空对象中的‘’和null
* @param params
* @returns Object
*/
static omitBy(params: any): any;
/**
* 根据某个属性查找重复数据
* @param data [{}]
* @param field 数组中对象的某个属性
* @returns {Array} 重复数据
*/
static getRepeatBy(data: any[], field: any): any[];
/**
* 首字母大写
* @param str
*/
static _capitalize(str: string): string | undefined;
/**
* 拼接年月字符串,isDay 是否需要天数
*/
static getYearMonth(year: any, month: any, isDay: any): any;
/**
* 将hex颜色转成rgba
* @param hex
* @param opacity
*/
static hexToRgba(hex: any, opacity?: number): {
rgba: string | null;
};
/**
* 将rgb颜色转成hex
* @param color
*/
static colorRGB2Hex(color: any): {
hex: string | null;
a: number;
};
/**
* 将时间戳转为 xx天xx小时xx分格式
* @param mss
*/
static formatDuring(mss: number): string;
/**
* 将时间戳转为小时数
* @param mss
*/
static formatHour(mss: number): number;
/**
* 混淆记住密码
* @param password
* @returns {string}
*/
static confusePass(password: any): string;
/**
* 解析混淆的密码
* @param confusePass
* @returns {string}
*/
static reConfusePass(confusePass: any): any;
/**
* 转换HTML
* @param oldStr
* @returns {*}
*/
static transferEntityName2Char(oldStr: any): any;
/**
* 默认值
* @param val
* @returns
*/
static dvb(val: any): boolean;
/**
* 当前值为空返回默认值
* @param val
* @param d
* @returns
*/
static defaultVal(val: any, d: any): any;
}
全局地图绘制stores方法
import { defineStore } from "pinia";
import "@msa/map-leaflet/dist/index.css";
import { Util } from "@msa/msa-core";
import {
L,
LeafletDrawLayerUtil,
createMapManager,
drawShapeLayer,
markerGroupLayer,
measureLayer,
shipIconLayer,
shipTrackLayer,
} from "@msa/map-leaflet";
export interface MapState {
$loading: Record<string, boolean>;
}
export const useMapStore = defineStore("map", {
state: (): MapState => ({
$loading: {},
}),
getters: {},
actions: {
async initMap() {
const tileUrl = import.meta.env.VITE_TILE_URL;
const tileLabelUrl = import.meta.env.VITE_TILE_LABEL_URL;
const mapManager = createMapManager({
id: "map-app",
tiles: [tileUrl, tileLabelUrl],
center: [20.01, 110.01],
zoom: 5,
minZoom: 3,
maxZoom: 18,
zoomRulePosition: "bottomright",
mouseLocPosition: "bottomright",
zoomControlPosition: "bottomright",
// // 图层设置为canvas svg
// preferCanvas: true,
});
if (!mapManager) {
return;
}
const onShipClick = (_shipData: any, shipFlag: boolean) => {
if (shipFlag) {
}
};
const drawLayerGroup = new L.FeatureGroup();
drawLayerGroup.addTo(mapManager.map);
LeafletDrawLayerUtil.initLayer(mapManager.map, drawLayerGroup);
const canvasRender = L.canvas({ padding: 0.5 });
const shipLayer = shipIconLayer({
map: mapManager.map,
shipData: [],
onShipClick,
sailFlagSpeed: 1,
showDynamicIconZoom: 12,
renderer: canvasRender,
});
const trackLayer = shipTrackLayer({
map: mapManager.map,
isSnake: true,
shipData: [],
shipTrackDataObj: {},
renderer: canvasRender,
circleLabelTitle: (item: any) => {
// 轨迹的title
return item.utc ? Util.formatToDateTime(item.utc) : "-";
},
circleHoverTitle: (item: any) => {
// 鼠标悬浮的title;
return `<div>时间:${item.utc ? Util.formatToDateTime(item.utc) : "-"}</div>`;
},
});
const markerLayer = markerGroupLayer({
map: mapManager.map,
renderer: canvasRender,
});
const drawLayer = drawShapeLayer({
map: mapManager.map,
});
const globalMeasureLayer = measureLayer({
map: mapManager.map,
});
const areaDrawLayer = drawShapeLayer({
map: mapManager.map,
});
window.globalMarkerLayer = markerLayer;
window.globalShipLayer = shipLayer;
window.globalTrackLayer = trackLayer;
window.globalDrawLayer = drawLayer;
window.globalMeasureLayer = globalMeasureLayer;
window.globalCanvasRender = canvasRender;
window.globalAreaDrawLayer = areaDrawLayer;
window.leafletMap = mapManager.map;
//业务组件的图层
window.globalLayerGroup = {};
},
/**
* 新建图层--layerGroup
*/
newLayerGroup(groupName: string = "") {
if (Util.isEmpty(window.globalLayerGroup[groupName])) {
window.globalLayerGroup[groupName] = new L.LayerGroup();
window.globalLayerGroup[groupName].addTo(window.leafletMap);
}
},
/**
* 清空指定图层
*/
removeLayerGroup(groupName: string = "") {
if (Util.isNotEmpty(window.globalLayerGroup[groupName])) {
window.globalLayerGroup[groupName].clearLayers &&
window.globalLayerGroup[groupName].clearLayers();
//通航要素图层
window.globalLayerGroup[groupName].clear && window.globalLayerGroup[groupName].clear();
}
},
/**
* 清空全部海图图层
*/
removeAllLayerGroup() {
Object.keys(window.globalLayerGroup).map((key) => {
if (Util.isNotEmpty(window.globalLayerGroup[key])) {
window.globalLayerGroup[key].clearLayers && window.globalLayerGroup[key].clearLayers();
//通航要素图层
window.globalLayerGroup[key].clear && window.globalLayerGroup[key].clear();
}
});
},
/**
* 添加layer
*/
addLayer(groupName: string = "", layer: any) {
window.globalLayerGroup[groupName]?.addLayer(layer);
},
/**
* 删除指定layer
*/
removeLayer(groupName: string = "", layer: any) {
window.globalLayerGroup[groupName]?.removeLayer(layer);
},
/**
* 判断图层是否存在
* 返回 true:代表图层存在
* 返回 false: 代表图层不存在
*/
groupIsExist(groupName: string = "") {
return Util.isNotEmpty(window.globalLayerGroup[groupName]);
},
},
});
4.引入公共图层的绘制
5.继续执行initDcrNavigationBaseInfoItem方法,进行点位撒点和图层,每次绘制之前调用 mapStore.removeLayerGroup()清除之前的图层,避免vue3的多次执行onMounted问题。
6.至此以上步骤,海图的基本点位的绘制、hover提示事件、点击事件都已经完成。下面做修改海图的某一个具体点位的信息功能(一般按钮都在修改页添加一下功能):
(1.)“修改按钮”(清除旧点位,添加新点位);
(2.)“清除按钮”(清除修改的点位位置);
(3.)“取消按钮”(修改点位后取消,恢复原有点位,减少重绘)
7.关闭当前页面,移出当前图层,清除当前所有点位的撒点