iovmap
Version:
a map sdk base on leaflet
333 lines (327 loc) • 10.1 kB
JavaScript
/*
* Copyright (C) 2017 dehai.site All Rights Reserved.
*
* @author level <dehai168@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
'use strict'
// 第三方集群插件(https://github.com/Leaflet/Leaflet.markercluster)
import markerCluster from 'leaflet.markercluster'
import 'leaflet.markercluster/dist/MarkerCluster.css'
import 'leaflet.markercluster/dist/MarkerCluster.Default.css'
//离线
import offline from '../assets/default/0.png'
//在线行驶
import online from '../assets/default/1.png'
//告警
import alarm from '../assets/default/2.png'
//不定位
import noposition from '../assets/default/3.png'
//停车
import stop from '../assets/default/4.png'
import m0 from '../assets/m0.png'
import m1 from '../assets/m1.png'
import m2 from '../assets/m2.png'
import m3 from '../assets/m3.png'
import m4 from '../assets/m4.png'
export class MarkerList_Native {
constructor(map, cb, cb2) {
this.map = map
this.clickCB = cb
this.closeCB = cb2
this.list = [] //数据列表
this.markers = null
this.markersSubArray = []
this.imgList = [[offline, online, alarm, noposition, stop]] //车辆图像列表
this.popup = null //气泡
this.popupId = null //气泡id
}
/**
* 增加 markerList
* @param {Array} listArray
*/
push(listArray) {
if (listArray.length > 0) {
this.list = listArray
this._drawCluster()
} else {
this._clear()
}
}
_drawCluster() {
const that = this
if (!this.markers) {
this.markers = L.markerClusterGroup({
showCoverageOnHover: false, //当您将鼠标悬停在集群上时,它会显示其标记的边界
removeOutsideVisibleBounds: true, //从地图中移除离视口太远的集群和标记以提高性能
spiderfyOnMaxZoom: false, //当您单击一个标记时,它会将所有其他标记都“蜘蛛网化”,并将它们放在一个单独的组中
disableClusteringAtZoom: this.map.getMaxZoom() - 2, //在最大缩放级别之前不进行群集
iconCreateFunction: function (cluster) {
//集群绘制
const size = cluster.getChildCount()
let style = 'text-align:center;'
if (size <= 500) {
style +=
'margin-top:-26px;margin-left:-26px;width:53px;height:52px;line-height:52px;background:url(' +
m0 +
') no-repeat;'
} else if (size <= 1000) {
style +=
'margin-top:-27px;margin-left:-28px;width:56px;height:55px;line-height:55px;background:url(' +
m1 +
') no-repeat;'
} else if (size <= 2000) {
style +=
'margin-top:-32px;margin-left:-33px;width:66px;height:65px;line-height:65px;background:url(' +
m2 +
') no-repeat;'
} else if (size <= 4000) {
style +=
'margin-top:-38px;margin-left:-39px;width:78px;height:77px;line-height:77px;background:url(' +
m3 +
') no-repeat;'
} else {
style +=
'margin-top:-44px;margin-left:-45px;width:90px;height:89px;line-height:89px;background:url(' +
m4 +
') no-repeat;'
}
//绘制图标
const myIcon = L.divIcon({
className: 'myIconClass',
html: "<div style='" + style + "'>" + size + '</div>',
})
return myIcon
},
})
for (let index = 0; index < this.list.length; index++) {
const item = this.list[index]
const myIcon = this._getIcon(item)
const marker = L.marker([item.lat, item.lng], {
icon: myIcon,
alt: item.id, //唯一标记
})
this.markers.addLayer(marker)
this.markersSubArray.push(marker)
}
this.markers.on('click', function (a) {
if (that.clickCB) {
that.clickCB(a.sourceTarget.options.alt)
}
})
this.map.addLayer(this.markers)
} else {
for (let index = 0; index < this.list.length; index++) {
const item = this.list[index]
const myIcon = this._getIcon(item)
const marker = L.marker([item.lat, item.lng], {
icon: myIcon,
alt: item.id, //唯一标记
})
let isHad = false
for (let index = 0; index < this.markersSubArray.length; index++) {
const marker = this.markersSubArray[index]
if (marker.options.alt === item.id) {
this.markersSubArray[index].setIcon(myIcon)
this.markersSubArray[index].setLatLng([item.lat, item.lng])
isHad = true
break
}
}
if (!isHad) {
this.markers.addLayer(marker)
this.markersSubArray.push(marker)
}
}
this.markers.refreshClusters(this.markersSubArray)
}
}
/**
* 清理 markerList
*/
remove() {
this._clear()
}
/**
* 打开一个气泡
* @param {*} id
*/
openPopup(id) {
const currentZoom = this.map.getZoom()
if (currentZoom !== this.maxZoom) {
this.map.setZoom(this.maxZoom)
}
const index = this.list.findIndex((v) => {
return v.id === id
})
if (index > -1) {
const object = this.list[index]
if (this.popup) {
this._movePopup([object.lat, object.lng], true)
} else {
this.popup = this._createPopup([object.lat, object.lng])
}
this.popupId = id
}
}
/**
* 移动已存在的popup
* @param {*} latlng
*/
_movePopup(latlng, isOpen) {
if (this.popup) {
this.popup.setLatLng(latlng)
if (isOpen) {
this.map.openPopup(this.popup)
}
}
}
/**
* 创建popup
* @param {*} latlng
* @param {*} content
* @returns
*/
_createPopup(latlng, content) {
let popup = L.popup({
className: 'myIconClass',
autoPan: false,
offset: [0, -16],
maxWidth: 600,
})
.setLatLng(latlng)
.setContent(content || 'loading...')
.openOn(this.map)
const that = this
this.map.on('popupclose', function (e) {
if (that.closeCB) {
that.closeCB()
}
})
return popup
}
/**
* 清理popup
*/
_clearPopup() {
if (this.popup) {
this.popup.remove()
this.map.off('popupclose')
this.popup = null
this.popupId = null
}
}
/**
* 关闭气泡
*/
closePopup() {
if (this.popup) {
this.popup.close()
}
}
/**
* 设定气泡内容
* @param {*} htmlStr
*/
setPopupContent(htmlStr) {
if (this.popup) {
this.popup.setContent(htmlStr)
}
}
/**
* 设定图片地址
* @param {*} array
*/
setImageSrc(array) {
this.imgList = [].concat(array)
}
/**
* 清理
*/
_clear() {
if (this.markers) {
this.markers.clearLayers()
this.markers = null
}
this.markersSubArray.length = 0
}
/**
* 获取元素图标
* @param {*} one
*/
_getIcon(one) {
let type = parseInt(one.type ? one.type : 0)
let state = parseInt(one.state ? one.state : 0)
let direction = parseInt(one.direction ? one.direction : 0) // 方向
let img = one.img || this.imgList[type][state]
let imgSize = this._getRotatedDimensions(
{ offsetWidth: one.imgWidth || 32, offsetHeight: one.imgHeight || 32 },
direction,
)
const textWidth = this._getTextWidth(one.text)
let width = textWidth > 32 ? textWidth : 32
let height = 18 + imgSize.newHeight
let style = 'transform:rotate(' + direction + 'deg);max-width:32px;max-height:32px;'
if (one.imgWidth && one.imgHeight) {
style += 'width:' + one.imgWidth + 'px;height:' + one.imgHeight + 'px;'
}
//绘制图标
let myIcon = L.divIcon({
className: 'myIconClass',
iconSize: [width, height],
html:
"<div align='center' style='height:" +
height +
'px;width:' +
width +
"px'><span style='display:block;width:100%;background-color:#fff;font-size:12px'>" +
one.text +
"</span><img style='" +
style +
"' src=" +
img +
'></img></div>',
})
return myIcon
}
/**
* 获取旋转后的尺寸
* @param {*} element
* @param {*} angle
* @returns
*/
_getRotatedDimensions(element, angle) {
const originalWidth = element.offsetWidth
const originalHeight = element.offsetHeight
// 将角度转换为弧度
const radianAngle = (angle * Math.PI) / 180
// 计算旋转后的宽度和高度
const newWidth = Math.abs(originalWidth * Math.cos(radianAngle)) + Math.abs(originalHeight * Math.sin(radianAngle))
const newHeight = Math.abs(originalWidth * Math.sin(radianAngle)) + Math.abs(originalHeight * Math.cos(radianAngle))
return { newWidth, newHeight }
}
/**
* 获取文字宽度
* @param {*} text
* @param {*} font
* @returns
*/
_getTextWidth(text, font = '12px Arial') {
const canvas = document.createElement('canvas')
const context = canvas.getContext('2d')
context.font = font
const textMetrics = context.measureText(text)
return textMetrics.width
}
}