更新矢量加载逻辑

This commit is contained in:
hym 2026-04-06 23:07:42 +08:00
parent cb78e3b6d4
commit 84270bd4eb
3 changed files with 144 additions and 12 deletions

View File

@ -66,7 +66,7 @@ export class ColorGenerator {
positiveColor = '#1a9850' positiveColor = '#1a9850'
) { ) {
const colors = []; const colors = [];
const midPoint = Math.floor(count / 2); const midPoint = Math.floor(count + 1 / 2);
// 负值部分 // 负值部分
const negRGB = this.parseHexColor(negativeColor); const negRGB = this.parseHexColor(negativeColor);

View File

@ -86,11 +86,11 @@ export function initMapbox(mapId, options = {}) {
map.on('load', () => { map.on('load', () => {
// 加载海岸线 // 加载海岸线
if (options.coastlineOn || false) if (options.coastlineOn || false)
loadVectorLayer("GSHHS_f_L1", ["line"], ["#5c71c3"], "visible", mapId, 'ougp'); loadVectorLayer({ layerId: "GSHHS_f_L1", features: ["line"], colors: ["#5c71c3"], visibility: "visible", mapId, workspace: 'ougp' });
// 加载等深线 // 加载等深线
if (options.contourOn || false) { if (options.contourOn || false) {
loadVectorLayer("contour-4500m", ["line"], ["#FEFEFE"], "visible", mapId, 'ougp'); loadVectorLayer({ layerId: "contour-4500m", features: ["line"], colors: ["#FEFEFE"], visibility: "visible", mapId, workspace: 'ougp' });
loadVectorLayer("contour-6000m", ["line"], ["#FEFEFE"], "visible", mapId, 'ougp'); loadVectorLayer({ layerId: "contour-6000m", features: ["line"], colors: ["#FEFEFE"], visibility: "visible", mapId, workspace: 'ougp' });
} }
}); });
} }

View File

@ -3,8 +3,21 @@ import { regInfo } from '@/api/dataSearch'
let sourceLayer = undefined; let sourceLayer = undefined;
let clickedLineIds = []; let clickedLineIds = [];
// 存储可复用的每个地图对象的唯一 Popup 实例key 为 mapId以避免频繁创建/销毁 Popup 导致的性能问题和潜在内存泄漏 // 存储可复用的每个地图对象的唯一 Popup 实例key 为 mapId以避免频繁创建/销毁 Popup 导致的性能问题和潜在内存泄漏
let sharedPopup = {}; let sharedPopup = {};
// 存储上一条点击的线
let lastLineId;
// 默认的线宽表达式
export let lineWidthExpression = [
"case",
["boolean", ["feature-state", "hover"], false],
4,
["boolean", ["feature-state", "click"], false],
2,
1.8
];
export function setMapLayoutProperty(mapId, visibility = "none") { export function setMapLayoutProperty(mapId, visibility = "none") {
// 设置所有图层的显示/隐藏状态(根据图层类型或名称过滤底图图层,避免误操作) // 设置所有图层的显示/隐藏状态(根据图层类型或名称过滤底图图层,避免误操作)
@ -16,7 +29,19 @@ export function setMapLayoutProperty(mapId, visibility = "none") {
} }
}); });
} }
export function loadVectorLayer(layerId, features = ["line", "symbol"], colors = ["#FEFEFE", "#FF0000"], visibility = "visible", mapId = "homeMap", workspace = 'dsds', textField = "name") {
export function setMapPaintProperty({ mapId, property, value }) {
const layers = Vue.config.maps[mapId].getStyle().layers;
layers.forEach(layer => {
// 跳过底图和非测线图层
if (layer.id !== '影像地图' && layer.type !== 'raster' && layer.id.endsWith("-line")) {
Vue.config.maps[mapId].setPaintProperty(layer.id, property, lineWidthExpression);
}
});
// Vue.config.maps[mapId].setPaintProperty(layerId, "line-width", 14);
}
export function loadVectorLayer({ layerId, features = ["line", "symbol"], colors = ["#FEFEFE", "#FF0000"], visibility = "visible", mapId = "homeMap", workspace = 'dsds', textField = "name", callbackOnClick }) {
// 添加数据源 // 添加数据源
const sourceId = `vector-${layerId}`; const sourceId = `vector-${layerId}`;
let source = Vue.config.maps[mapId].getSource(sourceId); let source = Vue.config.maps[mapId].getSource(sourceId);
@ -50,11 +75,11 @@ export function loadVectorLayer(layerId, features = ["line", "symbol"], colors =
let i = 0; let i = 0;
features.forEach((feature) => { features.forEach((feature) => {
loadVectorFeature(layerId, feature, colors[i++], visibility, mapId, textField); loadVectorFeature({ layerId, feature, color: colors[i++], visibility, mapId, textField, callbackOnClick });
}); });
} }
export async function loadVectorFeature(layerId, feature, color, visibility, mapId, textField = "name") { export async function loadVectorFeature({ layerId, feature, color, visibility, mapId, textField = "name", callbackOnClick }) {
let sourceId = `vector-${layerId}`; let sourceId = `vector-${layerId}`;
// symbol // symbol
// Slot 是 Mapbox 样式规范中的一个概念,它定义了图层在渲染过程中的位置和顺序。 // Slot 是 Mapbox 样式规范中的一个概念,它定义了图层在渲染过程中的位置和顺序。
@ -147,9 +172,9 @@ export async function loadVectorFeature(layerId, feature, color, visibility, map
changeCursor(`${sourceId}-${feature}`, mapId); changeCursor(`${sourceId}-${feature}`, mapId);
if (layerId.includes("sample_line")) if (layerId.includes("sample_line"))
await showSampleLineInfo(`${sourceId}-${feature}`, mapId); await showSampleLineInfo(`${sourceId}-${feature}`, mapId, callbackOnClick);
if (layerId.includes("sample_station")) if (layerId.includes("sample_station"))
await showSampleStationInfo(`${sourceId}-${feature}`, mapId); await showSampleStationInfo(`${sourceId}-${feature}`, mapId, callbackOnClick);
else if (sourceId.includes("-SY") || sourceId.includes("-FDZ")) { else if (sourceId.includes("-SY") || sourceId.includes("-FDZ")) {
await showDiveInfo(`${sourceId}-${feature}`, mapId); await showDiveInfo(`${sourceId}-${feature}`, mapId);
console.log(mapId, `${sourceId}-${feature}`); console.log(mapId, `${sourceId}-${feature}`);
@ -290,14 +315,20 @@ export function changeCursor(layerId, mapId = "homeMap", cursor = "pointer") {
}); });
} }
export function showSampleLineInfo(layerId, mapId = "homeMap") { export function showSampleLineInfo(layerId, mapId = "homeMap", callbackOnClick = null) {
Vue.config.maps[mapId].on("click", layerId, async (e) => { Vue.config.maps[mapId].on("click", layerId, async (e) => {
// 在左侧列表中高亮对应项
if (callbackOnClick && typeof callbackOnClick === "function") {
callbackOnClick(e.features[0]);
}
// 禁止点击事件穿透 - 判断同一个 event 是否已经触发,用于避免图层内标记点注册的点击事件重复触发(点位分布密集时容易出现) // 禁止点击事件穿透 - 判断同一个 event 是否已经触发,用于避免图层内标记点注册的点击事件重复触发(点位分布密集时容易出现)
if (e.defaultPrevented) if (e.defaultPrevented)
return; return;
// 标记该 event 已触发,禁止点击事件穿透 // 标记该 event 已触发,禁止点击事件穿透
if (typeof e.preventDefault === "function") if (typeof e.preventDefault === "function")
e.preventDefault(); e.preventDefault();
// console.log("showSampleLineInfo: ", layerId, e.features[0]);
const description = ` const description = `
<table class="popup-table" style="min-width:380px;"> <table class="popup-table" style="min-width:380px;">
@ -339,8 +370,13 @@ export function showSampleLineInfo(layerId, mapId = "homeMap") {
}); });
} }
export function showSampleStationInfo(layerId, mapId = "homeMap") { export function showSampleStationInfo(layerId, mapId = "homeMap", callbackOnClick = null) {
Vue.config.maps[mapId].on("click", layerId, async (e) => { Vue.config.maps[mapId].on("click", layerId, async (e) => {
// 在左侧列表中高亮对应项
if (callbackOnClick && typeof callbackOnClick === "function") {
callbackOnClick(e.features[0]);
}
// 禁止点击事件穿透 - 判断同一个 event 是否已经触发,用于避免图层内标记点注册的点击事件重复触发(点位分布密集时容易出现) // 禁止点击事件穿透 - 判断同一个 event 是否已经触发,用于避免图层内标记点注册的点击事件重复触发(点位分布密集时容易出现)
if (e.defaultPrevented) if (e.defaultPrevented)
return; return;
@ -361,7 +397,7 @@ export function showSampleStationInfo(layerId, mapId = "homeMap") {
</thead> </thead>
<tr> <tr>
<td>数据集名称: <b>${feature.properties.dataset_name}</b></td> <td>数据集名称: <b>${feature.properties.dataset_name}</b></td>
<td>数据样品编号: <b>${feature.properties.sample_name}</b></td> <td>样品编号: <b>${feature.properties.sample_name}</b></td>
</tr> </tr>
<tr> <tr>
<td>赞助机构: <b>${feature.properties.funding_org}</b></td> <td>赞助机构: <b>${feature.properties.funding_org}</b></td>
@ -384,6 +420,102 @@ export function showSampleStationInfo(layerId, mapId = "homeMap") {
}); });
} }
export function showHighlightSampleInfo({ mapId, job_type, sample, layerId, sourceLayerId, callbackOnClick }) {
let description = "";
let coordinate;
if (job_type == "测线作业") {
// // 恢复其它测线的线宽
// // setMapPaintProperty({ mapId, property: "line-width", value: lineWidthExpression });
// // 恢复上一条高亮测线的宽度
// Vue.config.maps[mapId].setPaintProperty(lastLineId, "line-width", lineWidthExpression);
// // 高亮当前选择的测线
// Vue.config.maps[mapId].setPaintProperty(layerId, "line-width", 5);
// if (lastLineId)
// Vue.config.maps[mapId].setFeatureState(
// { sourceId: sourceLayerId, id: lastLineId },
// { hover: false }
// );
// Vue.config.maps[mapId].setFeatureState(
// { sourceId: sourceLayerId, id: layerId },
// { hover: true }
// );
// if (lastLineId)
// Vue.config.maps[mapId].setPaintProperty(lastLineId, 'line-color', '#FFFFFF')
// Vue.config.maps[mapId].setPaintProperty(layerId, 'line-color', '#FFFF00')
// lastLineId = layerId;
coordinate = [(Number(sample.start_lon) + Number(sample.end_lon)) / 2, (Number(sample.start_lat) + Number(sample.end_lat)) / 2];
description = `
<table class="popup-table" style="min-width:380px;">
<thead>
<tr>
<td colspan="2">测线信息</td>
</tr>
</thead>
<tr>
<td>数据集名称: <b>${sample.dataset_name}</b></td>
<td>数据样品编号: <b>${sample.sample_name}</b></td>
</tr>
<tr>
<td>赞助机构: <b>${sample.funding_org}</b></td>
<td>公开期限: <b>${sample.publish_rule}</b></td>
</tr>
<tr>
<td>开始经度: <b>${sample.start_lon}°</b></td>
<td>结束经度: <b>${sample.end_lon}°</b></td>
</tr>
<tr>
<td>开始纬度: <b>${sample.start_lat}°</b></td>
<td>结束纬度: <b>${sample.end_lat}°</b></td>
</tr>
<tr>
<td>开始时间: <b>${sample.start_time}</b></td>
<td>结束时间: <b>${sample.end_time}</b></td>
</tr>
<tr>
<td>测线深度: <b>${sample.line_deep}m</b></td>
<td>数据状态: <b>${sample.sample_status}</b></td>
</tr>
<tr>
<td colspan="2">备注信息: <b>${sample.sample_remark}</b></td>
</tr>
</table>`;
}
else if (job_type == "站位作业") {
coordinate = [sample.sampling_lon, sample.sampling_lat];
description = `
<table class="popup-table" style="min-width:380px;">
<thead>
<tr>
<td colspan="2">站位信息</td>
</tr>
</thead>
<tr>
<td>数据集名称: <b>${sample.dataset_name}</b></td>
<td>样品编号: <b>${sample.sample_name}</b></td>
</tr>
<tr>
<td>赞助机构: <b>${sample.funding_org}</b></td>
<td>公开期限: <b>${sample.publish_rule}</b></td>
</tr>
<tr>
<td>站位经度: <b>${sample.sampling_lon}°</b></td>
<td>站位纬度: <b>${sample.sampling_lat}°</b></td>
</tr>
<tr>
<td>采样时间: <b>${sample.sampling_time}</b></td>
<td>采样深度: <b>${sample.sampling_deep}m</b></td>
</tr>
<tr>
<td colspan="2">备注信息: <b>${sample.sample_remark}</b></td>
</tr>
</table>`;
}
showPopupDetails({ mapId, coordinate, description, maxWidth: "450px", callbackOnClose: callbackOnClick });
}
export function showTrackInfo(layerId, mapId = "homeMap") { export function showTrackInfo(layerId, mapId = "homeMap") {
Vue.config.maps[mapId].on("click", layerId, async (e) => { Vue.config.maps[mapId].on("click", layerId, async (e) => {
// 禁止点击事件穿透 - 判断同一个 event 是否已经触发,用于避免图层内标记点注册的点击事件重复触发(点位分布密集时容易出现) // 禁止点击事件穿透 - 判断同一个 event 是否已经触发,用于避免图层内标记点注册的点击事件重复触发(点位分布密集时容易出现)