|
|
@@ -13,7 +13,6 @@ import DestinationIcon from '../images/destinationIcon.png'
|
|
|
import OriginIcon from '../images/originIcon.png'
|
|
|
import TransferIcon from '../images/transferIcon.png'
|
|
|
import { onMounted, ref, watch } from 'vue'
|
|
|
-import * as turf from '@turf/turf'
|
|
|
import { useThemeStore } from '@/stores/modules/theme'
|
|
|
|
|
|
const themeStore = useThemeStore()
|
|
|
@@ -63,179 +62,6 @@ const initMap = () => {
|
|
|
}).addTo(map)
|
|
|
}
|
|
|
|
|
|
-// 修正经度
|
|
|
-const fixLng = (lng: number) => {
|
|
|
- while (lng > 180) lng = lng - 360
|
|
|
- while (lng <= -180) lng = lng + 360
|
|
|
- return lng
|
|
|
-}
|
|
|
-const getBBox = () => {
|
|
|
- let bnd = map.getBounds()
|
|
|
- let ww = bnd.getEast() - bnd.getWest()
|
|
|
- let cent_pt = map.getCenter()
|
|
|
- let bbox = [
|
|
|
- fixLng(cent_pt.lng - ww / 2),
|
|
|
- bnd.getSouth(),
|
|
|
- fixLng(cent_pt.lng + ww / 2),
|
|
|
- bnd.getNorth()
|
|
|
- ]
|
|
|
-
|
|
|
- let bbox2 = []
|
|
|
- let bbox3 = []
|
|
|
- if (ww > 360) {
|
|
|
- bbox[0] = -180
|
|
|
- bbox[2] = 0
|
|
|
-
|
|
|
- bbox2[0] = 0
|
|
|
- bbox2[1] = bbox[1]
|
|
|
- bbox2[2] = 180
|
|
|
- bbox2[3] = bbox[3]
|
|
|
- }
|
|
|
- if (bbox[2] * bbox[0] < 0 || bbox[2] < bbox[0]) {
|
|
|
- if (bbox[0] >= 0) {
|
|
|
- bbox2[0] = -180
|
|
|
- bbox2[2] = bbox[2]
|
|
|
- bbox2[1] = bbox[1]
|
|
|
- bbox2[3] = bbox[3]
|
|
|
- bbox[2] = 180
|
|
|
- } else {
|
|
|
- bbox2[0] = 0
|
|
|
- bbox2[2] = bbox[2]
|
|
|
- bbox2[1] = bbox[1]
|
|
|
- bbox2[3] = bbox[3]
|
|
|
- bbox[2] = 0
|
|
|
- }
|
|
|
- }
|
|
|
- if (bbox2[2] * bbox2[0] < 0 || bbox2[2] < bbox2[0]) {
|
|
|
- if (bbox2[0] >= 0) {
|
|
|
- bbox3[0] = -180
|
|
|
- bbox3[2] = bbox2[2]
|
|
|
- bbox3[1] = bbox2[1]
|
|
|
- bbox3[3] = bbox2[3]
|
|
|
- bbox2[2] = 180
|
|
|
- } else {
|
|
|
- bbox3[0] = 0
|
|
|
- bbox3[2] = bbox2[2]
|
|
|
- bbox3[1] = bbox2[1]
|
|
|
- bbox3[3] = bbox2[3]
|
|
|
- bbox2[2] = 0
|
|
|
- }
|
|
|
- }
|
|
|
- let ll = []
|
|
|
- ll.push(bbox)
|
|
|
-
|
|
|
- if (bbox2.length > 0) ll.push(bbox2)
|
|
|
- if (bbox3.length > 0) ll.push(bbox3)
|
|
|
- return ll
|
|
|
-}
|
|
|
-let track_added_marker = []
|
|
|
-
|
|
|
-const clear_marker = () => {
|
|
|
- track_added_marker.forEach((v) => {
|
|
|
- map!.removeLayer(v)
|
|
|
- })
|
|
|
-
|
|
|
- track_added_marker = []
|
|
|
-}
|
|
|
-const draw_marker = (dottedLine = [], solidLine = []) => {
|
|
|
- clear_marker()
|
|
|
- dottedLine.forEach((l) => {
|
|
|
- addMapLine(l, true, { color: '#ff7500', weight: 2 })
|
|
|
- })
|
|
|
- solidLine.forEach((l) => {
|
|
|
- addMapLine(l, false, { color: '#ff7500', weight: 2 })
|
|
|
- })
|
|
|
-}
|
|
|
-const addMapLine = (l, IsDash, opts) => {
|
|
|
- let mpts = l.pts
|
|
|
- if (mpts == null || mpts.length == 0) return
|
|
|
-
|
|
|
- let bnd = map.getBounds()
|
|
|
- let ww = bnd.getEast() - bnd.getWest()
|
|
|
- let cc = Math.ceil(ww / 360)
|
|
|
-
|
|
|
- let boxlist = getBBox()
|
|
|
-
|
|
|
- let ll = []
|
|
|
-
|
|
|
- for (let ii = 0; ii < mpts.length; ii++) {
|
|
|
- ll[ii] = [mpts[ii][1], mpts[ii][0]]
|
|
|
- }
|
|
|
- let pline = turf.lineString(ll, { name: '' })
|
|
|
- let level = map.getZoom()
|
|
|
- let options = {
|
|
|
- tolerance:
|
|
|
- Math.round(
|
|
|
- ((level < 8 ? 0.0005 : level < 12 ? 0.00005 : 0) / (level == 0 ? 1 : level)) * 1000000
|
|
|
- ) / 1000000,
|
|
|
- highQuality: false
|
|
|
- }
|
|
|
- let simplified = turf.simplify(pline, options)
|
|
|
-
|
|
|
- let lines_list = []
|
|
|
- let clipped: any = simplified
|
|
|
- boxlist.forEach((bbox) => {
|
|
|
- let bb = bbox
|
|
|
- clipped = turf.bboxClip(simplified, bb)
|
|
|
- if (clipped != null) {
|
|
|
- if (clipped.geometry.type === 'LineString') {
|
|
|
- let line_pts = clipped.geometry.coordinates
|
|
|
- let pta = []
|
|
|
- let jj = 0
|
|
|
- for (let ii = 0; ii < line_pts.length; ii++) {
|
|
|
- pta[jj++] = [line_pts[ii][1], line_pts[ii][0]]
|
|
|
- }
|
|
|
- lines_list.push(pta)
|
|
|
- } else if (clipped.geometry.type === 'MultiLineString') {
|
|
|
- clipped.geometry.coordinates.forEach((_pts) => {
|
|
|
- let line_pts = _pts
|
|
|
- let pta = []
|
|
|
- let jj = 0
|
|
|
- for (let ii = 0; ii < line_pts.length; ii++) {
|
|
|
- pta[jj++] = [line_pts[ii][1], line_pts[ii][0]]
|
|
|
- }
|
|
|
- lines_list.push(pta)
|
|
|
- })
|
|
|
- }
|
|
|
- }
|
|
|
- })
|
|
|
-
|
|
|
- let cc1 = Math.floor(bnd.getWest() / 360)
|
|
|
- let cc2 = Math.ceil(bnd.getEast() / 360)
|
|
|
- cc = cc2 - cc1 + 1
|
|
|
-
|
|
|
- let kk = cc1
|
|
|
- // let lines_list = [mpts]
|
|
|
- while (kk >= cc1 && kk <= cc2 && cc > 0) {
|
|
|
- lines_list.forEach((a) => {
|
|
|
- let ii = 0
|
|
|
- let jj = 0
|
|
|
- let pts = []
|
|
|
- for (ii = 0; ii < a.length; ii++) pts[jj++] = [a[ii][0], a[ii][1] + kk * 360]
|
|
|
-
|
|
|
- if (jj > 0) {
|
|
|
- if (IsDash) {
|
|
|
- showTrackLine(
|
|
|
- pts,
|
|
|
- jj,
|
|
|
- Object.assign({}, { color: '#ff7500', dashArray: '10', weight: 2 }, opts)
|
|
|
- )
|
|
|
- } else {
|
|
|
- showTrackLine(pts, jj, Object.assign({}, { color: '#ff7500', weight: 1 }, opts))
|
|
|
- }
|
|
|
- }
|
|
|
- })
|
|
|
-
|
|
|
- kk++
|
|
|
- cc--
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-const showTrackLine = (pts, jj, opts) => {
|
|
|
- let arrow = L.polyline(pts, Object.assign({}, { color: '#ff7500', weight: 2 }, opts)).addTo(map)
|
|
|
- track_added_marker.push(arrow)
|
|
|
-}
|
|
|
-
|
|
|
const addResetZoomButton = (center: L.LatLng, zoom: number) => {
|
|
|
const ResetZoomControl = L.Control.extend({
|
|
|
options: {
|
|
|
@@ -272,7 +98,6 @@ let initialZoomLevel: number | null = null
|
|
|
let isFirstRender = true // 标记是否为首次渲染
|
|
|
|
|
|
let allMarkers = []
|
|
|
-let visibleMarkers = new Set()
|
|
|
|
|
|
// 添加标记后更新中心和缩放级别
|
|
|
const addMarkersToMap = () => {
|
|
|
@@ -300,8 +125,6 @@ const addMarkersToMap = () => {
|
|
|
allMarkers[`${position.lat},${position.lng}`] = marker
|
|
|
})
|
|
|
|
|
|
- updateVisibleMarkers()
|
|
|
-
|
|
|
if (viewData.value.length > 0) {
|
|
|
// 根据标记的位置设置中心点以及缩放级别
|
|
|
const bounds = L.latLngBounds(viewData.value)
|
|
|
@@ -313,154 +136,10 @@ const addMarkersToMap = () => {
|
|
|
isFirstRender = false
|
|
|
}
|
|
|
addResetZoomButton(initialCenter!, initialZoomLevel!)
|
|
|
- }, 1000)
|
|
|
+ }, 500)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-// 新增轮船当前位置标记
|
|
|
-const addShipMarker = (x: number) => {
|
|
|
- const solidLine = allMapData.value.solidLine
|
|
|
- // 如果轮船还未出发,则显示起点轮船标记
|
|
|
- if (solidLine.length === 0) {
|
|
|
- // 创建轮船图标
|
|
|
- const arrowIcon = L.divIcon({
|
|
|
- html: `
|
|
|
- <div class="container">
|
|
|
- <div class="circle"></div>
|
|
|
- <span style="padding: 0; color:white; border:1px solid white" class="font_family icon-icon_ocean_b"></span>
|
|
|
- </div>
|
|
|
- `,
|
|
|
- className: 'arrow-icon',
|
|
|
- iconSize: [50, 50],
|
|
|
- iconAnchor: [25, 25], // 箭头的中心点
|
|
|
- popupAnchor: [0, -25] // 弹出框的锚点
|
|
|
- })
|
|
|
-
|
|
|
- let curMarkerLocation = markerPositions.value.find((item) => item.label === 'Origin')
|
|
|
- const arrowMarker = L.marker([curMarkerLocation.lat, curMarkerLocation.lng + x * 360], {
|
|
|
- icon: arrowIcon
|
|
|
- }).addTo(map)
|
|
|
- track_added_marker.push(arrowMarker)
|
|
|
- } else if (solidLine.length > 0) {
|
|
|
- // 如果轮船已经出发,则显示轮船当前位置标记
|
|
|
- // 如果线段至少有两个点,才添加箭头
|
|
|
- // 获取线段的最后一个点和倒数第二个点
|
|
|
- const lastPoint = solidLine[solidLine.length - 1]
|
|
|
- const secondLastPoint = solidLine[solidLine.length - 2]
|
|
|
- // 计算线段末端的角度(以弧度为单位)
|
|
|
- const angle =
|
|
|
- (Math.atan2(
|
|
|
- Number(lastPoint.lon) - Number(secondLastPoint.lon), // Δlon (x)
|
|
|
- Number(lastPoint.lat) - Number(secondLastPoint.lat) // Δlat (y)
|
|
|
- ) *
|
|
|
- (180 / Math.PI) +
|
|
|
- 360) %
|
|
|
- 360
|
|
|
- // 创建自定义箭头图标
|
|
|
- const arrowIcon = L.divIcon({
|
|
|
- html: `
|
|
|
- <div style="transform: rotate(${angle}deg);" class="container">
|
|
|
- <div class="circle"></div>
|
|
|
- <span style="color:white;border:1px solid white" class="font_family icon-icon_arrow_b"></span>
|
|
|
- </div>
|
|
|
- `,
|
|
|
- className: 'arrow-icon',
|
|
|
- iconSize: [50, 50],
|
|
|
- iconAnchor: [25, 25], // 箭头的中心点
|
|
|
- popupAnchor: [0, -25] // 弹出框的锚点
|
|
|
- })
|
|
|
- // 创建箭头标记,并根据计算出的角度旋转箭头
|
|
|
- const arrowMarker = L.marker([Number(lastPoint.lat), Number(lastPoint.lon) + x * 360], {
|
|
|
- icon: arrowIcon
|
|
|
- }).addTo(map)
|
|
|
- // 将箭头标记也存储在 track_added_marker 数组中,以便后续管理
|
|
|
- track_added_marker.push(arrowMarker)
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-// 更新可见标记
|
|
|
-const updateVisibleMarkers = () => {
|
|
|
- const newVisibleMarkers = new Set()
|
|
|
-
|
|
|
- let bnd = map.getBounds()
|
|
|
- let ww = bnd.getEast() - bnd.getWest()
|
|
|
-
|
|
|
- let cc = Math.ceil(ww / 360)
|
|
|
-
|
|
|
- let cc1 = Math.floor(bnd.getWest() / 360)
|
|
|
- let cc2 = Math.ceil(bnd.getEast() / 360)
|
|
|
- cc = cc2 - cc1 + 1
|
|
|
-
|
|
|
- let x = cc1
|
|
|
-
|
|
|
- // 移除不再可见的标记
|
|
|
- visibleMarkers.forEach((marker: any) => {
|
|
|
- if (!newVisibleMarkers.has(marker)) {
|
|
|
- map.removeLayer(marker)
|
|
|
- delete allMarkers[`${marker.getLatLng().lat},${marker._lng},${marker._x}`]
|
|
|
- }
|
|
|
- })
|
|
|
-
|
|
|
- // 计算当前视图中的标记,包括多地球的情况
|
|
|
- while (x >= cc1 && x <= cc2 && cc > 0) {
|
|
|
- Object.values(allMarkers).forEach((marker) => {
|
|
|
- const latLng = marker.getLatLng()
|
|
|
- const key = `${latLng.lat},${latLng.lng},${x}`
|
|
|
- if (!allMarkers[key]) {
|
|
|
- const newMarker: any = L.marker([latLng.lat, latLng.lng + x * 360], {
|
|
|
- icon: marker.options.icon
|
|
|
- })
|
|
|
- .bindPopup(marker.getPopup().getContent(), marker.getPopup().options)
|
|
|
- .openPopup()
|
|
|
- newMarker._x = x
|
|
|
- // 使用原始的经度作为标记的唯一标识
|
|
|
- newMarker._lng = latLng.lng
|
|
|
- allMarkers[key] = newMarker
|
|
|
- map.addLayer(newMarker)
|
|
|
- }
|
|
|
- newVisibleMarkers.add(allMarkers[key])
|
|
|
- })
|
|
|
-
|
|
|
- addShipMarker(x)
|
|
|
-
|
|
|
- x++
|
|
|
- cc--
|
|
|
- }
|
|
|
-
|
|
|
- // 更新可见标记集合
|
|
|
- visibleMarkers = newVisibleMarkers
|
|
|
-}
|
|
|
-
|
|
|
-// 处理得到的数据
|
|
|
-const handleData = (data) => {
|
|
|
- let key = 0
|
|
|
- let curLine = []
|
|
|
- let resultLine = []
|
|
|
- data.forEach((item, index) => {
|
|
|
- if (item.sn === '1' && key === 0) {
|
|
|
- key++
|
|
|
- curLine.push([Number(item.lat), Number(item.lon)])
|
|
|
- } else if (item.sn === '1' && key !== 0) {
|
|
|
- resultLine.push({
|
|
|
- name: key,
|
|
|
- pts: curLine
|
|
|
- })
|
|
|
- curLine = [[Number(item.lat), Number(item.lon)]]
|
|
|
- key++
|
|
|
- }
|
|
|
- if (item.sn !== '1') {
|
|
|
- curLine.push([Number(item.lat), Number(item.lon)])
|
|
|
- }
|
|
|
- if (index === data.length - 1 && item.sn !== '1') {
|
|
|
- resultLine.push({
|
|
|
- name: key,
|
|
|
- pts: curLine
|
|
|
- })
|
|
|
- }
|
|
|
- })
|
|
|
- return resultLine
|
|
|
-}
|
|
|
-
|
|
|
const allMapData = ref()
|
|
|
const viewData = ref([])
|
|
|
// 请求接口并处理标记
|
|
|
@@ -474,8 +153,8 @@ const getMarker = () => {
|
|
|
if (res.code === 200) {
|
|
|
allMapData.value = res.data
|
|
|
const { data } = res
|
|
|
- data?.point &&
|
|
|
- data?.point.forEach((item) => {
|
|
|
+ data &&
|
|
|
+ data.forEach((item) => {
|
|
|
const iconColorList = {
|
|
|
Destination: { color: '#24ca5a', icon: destinationIcon },
|
|
|
Origin: { color: '#ED6D00', icon: originIcon },
|
|
|
@@ -490,24 +169,10 @@ const getMarker = () => {
|
|
|
iconColor: iconColorList[item.label].color
|
|
|
})
|
|
|
})
|
|
|
- viewData.value = (data?.rangePoint.length > 0 ? data?.rangePoint : data?.point)?.map(
|
|
|
- (item) => {
|
|
|
- return [Number(item.lat), Number(item.lon || item.lng)]
|
|
|
- }
|
|
|
- )
|
|
|
- // 请求成功后添加标记,并动态添加重置按钮
|
|
|
+ viewData.value = data?.map((item) => {
|
|
|
+ return [Number(item.lat), Number(item.lng)]
|
|
|
+ }) // 请求成功后添加标记,并动态添加重置按钮
|
|
|
addMarkersToMap()
|
|
|
- if (data?.dottedLine) {
|
|
|
- draw_marker(handleData(data.dottedLine), handleData(data.solidLine))
|
|
|
- map.on('moveend', function () {
|
|
|
- draw_marker(handleData(data.dottedLine), handleData(data.solidLine))
|
|
|
- updateVisibleMarkers()
|
|
|
- })
|
|
|
- map.on('zoomend', function () {
|
|
|
- draw_marker(handleData(data.dottedLine), handleData(data.solidLine))
|
|
|
- updateVisibleMarkers()
|
|
|
- })
|
|
|
- }
|
|
|
}
|
|
|
})
|
|
|
}
|