CN-1484 feat: 地图事件开发
This commit is contained in:
@@ -23,9 +23,47 @@
|
||||
.subscriber-map {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
|
||||
.maplibregl-canvas:focus-visible {
|
||||
outline: none;
|
||||
}
|
||||
}
|
||||
.panel-chart__no-data {
|
||||
height: calc(100% - 46px);
|
||||
}
|
||||
}
|
||||
|
||||
.subscriber-map-point-tooltip {
|
||||
position: fixed;
|
||||
background-color: white;
|
||||
width: 200px;
|
||||
border: 1px solid #C5C5C5;
|
||||
box-shadow: -1px 1px 10px -1px rgba(205,205,205,0.85);
|
||||
border-radius: 2px;
|
||||
|
||||
.subscriber-map-point-tooltip__time {
|
||||
padding: 10px;
|
||||
font-size: 12px;
|
||||
color: #353636;
|
||||
font-weight: bold;
|
||||
}
|
||||
.subscriber-map-point-tooltip__coordinates {
|
||||
padding: 0 10px 10px;
|
||||
|
||||
.subscriber-map-point-tooltip__coordinate {
|
||||
display: flex;
|
||||
|
||||
.coordinate__label {
|
||||
width: 115px;
|
||||
font-size: 12px;
|
||||
color: #575757;
|
||||
}
|
||||
.coordinate__value {
|
||||
font-size: 12px;
|
||||
color: #353636;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,7 +98,7 @@ export const entityType = {
|
||||
app: 'app',
|
||||
domain: 'domain',
|
||||
ip: 'ip',
|
||||
subscribe: 'subscribe'
|
||||
subscriber: 'subscriber'
|
||||
}
|
||||
|
||||
export const knowledgeCardUpdateRecordType = {
|
||||
@@ -153,7 +153,7 @@ export const entityDetailTabConfig = [
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'subscribe',
|
||||
name: 'subscriber',
|
||||
config: [
|
||||
{ name: entityDetailTabsName.deviceInformation, label: 'entities.deviceInformation', icon: 'cn-icon cn-icon-device-info', tag: 0 },
|
||||
{ name: entityDetailTabsName.accountInformation, label: 'entities.accountInformation', icon: 'cn-icon cn-icon-account-info', tag: 0 },
|
||||
|
||||
@@ -17,6 +17,21 @@
|
||||
<chart-error v-if="showError" :content="errorMsg" />
|
||||
<div id="subscriberMap" class="subscriber-map"></div>
|
||||
</div>
|
||||
|
||||
<!-- 地图point悬浮框 -->
|
||||
<div class="subscriber-map-point-tooltip" v-if="tooltip.showTooltip" :style="{'left': `${tooltip.x}px`, 'top': `${tooltip.y}px`}">
|
||||
<div class="subscriber-map-point-tooltip__time">{{dateFormatByAppearance(currentPoint.stat_time)}}</div>
|
||||
<div class="subscriber-map-point-tooltip__coordinates">
|
||||
<div class="subscriber-map-point-tooltip__coordinate">
|
||||
<div class="coordinate__label">{{$t('overall.longitude')}}</div>
|
||||
<div class="coordinate__value">{{currentPoint.longitude}}</div>
|
||||
</div>
|
||||
<div class="subscriber-map-point-tooltip__coordinate">
|
||||
<div class="coordinate__label">{{$t('overall.latitude')}}</div>
|
||||
<div class="coordinate__value">{{currentPoint.latitude}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -28,9 +43,10 @@ import maplibregl from 'maplibre-gl'
|
||||
import mapStyle from './mapStyle'
|
||||
import axios from 'axios'
|
||||
import { api } from '@/utils/api'
|
||||
import 'maplibre-gl/dist/maplibre-gl.css'
|
||||
import _ from 'lodash'
|
||||
import { ref } from 'vue'
|
||||
import { getNowTime } from '@/utils/date-util'
|
||||
import { getNowTime, getSecond } from '@/utils/date-util'
|
||||
|
||||
export default {
|
||||
name: 'EntityDetailMap',
|
||||
@@ -39,22 +55,19 @@ export default {
|
||||
ChartError,
|
||||
ChartNoData
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
this.initMap()
|
||||
},
|
||||
methods: {
|
||||
initMap () {
|
||||
async initMap () {
|
||||
const _this = this
|
||||
const map = new maplibregl.Map({
|
||||
container: 'subscriberMap',
|
||||
style: mapStyle,
|
||||
center: [116.39, 39.9],
|
||||
zoom: 9,
|
||||
maxZoom: 12,
|
||||
minZoom: 4,
|
||||
center: this.center,
|
||||
maxZoom: this.maxZoom,
|
||||
minZoom: this.minZoom,
|
||||
zoom: 7,
|
||||
transformRequest: function (url, resourceType) {
|
||||
if (resourceType === 'Tile' && url.indexOf('https://api.maptiler.com/tiles/v3') > -1) {
|
||||
const urlParams = url.split('.pbf')[0].split('/')
|
||||
@@ -85,52 +98,102 @@ export default {
|
||||
}
|
||||
})
|
||||
|
||||
/* axios.get(`${api.entity.locationTrack}?resource=${this.entity.entityName}`).then(res => {
|
||||
|
||||
}) */
|
||||
this.toggleLoading(false)
|
||||
const res = {
|
||||
status: 200,
|
||||
data: {
|
||||
data: {
|
||||
result: [
|
||||
{
|
||||
stat_time: 1701259999,
|
||||
subscriber_id: '883849',
|
||||
subscriber_longitude: 116.29,
|
||||
subscriber_latitude: 39.8
|
||||
},
|
||||
{
|
||||
stat_time: 1701269999,
|
||||
subscriber_id: '883849',
|
||||
subscriber_longitude: 116.34,
|
||||
subscriber_latitude: 39.85
|
||||
},
|
||||
{
|
||||
stat_time: 1701279999,
|
||||
subscriber_id: '883849',
|
||||
subscriber_longitude: 116.29,
|
||||
subscriber_latitude: 39.9
|
||||
},
|
||||
{
|
||||
stat_time: 1701299999,
|
||||
subscriber_id: '883849',
|
||||
subscriber_longitude: 116.39,
|
||||
subscriber_latitude: 39.9
|
||||
},
|
||||
{
|
||||
stat_time: 1701289999,
|
||||
subscriber_id: '883849',
|
||||
subscriber_longitude: 116.3,
|
||||
subscriber_latitude: 39.97
|
||||
this.queryData().then(res => {
|
||||
this.showError = false
|
||||
const result = _.get(res, 'data.data.result', []).sort((a, b) => a.stat_time - b.stat_time)
|
||||
const route = this.generateRouteGEOJSON(result)
|
||||
const points = this.generatePointsGEOJSON(result)
|
||||
map.on('load', () => {
|
||||
map.jumpTo({ center: this.computeMapCenter(result) })
|
||||
map.zoomTo(this.computeMapZoom(result))
|
||||
map.loadImage(
|
||||
`${window.location.protocol}//${window.location.host}/images/entity-detail/track-point.png`,
|
||||
(error, image) => {
|
||||
if (error) throw error
|
||||
map.addImage('trace-point', image)
|
||||
map.addSource('points', {
|
||||
type: 'geojson',
|
||||
data: points
|
||||
})
|
||||
map.addLayer(this.generatePointsLayer())
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
const result = _.get(res, 'data.data.result', []).sort((a, b) => a.stat_time - b.stat_time)
|
||||
)
|
||||
map.addSource('route', {
|
||||
type: 'geojson',
|
||||
lineMetrics: true,
|
||||
data: route
|
||||
})
|
||||
map.addLayer(this.generateRouteLayer())
|
||||
|
||||
const route = {
|
||||
this.myChart = map
|
||||
|
||||
// point的鼠标事件
|
||||
map.on('mouseenter', 'points', () => {
|
||||
_this.tooltip.showTooltip = true
|
||||
})
|
||||
map.on('mouseleave', 'points', () => {
|
||||
_this.tooltip.showTooltip = false
|
||||
})
|
||||
map.on('mousemove', 'points', ({ point, originalEvent, features }) => {
|
||||
_this.tooltip.x = originalEvent.clientX + 10
|
||||
_this.tooltip.y = originalEvent.clientY - 95
|
||||
_this.currentPoint = { ...features[0].properties }
|
||||
})
|
||||
})
|
||||
}).catch(e => {
|
||||
this.showError = true
|
||||
console.error(e)
|
||||
this.errorMsg = this.errorMsgHandler(e)
|
||||
}).finally(() => {
|
||||
this.toggleLoading(false)
|
||||
})
|
||||
},
|
||||
queryData () {
|
||||
return new Promise((resolve, reject) => {
|
||||
resolve({
|
||||
status: 200,
|
||||
data: {
|
||||
data: {
|
||||
result: [
|
||||
{
|
||||
stat_time: 1701259999,
|
||||
subscriber_id: '883849',
|
||||
subscriber_longitude: 116.29,
|
||||
subscriber_latitude: 39.8
|
||||
},
|
||||
{
|
||||
stat_time: 1701269999,
|
||||
subscriber_id: '883849',
|
||||
subscriber_longitude: 116.34,
|
||||
subscriber_latitude: 39.85
|
||||
},
|
||||
{
|
||||
stat_time: 1701279999,
|
||||
subscriber_id: '883849',
|
||||
subscriber_longitude: 116.29,
|
||||
subscriber_latitude: 39.9
|
||||
},
|
||||
{
|
||||
stat_time: 1701299999,
|
||||
subscriber_id: '883849',
|
||||
subscriber_longitude: 116.39,
|
||||
subscriber_latitude: 39.9
|
||||
},
|
||||
{
|
||||
stat_time: 1701289999,
|
||||
subscriber_id: '883849',
|
||||
subscriber_longitude: 116.3,
|
||||
subscriber_latitude: 39.97
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
// return axios.get(`${api.entity.locationTrack}?resource=${this.entity.entityName}`)
|
||||
},
|
||||
generateRouteGEOJSON (result) {
|
||||
return {
|
||||
type: 'FeatureCollection',
|
||||
features: [
|
||||
{
|
||||
@@ -142,8 +205,9 @@ export default {
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
const points = {
|
||||
},
|
||||
generatePointsGEOJSON (result) {
|
||||
return {
|
||||
type: 'FeatureCollection',
|
||||
features: result.map((r, index) => {
|
||||
return {
|
||||
@@ -154,68 +218,91 @@ export default {
|
||||
},
|
||||
properties: {
|
||||
index: index + 1,
|
||||
stat_time: r.stat_time
|
||||
stat_time: r.stat_time,
|
||||
longitude: r.subscriber_longitude,
|
||||
latitude: r.subscriber_latitude
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
map.on('load', () => {
|
||||
map.loadImage(
|
||||
`${window.location.protocol}//${window.location.host}/images/entity-detail/track-point.png`,
|
||||
(error, image) => {
|
||||
if (error) throw error
|
||||
map.addImage('trace-point', image)
|
||||
map.addSource('points', {
|
||||
type: 'geojson',
|
||||
data: points
|
||||
})
|
||||
map.addLayer({
|
||||
id: 'points',
|
||||
type: 'symbol',
|
||||
source: 'points',
|
||||
layout: {
|
||||
'icon-image': 'trace-point',
|
||||
'icon-size': 0.7,
|
||||
'icon-offset': [0, -20],
|
||||
'text-field': ['get', 'index'],
|
||||
'text-font': ['Noto Sans Bold'],
|
||||
'text-offset': [0, -1.1],
|
||||
'text-size': 13
|
||||
},
|
||||
paint: {
|
||||
'text-color': '#FFF'
|
||||
}
|
||||
})
|
||||
}
|
||||
)
|
||||
map.addSource('route', {
|
||||
type: 'geojson',
|
||||
lineMetrics: true,
|
||||
data: route
|
||||
})
|
||||
map.addLayer({
|
||||
id: 'route',
|
||||
source: 'route',
|
||||
type: 'line',
|
||||
paint: {
|
||||
'line-color': '#E26154',
|
||||
'line-width': 4,
|
||||
'line-gradient': [
|
||||
'interpolate',
|
||||
['linear'],
|
||||
['line-progress'],
|
||||
0,
|
||||
'#F4B32F',
|
||||
1,
|
||||
'#E26154'
|
||||
]
|
||||
},
|
||||
layout: {
|
||||
'line-cap': 'round',
|
||||
'line-join': 'round'
|
||||
}
|
||||
})
|
||||
},
|
||||
generateRouteLayer () {
|
||||
return {
|
||||
id: 'route',
|
||||
source: 'route',
|
||||
type: 'line',
|
||||
paint: {
|
||||
'line-color': '#E26154',
|
||||
'line-width': 4,
|
||||
'line-gradient': [
|
||||
'interpolate',
|
||||
['linear'],
|
||||
['line-progress'],
|
||||
0,
|
||||
'#F4B32F',
|
||||
1,
|
||||
'#E26154'
|
||||
]
|
||||
},
|
||||
layout: {
|
||||
'line-cap': 'round',
|
||||
'line-join': 'round'
|
||||
}
|
||||
}
|
||||
},
|
||||
generatePointsLayer () {
|
||||
return {
|
||||
id: 'points',
|
||||
type: 'symbol',
|
||||
source: 'points',
|
||||
layout: {
|
||||
'icon-image': 'trace-point',
|
||||
'icon-size': 0.7,
|
||||
'icon-offset': [0, -20],
|
||||
'text-field': ['get', 'index'],
|
||||
'text-font': ['Noto Sans Bold'],
|
||||
'text-offset': [0, -1.1],
|
||||
'text-size': 13
|
||||
},
|
||||
paint: {
|
||||
'text-color': '#FFF'
|
||||
}
|
||||
}
|
||||
},
|
||||
computeMapCenter (result) {
|
||||
const longitude = result.map(r => r.subscriber_longitude)
|
||||
const latitude = result.map(r => r.subscriber_latitude)
|
||||
return [
|
||||
_.floor((_.max(longitude) + _.min(longitude)) / 2, 6),
|
||||
_.floor((_.max(latitude) + _.min(latitude)) / 2, 6)
|
||||
]
|
||||
},
|
||||
computeMapZoom (result) {
|
||||
const longitude = result.map(r => r.subscriber_longitude)
|
||||
const latitude = result.map(r => r.subscriber_latitude)
|
||||
const longitudeRange = _.max(longitude) - _.min(longitude)
|
||||
const latitudeRange = _.max(latitude) - _.min(latitude)
|
||||
const max = _.max([this.minZoom, 7 - Math.log2(_.max([longitudeRange, latitudeRange]))])
|
||||
return _.min([max, this.maxZoom])
|
||||
},
|
||||
reload (startTime, endTime, dateRangeValue) {
|
||||
this.toggleLoading(true)
|
||||
this.timeFilter = { startTime: getSecond(startTime), endTime: getSecond(endTime), dateRangeValue: dateRangeValue }
|
||||
this.queryData().then(res => {
|
||||
this.showError = false
|
||||
const result = _.get(res, 'data.data.result', []).sort((a, b) => a.stat_time - b.stat_time)
|
||||
const route = this.generateRouteGEOJSON(result)
|
||||
const points = this.generatePointsGEOJSON(result)
|
||||
this.myChart.getSource('route').setData(route)
|
||||
this.myChart.getSource('points').setData(points)
|
||||
this.myChart.jumpTo({ center: this.computeMapCenter(result) })
|
||||
this.myChart.zoomTo(this.computeMapZoom(result))
|
||||
}).catch(e => {
|
||||
this.showError = true
|
||||
console.error(e)
|
||||
this.errorMsg = this.errorMsgHandler(e)
|
||||
}).finally(() => {
|
||||
this.toggleLoading(false)
|
||||
})
|
||||
}
|
||||
},
|
||||
@@ -225,8 +312,19 @@ export default {
|
||||
const { startTime, endTime } = getNowTime(dateRangeValue)
|
||||
timeFilter.value.startTime = startTime
|
||||
timeFilter.value.endTime = endTime
|
||||
|
||||
const currentPoint = ref({})
|
||||
const tooltip = ref({
|
||||
showTooltip: false
|
||||
})
|
||||
|
||||
return {
|
||||
timeFilter
|
||||
timeFilter,
|
||||
currentPoint,
|
||||
tooltip,
|
||||
maxZoom: 11,
|
||||
minZoom: 1,
|
||||
center: [116.38, 39.9]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ export default {
|
||||
entityData.appName = query.entityName
|
||||
break
|
||||
}
|
||||
case 'subscribe': {
|
||||
case 'subscriber': {
|
||||
panelType = panelTypeAndRouteMapping.subscribeEntityDetail
|
||||
entityData.appName = query.entityName
|
||||
break
|
||||
|
||||
Reference in New Issue
Block a user