Compare commits
2 Commits
e472fb961e
...
84270bd4eb
| Author | SHA1 | Date |
|---|---|---|
|
|
84270bd4eb | |
|
|
cb78e3b6d4 |
|
|
@ -66,7 +66,7 @@ export class ColorGenerator {
|
|||
positiveColor = '#1a9850'
|
||||
) {
|
||||
const colors = [];
|
||||
const midPoint = Math.floor(count / 2);
|
||||
const midPoint = Math.floor(count + 1 / 2);
|
||||
|
||||
// 负值部分
|
||||
const negRGB = this.parseHexColor(negativeColor);
|
||||
|
|
|
|||
|
|
@ -86,11 +86,11 @@ export function initMapbox(mapId, options = {}) {
|
|||
map.on('load', () => {
|
||||
// 加载海岸线
|
||||
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) {
|
||||
loadVectorLayer("contour-4500m", ["line"], ["#FEFEFE"], "visible", mapId, 'ougp');
|
||||
loadVectorLayer("contour-6000m", ["line"], ["#FEFEFE"], "visible", mapId, 'ougp');
|
||||
loadVectorLayer({ layerId: "contour-4500m", features: ["line"], colors: ["#FEFEFE"], visibility: "visible", mapId, workspace: 'ougp' });
|
||||
loadVectorLayer({ layerId: "contour-6000m", features: ["line"], colors: ["#FEFEFE"], visibility: "visible", mapId, workspace: 'ougp' });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,8 +3,21 @@ import { regInfo } from '@/api/dataSearch'
|
|||
|
||||
let sourceLayer = undefined;
|
||||
let clickedLineIds = [];
|
||||
|
||||
// 存储可复用的每个地图对象的唯一 Popup 实例(key 为 mapId),以避免频繁创建/销毁 Popup 导致的性能问题和潜在内存泄漏
|
||||
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") {
|
||||
// 设置所有图层的显示/隐藏状态(根据图层类型或名称过滤底图图层,避免误操作)
|
||||
|
|
@ -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}`;
|
||||
let source = Vue.config.maps[mapId].getSource(sourceId);
|
||||
|
|
@ -50,11 +75,11 @@ export function loadVectorLayer(layerId, features = ["line", "symbol"], colors =
|
|||
|
||||
let i = 0;
|
||||
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}`;
|
||||
// symbol
|
||||
// Slot 是 Mapbox 样式规范中的一个概念,它定义了图层在渲染过程中的位置和顺序。
|
||||
|
|
@ -147,9 +172,9 @@ export async function loadVectorFeature(layerId, feature, color, visibility, map
|
|||
changeCursor(`${sourceId}-${feature}`, mapId);
|
||||
|
||||
if (layerId.includes("sample_line"))
|
||||
await showSampleLineInfo(`${sourceId}-${feature}`, mapId);
|
||||
await showSampleLineInfo(`${sourceId}-${feature}`, mapId, callbackOnClick);
|
||||
if (layerId.includes("sample_station"))
|
||||
await showSampleStationInfo(`${sourceId}-${feature}`, mapId);
|
||||
await showSampleStationInfo(`${sourceId}-${feature}`, mapId, callbackOnClick);
|
||||
else if (sourceId.includes("-SY") || sourceId.includes("-FDZ")) {
|
||||
await showDiveInfo(`${sourceId}-${feature}`, mapId);
|
||||
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) => {
|
||||
// 在左侧列表中高亮对应项
|
||||
if (callbackOnClick && typeof callbackOnClick === "function") {
|
||||
callbackOnClick(e.features[0]);
|
||||
}
|
||||
|
||||
// 禁止点击事件穿透 - 判断同一个 event 是否已经触发,用于避免图层内标记点注册的点击事件重复触发(点位分布密集时容易出现)
|
||||
if (e.defaultPrevented)
|
||||
return;
|
||||
// 标记该 event 已触发,禁止点击事件穿透
|
||||
if (typeof e.preventDefault === "function")
|
||||
e.preventDefault();
|
||||
// console.log("showSampleLineInfo: ", layerId, e.features[0]);
|
||||
|
||||
const description = `
|
||||
<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) => {
|
||||
// 在左侧列表中高亮对应项
|
||||
if (callbackOnClick && typeof callbackOnClick === "function") {
|
||||
callbackOnClick(e.features[0]);
|
||||
}
|
||||
|
||||
// 禁止点击事件穿透 - 判断同一个 event 是否已经触发,用于避免图层内标记点注册的点击事件重复触发(点位分布密集时容易出现)
|
||||
if (e.defaultPrevented)
|
||||
return;
|
||||
|
|
@ -361,7 +397,7 @@ export function showSampleStationInfo(layerId, mapId = "homeMap") {
|
|||
</thead>
|
||||
<tr>
|
||||
<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>
|
||||
<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") {
|
||||
Vue.config.maps[mapId].on("click", layerId, async (e) => {
|
||||
// 禁止点击事件穿透 - 判断同一个 event 是否已经触发,用于避免图层内标记点注册的点击事件重复触发(点位分布密集时容易出现)
|
||||
|
|
|
|||
|
|
@ -236,7 +236,7 @@ import { getParamsList, getVoyageLine } from '../api/home'
|
|||
import { regInfo } from '@/api/dataSearch'
|
||||
import Cookies from 'js-cookie'
|
||||
import Vue from 'vue'
|
||||
import { setMapLayoutProperty, loadVectorLayer } from '@/utils/vector-layer-utils'
|
||||
import { setMapLayoutProperty, loadVectorLayer, showHighlightSampleInfo, lineWidthExpression } from '@/utils/vector-layer-utils'
|
||||
import { ColorGenerator } from '@/utils/color-generator';
|
||||
import { initMapbox, triggerLayerClick } from "@/utils/mapbox-utils";
|
||||
|
||||
|
|
@ -464,7 +464,7 @@ export default {
|
|||
item.highlight = false
|
||||
item.show = true
|
||||
// 加载轨迹图层
|
||||
loadVectorLayer(item.voyage_name, ["line", "symbol"], [colors[i], colors[i]], "visible", "dataSearchMap", "dsds");
|
||||
loadVectorLayer({ layerId: item.voyage_name, features: ["line", "symbol"], colors: [colors[i], colors[i]], visibility: "visible", mapId: "dataSearchMap", workspace: "dsds" });
|
||||
i++;
|
||||
})
|
||||
}
|
||||
|
|
@ -487,14 +487,6 @@ export default {
|
|||
},
|
||||
// 清除高亮
|
||||
clearHighlight(voyageName, i) {
|
||||
let lineWidthExpression = [
|
||||
"case",
|
||||
["boolean", ["feature-state", "hover"], false],
|
||||
4,
|
||||
["boolean", ["feature-state", "click"], false],
|
||||
2,
|
||||
1.8
|
||||
];
|
||||
Vue.config.maps["dataSearchMap"].setPaintProperty(`vector-${voyageName}-line`, "line-width", lineWidthExpression);
|
||||
this.dataList[i].highlight = false;
|
||||
},
|
||||
|
|
@ -540,11 +532,13 @@ export default {
|
|||
let i = 0;
|
||||
const colors = ColorGenerator.generateDivergingColors(arr.length);
|
||||
arr.forEach(item => {
|
||||
// 加载测线/站位所在航次的轨迹
|
||||
// loadVectorLayer({layerId:item.voyage_name, features:["line", "symbol"], colors:[colors[i], colors[i]], visibility:"visible", mapId:"dataSearchMap", workspace:"dsds"});
|
||||
// 添加测线/站位图层
|
||||
if (item.job_type == "测线作业") {
|
||||
loadVectorLayer(`sample_line_${item.dataset_name}`, ["line"], ["#FFFFFF", "#FFFFFF"], "visible", "dataSearchMap", "dsds", "sample_name");
|
||||
loadVectorLayer({ layerId: `sample_line_${item.dataset_name}`, features: ["line"], colors: ["#FFFFFF", "#FFFFFF"], visibility: "visible", mapId: "dataSearchMap", workspace: "dsds", textField: "sample_name", callbackOnClick: this.setHightItem });
|
||||
} else {
|
||||
loadVectorLayer(`sample_station_${item.dataset_name}`, ["symbol"], ["#FFFFFF", "#FFFFFF"], "visible", "dataSearchMap", "dsds", "sample_name");
|
||||
loadVectorLayer({ layerId: `sample_station_${item.dataset_name}`, features: ["symbol"], colors: ["#FFFFFF", "#FFFFFF"], visibility: "visible", mapId: "dataSearchMap", workspace: "dsds", textField: "sample_name", callbackOnClick: this.setHightItem });
|
||||
}
|
||||
i++;
|
||||
})
|
||||
|
|
@ -570,6 +564,13 @@ export default {
|
|||
this.dataList = voyageList
|
||||
},
|
||||
|
||||
setHightItem(item) {
|
||||
// 单击地图上的样品后,在左侧列表中高亮对应项
|
||||
this.currenSample = item.properties.tsy_id;
|
||||
// this.currenId = item.properties.tsy_id;
|
||||
console.log("clicked item:", item);
|
||||
},
|
||||
|
||||
turnDeatilPage(item) {
|
||||
this.dialog5 = true
|
||||
regInfo({ voyage_name: item.voyage_name }).then(res => {
|
||||
|
|
@ -647,9 +648,14 @@ export default {
|
|||
});
|
||||
let layerId = `vector-${job_type == "测线作业" ? "sample_line" : "sample_station"}_${sample.dataset_name}-${job_type == "测线作业" ? "line" : "symbol"}`;
|
||||
let sourceLayerId = `${job_type == "测线作业" ? "sample_line" : "sample_station"}_${sample.dataset_name}`;
|
||||
// triggerLayerClick("dataSearchMap", sourceLayerId, layerId, [lon, lat], { "sample_name": sample.sample_name });
|
||||
// 单击样品时,同步在地图上显示样品信息弹窗
|
||||
showHighlightSampleInfo({ mapId: "dataSearchMap", job_type, sample, layerId, sourceLayerId });
|
||||
// 将选中的图层移动到最顶层,传入 undefined 作为第二个参数即可
|
||||
Vue.config.maps["dataSearchMap"].moveLayer(layerId, undefined);
|
||||
|
||||
// vector-sample_station_TS-46-1_FDZ377_Slurp_SWYP-symbol、vector-sample_line_TS2-29-1_SY612_GQXJ_PJZP-line
|
||||
// highlightFeaturesByProperty("dataSearchMap", `${job_type == "测线作业" ? "sample_line" : "sample_station"}_${sample.dataset_name}`, layerId, "sample_name", sample.sample_name);
|
||||
triggerLayerClick("dataSearchMap", sourceLayerId, layerId, [lon, lat], { "sample_name": sample.sample_name });
|
||||
},
|
||||
goHome() {
|
||||
this.$router.push({ name: 'home' })
|
||||
|
|
|
|||
|
|
@ -328,8 +328,8 @@ export default {
|
|||
// 加载海岸线
|
||||
// loadVectorLayer("GSHHS_f_L1", ["line"], ["#FEFEFE"], "homeMap", 'ougp');
|
||||
// 加载等深线(默认不显示)
|
||||
loadVectorLayer("contour-4500m", ["line"], ["#FEFEFE"], "none", "homeMap", 'ougp');
|
||||
loadVectorLayer("contour-6000m", ["line"], ["#FEFEFE"], "none", "homeMap", 'ougp');
|
||||
loadVectorLayer({ layerId: "contour-4500m", features: ["line"], colors: ["#FEFEFE"], visibility: "none", mapId: "homeMap", workspace: 'ougp' });
|
||||
loadVectorLayer({ layerId: "contour-6000m", features: ["line"], colors: ["#FEFEFE"], visibility: "none", mapId: "homeMap", workspace: 'ougp' });
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
|
|
@ -345,7 +345,7 @@ export default {
|
|||
const colors = ColorGenerator.generateDivergingColors(this.voyageList.length);
|
||||
this.voyageList.forEach(element => {
|
||||
// 加载轨迹图层
|
||||
loadVectorLayer(element.voyage_name, ["line", "symbol"], [colors[i], colors[i]], "visible", "homeMap", "dsds");
|
||||
loadVectorLayer({ layerId: element.voyage_name, features: ["line", "symbol"], colors: [colors[i], colors[i]], visibility: "visible", mapId: "homeMap", workspace: "dsds" });
|
||||
i++;
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -235,7 +235,7 @@ export default {
|
|||
// 添加轨迹图层
|
||||
res.array.forEach(item => {
|
||||
// 加载轨迹图层
|
||||
loadVectorLayer(item.diving_sn, ["line", "symbol"], [colors[i], "#FFFFFF"], "visible", "voyageMap_auv", "dsds");
|
||||
loadVectorLayer({ layerId: item.diving_sn, features: ["line", "symbol"], colors: [colors[i], "#FFFFFF"], visibility: "visible", mapId: "voyageMap_auv", worksapce: "dsds" });
|
||||
i++;
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -235,7 +235,7 @@ export default {
|
|||
const colors = ColorGenerator.generateDivergingColors(res.array.length);
|
||||
res.array.forEach(item => {
|
||||
// 加载下潜轨迹
|
||||
loadVectorLayer(item.diving_sn, ["line", "symbol"], [colors[i], "#FFFFFF"], "visible", "voyageMap_hov", "dsds");
|
||||
loadVectorLayer({ layerId: item.diving_sn, features: ["line", "symbol"], colors: [colors[i], "#FFFFFF"], visibility: "visible", mapId: "voyageMap_hov", workspace: "dsds" });
|
||||
i++;
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -235,7 +235,7 @@ export default {
|
|||
// 添加轨迹图层
|
||||
res.array.forEach(item => {
|
||||
// 加载轨迹图层
|
||||
loadVectorLayer(item.diving_sn, ["line", "symbol"], [colors[i], "#FFFFFF"], "visible", "voyageMap_rov", "dsds");
|
||||
loadVectorLayer({ layerId: item.diving_sn, features: ["line", "symbol"], colors: [colors[i], "#FFFFFF"], visibility: "visible", mapId: "voyageMap_rov", workspace: "dsds" });
|
||||
i++;
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -250,7 +250,7 @@ export default {
|
|||
// 添加轨迹图层
|
||||
res.array.forEach(item => {
|
||||
// 加载轨迹图层(已存在则设置为可见)
|
||||
loadVectorLayer(item.voyage_name, ['line', 'symbol'], [colors[i], '#FFFFFF'], 'visible', 'voyageMap_ship', 'dsds')
|
||||
loadVectorLayer({ layerId: item.voyage_name, features: ['line', 'symbol'], colors: [colors[i], '#FFFFFF'], visibility: 'visible', mapId: 'voyageMap_ship', workspace: 'dsds' })
|
||||
i++
|
||||
})
|
||||
})
|
||||
|
|
|
|||
Loading…
Reference in New Issue