优化
This commit is contained in:
@@ -51,7 +51,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// import { throttle } from 'lodash'
|
||||
import { throttle } from 'lodash'
|
||||
import markerImage from '@images/new/agv.png'
|
||||
import { getMapInfoByCode, getRouteInfo, queryMapAllStation } from '@config/getData.js'
|
||||
import canvasZoomDrag from '@config/canvasZoomDrag'
|
||||
@@ -66,12 +66,21 @@ export default {
|
||||
showPopup: false,
|
||||
selectedPoint: {},
|
||||
popupStyle: {left: '0px', top: '0px'},
|
||||
selectedPointId: null
|
||||
selectedPointId: null,
|
||||
cachedImages: {
|
||||
map: null,
|
||||
marker: null
|
||||
},
|
||||
imageLoadStatus: {
|
||||
map: false,
|
||||
marker: false
|
||||
}
|
||||
}
|
||||
},
|
||||
mixins: [canvasZoomDrag],
|
||||
mounted () {
|
||||
this._getMapInfoByCode()
|
||||
this.preloadMarkerImage()
|
||||
this.loadAllDataInParallel()
|
||||
document.addEventListener('click', this.handleDocumentClick)
|
||||
},
|
||||
beforeDestroy () {
|
||||
@@ -79,49 +88,119 @@ export default {
|
||||
document.removeEventListener('click', this.handleDocumentClick)
|
||||
},
|
||||
methods: {
|
||||
preloadMarkerImage () {
|
||||
if (this.cachedImages.marker) {
|
||||
this.imageLoadStatus.marker = true
|
||||
return
|
||||
}
|
||||
const img = new Image()
|
||||
img.src = markerImage
|
||||
img.onload = () => {
|
||||
this.cachedImages.marker = img
|
||||
this.imageLoadStatus.marker = true
|
||||
this.checkImagesLoadedAndRedraw()
|
||||
}
|
||||
img.onerror = () => {
|
||||
console.error('标记图片加载失败')
|
||||
this.imageLoadStatus.marker = true
|
||||
this.checkImagesLoadedAndRedraw()
|
||||
}
|
||||
},
|
||||
loadMapImage () {
|
||||
if (!this.mapData.mapImageAddress) {
|
||||
return Promise.reject(new Error('地图数据缺失'))
|
||||
}
|
||||
if (this.cachedImages.map && this.imageLoadStatus.map) {
|
||||
return Promise.resolve(this.cachedImages.map)
|
||||
}
|
||||
return new Promise((resolve, reject) => {
|
||||
const img = new Image()
|
||||
img.src = `${this.$store.getters.baseUrl}${this.mapData.mapImageAddress}`
|
||||
// img.src = this.mapData.mapImageAddress
|
||||
img.onload = () => {
|
||||
this.cachedImages.map = img
|
||||
this.imageLoadStatus.map = true
|
||||
this.checkImagesLoadedAndRedraw()
|
||||
resolve(img)
|
||||
}
|
||||
img.onerror = (error) => {
|
||||
console.error('地图图片加载失败:', error)
|
||||
this.imageLoadStatus.map = true
|
||||
reject(error)
|
||||
}
|
||||
})
|
||||
},
|
||||
checkImagesLoadedAndRedraw () {
|
||||
if (this.imageLoadStatus.map && this.imageLoadStatus.marker) {
|
||||
this.redrawCanvas()
|
||||
}
|
||||
},
|
||||
async loadAllDataInParallel () {
|
||||
try {
|
||||
this.loading = this.$loading({
|
||||
lock: true,
|
||||
spinner: 'el-icon-loading',
|
||||
background: 'rgba(0, 0, 0, 0.6)'
|
||||
})
|
||||
const [mapData, pathData, stations] = await Promise.all([
|
||||
this._getMapInfoByCode(),
|
||||
this._getRouteInfo(),
|
||||
this._queryMapAllStation()
|
||||
])
|
||||
this.mapData = mapData
|
||||
this.pathData = [...pathData]
|
||||
this.pointData = this.filterPointData(pathData, stations)
|
||||
this.initCanvas()
|
||||
await this.loadMapImage()
|
||||
this.loading.close()
|
||||
} catch (e) {
|
||||
this.$message.error(`数据加载失败: ${e.message || '未知错误'}`)
|
||||
this.loading.close()
|
||||
}
|
||||
},
|
||||
async _getMapInfoByCode () {
|
||||
try {
|
||||
let res = await getMapInfoByCode()
|
||||
if (res) {
|
||||
this.mapData = res
|
||||
this._getRouteInfo()
|
||||
}
|
||||
const res = await getMapInfoByCode()
|
||||
if (!res) throw new Error('地图信息为空')
|
||||
return res
|
||||
} catch (e) {
|
||||
this.$message.error(e)
|
||||
console.error('获取地图信息失败:', e)
|
||||
throw new Error(`获取地图信息失败: ${e.message}`)
|
||||
}
|
||||
},
|
||||
async _getRouteInfo () {
|
||||
try {
|
||||
let res = await getRouteInfo()
|
||||
this.pathData = [...res]
|
||||
this._queryMapAllStation()
|
||||
const res = await getRouteInfo()
|
||||
if (!res) throw new Error('路径信息为空')
|
||||
return res
|
||||
} catch (e) {
|
||||
this.$message.error(e)
|
||||
console.error('获取路径信息失败:', e)
|
||||
throw new Error(`获取路径信息失败: ${e.message}`)
|
||||
}
|
||||
},
|
||||
async _queryMapAllStation () {
|
||||
try {
|
||||
let res = await queryMapAllStation()
|
||||
const stations = [...res]
|
||||
this.pointData = this.filterPointData(this.pathData, stations)
|
||||
this.initCanvas()
|
||||
const res = await queryMapAllStation()
|
||||
if (!res) throw new Error('站点信息为空')
|
||||
return res
|
||||
} catch (e) {
|
||||
this.$message.error(e)
|
||||
console.error('获取站点信息失败:', e)
|
||||
throw new Error(`获取站点信息失败: ${e.message}`)
|
||||
}
|
||||
},
|
||||
filterPointData (routes, stations) {
|
||||
const result = []
|
||||
const seenStationIds = new Set()
|
||||
routes.forEach((route) => {
|
||||
const startStation = stations.find((station) => station.station_id === route.start_id)
|
||||
const endStation = stations.find((station) => station.station_id === route.end_id)
|
||||
routes.forEach(route => {
|
||||
const startStation = stations.find(s => s.station_id === route.start_id)
|
||||
const endStation = stations.find(s => s.station_id === route.end_id)
|
||||
if (startStation && !seenStationIds.has(startStation.station_id)) {
|
||||
result.push(startStation)
|
||||
seenStationIds.add(startStation.station_id)
|
||||
}
|
||||
if (endStation && !seenStationIds.has(endStation.station_id)) {
|
||||
result.push(endStation)
|
||||
seenStationIds.add(endStation.station_id) // 标记为已添加
|
||||
seenStationIds.add(endStation.station_id)
|
||||
}
|
||||
})
|
||||
return result
|
||||
@@ -133,19 +212,28 @@ export default {
|
||||
this.canvas.height = this.mapData.height
|
||||
this.redrawCanvas()
|
||||
},
|
||||
redrawCanvas () {
|
||||
redrawCanvas: throttle(function () {
|
||||
if (!this.ctx || !this.mapData) return
|
||||
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height)
|
||||
const img = new Image()
|
||||
img.src = `${this.$store.getters.baseUrl}${this.mapData.mapImageAddress}`
|
||||
// img.src = `${this.mapData.mapImageAddress}`
|
||||
img.onload = () => {
|
||||
this.ctx.drawImage(img, 0, 0, this.canvas.width, this.canvas.height)
|
||||
this.ctx.save()
|
||||
this.drawPath()
|
||||
this.drawMarkers()
|
||||
this.ctx.save()
|
||||
// 绘制地图背景
|
||||
if (this.cachedImages.map) {
|
||||
this.ctx.drawImage(
|
||||
this.cachedImages.map,
|
||||
0, 0,
|
||||
this.canvas.width,
|
||||
this.canvas.height
|
||||
)
|
||||
} else {
|
||||
this.ctx.fillStyle = '#ccc'
|
||||
this.ctx.fillText('地图加载中...', 50, 50)
|
||||
}
|
||||
},
|
||||
this.drawPath()
|
||||
this.drawMarkers()
|
||||
this.ctx.restore()
|
||||
}, 30),
|
||||
drawPath () {
|
||||
if (!this.pathData.length) return
|
||||
this.ctx.beginPath()
|
||||
this.pathData.forEach((point, index) => {
|
||||
const startX = (point.start_x - this.mapData.x) / this.mapData.resolution
|
||||
@@ -154,32 +242,38 @@ export default {
|
||||
const endY = this.mapData.height - (point.end_y - this.mapData.y) / this.mapData.resolution
|
||||
this.ctx.moveTo(startX, startY)
|
||||
this.ctx.lineTo(endX, endY)
|
||||
this.ctx.strokeStyle = '#009de5'
|
||||
this.ctx.lineWidth = 3
|
||||
this.ctx.stroke()
|
||||
})
|
||||
this.ctx.strokeStyle = '#009de5'
|
||||
this.ctx.lineWidth = 2
|
||||
this.ctx.stroke()
|
||||
},
|
||||
drawMarkers () {
|
||||
const markerImg = new Image()
|
||||
markerImg.src = markerImage
|
||||
markerImg.onload = () => {
|
||||
this.pointData.forEach(point => {
|
||||
const x = (point.x - this.mapData.x) / this.mapData.resolution
|
||||
const y = this.mapData.height - (point.y - this.mapData.y) / this.mapData.resolution
|
||||
if (point.station_id === this.selectedPointId) {
|
||||
this.ctx.beginPath()
|
||||
this.ctx.arc(x, y, 5, 0, Math.PI * 2)
|
||||
this.ctx.fillStyle = '#59ccd2'
|
||||
this.ctx.fill()
|
||||
} else {
|
||||
this.ctx.drawImage(markerImg, x - 5, y - 5, 10, 10)
|
||||
}
|
||||
this.ctx.font = '12px Arial'
|
||||
this.ctx.fillStyle = 'white'
|
||||
this.ctx.textAlign = 'center'
|
||||
this.ctx.fillText(point.station_name, x, y + 18)
|
||||
})
|
||||
}
|
||||
if (!this.pointData.length) return
|
||||
const markerSize = 10 // 标记大小随缩放变化
|
||||
this.pointData.forEach(point => {
|
||||
const x = (point.x - this.mapData.x) / this.mapData.resolution
|
||||
const y = this.mapData.height - (point.y - this.mapData.y) / this.mapData.resolution
|
||||
// 绘制选中状态
|
||||
if (point.station_id === this.selectedPointId) {
|
||||
this.ctx.beginPath()
|
||||
this.ctx.arc(x, y, 5, 0, Math.PI * 2)
|
||||
this.ctx.fillStyle = '#59ccd2'
|
||||
this.ctx.fill()
|
||||
} else if (this.cachedImages.marker) {
|
||||
this.ctx.drawImage(
|
||||
this.cachedImages.marker,
|
||||
x - markerSize / 2, // 居中对齐
|
||||
y - markerSize / 2,
|
||||
markerSize,
|
||||
markerSize
|
||||
)
|
||||
}
|
||||
// 绘制点位名称(文字大小随缩放变化)
|
||||
this.ctx.font = '12px Arial'
|
||||
this.ctx.fillStyle = 'white'
|
||||
this.ctx.textAlign = 'center'
|
||||
this.ctx.fillText(point.station_name, x, y + 18)
|
||||
})
|
||||
},
|
||||
handleCanvasClick (event) {
|
||||
const rect = this.canvas.getBoundingClientRect()
|
||||
@@ -192,22 +286,34 @@ export default {
|
||||
y = Math.abs(y) === 0 ? 0 : y
|
||||
// 检查点击位置是否在标记图片内
|
||||
if (mouseX >= x - 10 && mouseX <= x + 10 && mouseY >= y - 10 && mouseY <= y + 10) {
|
||||
if (this.selectedPointId === point.station_id) {
|
||||
this.resetSelection()
|
||||
} else {
|
||||
this.selectedPointId = point.station_id
|
||||
this.selectedPoint = point
|
||||
this.showPopup = true
|
||||
this.popupStyle = {
|
||||
left: `${event.clientX - 40}px`,
|
||||
top: `${event.clientY - 150}px`
|
||||
}
|
||||
this.initCanvas()
|
||||
event.stopPropagation()
|
||||
}
|
||||
this.handlePointSelect(point, event)
|
||||
event.stopPropagation()
|
||||
}
|
||||
})
|
||||
},
|
||||
handlePointSelect (point, event) {
|
||||
if (this.selectedPointId === point.station_id) {
|
||||
this.resetSelection()
|
||||
} else {
|
||||
this.selectedPointId = point.station_id
|
||||
this.selectedPoint = point
|
||||
this.showPopup = true
|
||||
this.calculatePopupPosition(event)
|
||||
this.redrawCanvas()
|
||||
}
|
||||
},
|
||||
calculatePopupPosition (event) {
|
||||
const popupWidth = 200
|
||||
const popupHeight = 180
|
||||
let left = event.clientX - 40
|
||||
let top = event.clientY - 150
|
||||
|
||||
// 限制弹窗在窗口可视范围内
|
||||
left = Math.max(10, Math.min(left, window.innerWidth - popupWidth - 10))
|
||||
top = Math.max(10, Math.min(top, window.innerHeight - popupHeight - 10))
|
||||
|
||||
this.popupStyle = { left: `${left}px`, top: `${top}px` }
|
||||
},
|
||||
handleDocumentClick () {
|
||||
this.resetSelection()
|
||||
},
|
||||
@@ -216,7 +322,7 @@ export default {
|
||||
this.selectedPointId = null
|
||||
this.selectedPoint = null
|
||||
this.showPopup = false
|
||||
this.initCanvas()
|
||||
this.redrawCanvas()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user