mapbox点位图层

mapbox点位图层

import AddPopup from "@/components/Mapbox/addPopup";

class LayerClusters{
	declare map: any
	declare geojsonData: any
	declare isCluster: boolean
	declare layerProps: any
	declare dialog: Object
	
	declare sourceId: string
	declare layerClustersId: string
	declare layerClustersTextId: string
	declare layerUnclusteredId: string
	
	declare popup:any
	
	constructor(option: {
		map: any,
		geojsonData: Object,
		isCluster: true,
		layerProps: {
			iconImage: string,
			iconSize: string
		},
		dialog: {
			component: string,
		}
	}) {
		
		this.map = option?.map
		this.geojsonData = option?.geojsonData
		this.isCluster = option.isCluster
		this.layerProps = option?.layerProps
		this.dialog = option?.dialog
		
		this.sourceId = 'layer-clusters' + Date.now()
		this.layerClustersId = 'layer-clusters' + Date.now()
		this.layerClustersTextId = 'layer-clusters-text' + Date.now()
		this.layerUnclusteredId = 'layer-clusters-unclustered' + Date.now()
		
		this.popup = undefined
		
		this.init()
	}
	
	private init(){
		// 数据源加载和图层加载分开,尽量不共用一个id
		this.map.addSource(this.sourceId, {
			type: 'geojson',
			data: this.geojsonData,
			cluster: this.isCluster, // 是否聚合  true 是
			clusterMaxZoom: 14, // 最大聚合等级
			clusterRadius: 50 // 聚合半径,
		})
		
		// 聚合点圆样式
		this.map.addLayer({
			id: this.layerClustersId,
			type: 'circle',
			source: this.sourceId,
			filter: ['has', 'point_count'],
			paint: {
				//    聚合颜色:
				//    100个点为 #51bbd6
				//    750个点为 #f1f075
				//    750以上 #f28cb1
				'circle-color': [
					'step',
					['get', 'point_count'],
					'#51bbd6',
					100,
					'#f1f075',
					750,
					'#f28cb1'
				],
				// 聚合圆半径
				//    100个点为 20 px
				//    750个点为 30 px
				//    750以上 40 px
				'circle-radius': [
					'step',
					['get', 'point_count'],
					20,
					100,
					30,
					750,
					40
				]
			},
		});
		
		// 聚合点文字
		if(this.isCluster){
			this.map.addLayer({
				id: this.layerClustersTextId,
				type: 'symbol',
				source: this.sourceId,
				filter: ['has', 'point_count'],
				layout: {
					'text-field': ['get', 'point_count_abbreviated'],
					'text-font': ['DIN Offc Pro Medium', 'Arial Unicode MS Bold'],
					'text-size': 12
				}
			});
		}
		
		
		// 不聚合点样式
		if(this.layerProps?.iconImage){
			// 不聚合点样式
			this.map.addLayer({
				id: this.layerUnclusteredId,
				type: 'symbol',
				source: this.sourceId,
				filter: ['!', ['has', 'point_count']],
				layout: {
					'icon-image': this.layerProps?.iconImage,
					'icon-size': this.layerProps?.iconSize || 1,
					"icon-allow-overlap": true,
				},
			});
		}else {
			// 不聚合点样式
			this.map.addLayer({
				id: this.layerUnclusteredId,
				type: 'circle',
				source: this.sourceId,
				filter: ['!', ['has', 'point_count']],
				paint: {
					'circle-color': '#11b4da',
					'circle-radius': 4,
					'circle-stroke-width': 1,
					'circle-stroke-color': '#fff'
				},
			});
		}
		
	}
	
	on(callback){
		this.map.on('mouseenter', this.layerClustersId, () => {
			this.map.getCanvas().style.cursor = 'pointer';
		});
		this.map.on('mouseleave', this.layerClustersId, () => {
			this.map.getCanvas().style.cursor = '';
		});
		
		this.map.on('mouseenter', this.layerUnclusteredId, () => {
			this.map.getCanvas().style.cursor = 'pointer';
		});
		this.map.on('mouseleave', this.layerUnclusteredId, () => {
			this.map.getCanvas().style.cursor = '';
		});
		this.map.on('click',this.layerUnclusteredId,(e)=>{
			callback(e)
			
			const coordinates = e.features[0].geometry.coordinates
			
			this.map.panTo(coordinates)
			
			if(this.popup){
				this.popup.destory()
			}
			
			if(this.dialog?.component){
				this.popup = new AddPopup({
					map: this.map,
					coordinates: coordinates,
					dialog: {
						component: this.dialog?.component,
						props: {
							...e.features[0].properties
						}
					}
				})
			}
		})
	}
	
	setLayoutProperty(attr, attrValue){
		this.map.setLayoutProperty(this.layerUnclusteredId, attr, attrValue)
	}
	
	mouse(attrName){
		let that = this
		this.map.on('mouseenter', this.layerUnclusteredId, (e) => {
			this.map.getCanvas().style.cursor = 'pointer';
			
			const coordinatesM = e.features[0].geometry.coordinates
			
			const popUps = document.getElementsByClassName('my-class1')
			
			if (popUps[0]) popUps[0].remove()
			
			const markerHeight = 20
			const markerRadius = 10
			const linearOffset = 25
			const popupOffsets = {
				'top': [-10, 0],
				'top-left': [0, 0],
				'top-right': [0, 0],
				'bottom': [0, -markerHeight],
				'bottom-left': [linearOffset, (markerHeight - markerRadius + linearOffset) * -1],
				'bottom-right': [-linearOffset, (markerHeight - markerRadius + linearOffset) * -1],
				'left': [markerRadius, (markerHeight - markerRadius) * -1],
				'right': [-markerRadius, (markerHeight - markerRadius) * -1]
			}
			new mapboxgl.Popup({offset: popupOffsets, className: 'my-class1', closeButton: false})
				.setMaxWidth('none')
				.setLngLat(coordinatesM)
				.setHTML(`<div>${e.features[0].properties[attrName]}</div>`)
				.addTo(that.map)
			// if (popUps[1]) popUps[1].remove()
			
		});
		this.map.on('mouseleave', this.layerUnclusteredId, () => {
			this.map.getCanvas().style.cursor = '';
			
			const popUps = document.getElementsByClassName('my-class1')
			if (popUps[0]) popUps[0].remove()
		});
	}
	
	closePopup(){
		if(this.popup){
			this.popup.destory()
		}
	}
	
	// 必须先清除layer再清除图层
	destory(){
		if(this.popup){
			this.popup.destory()
		}
		if(this.map?.getSource(this.sourceId)){
			this.map?.removeLayer(this.layerClustersId)
			this.map?.removeLayer(this.layerUnclusteredId)
			
			if(this.isCluster){
				this.map?.removeLayer(this.layerClustersTextId)
			}
			this.map?.removeSource(this.sourceId)
		}
	}
	
}

export default LayerClusters

Addpopup

import {createVNode, render} from "vue";
// import mapboxgl from 'mapbox-gl'

class AddPopup{
	declare map:any
	declare coordinates:any
	declare dialog:any
	declare popup:any
	declare pupupId: string
	
	constructor(option: {
		map: any,
		coordinates: any,
		dialog: object
	}) {
		
		this.map = option.map
		this.coordinates = option.coordinates
		this.dialog = option.dialog
		
		this.popup = null
		
		this.pupupId = `pupupId`
		
		this.init()
	}
	
	private init(){
		const app = createVNode(this.dialog?.component, {data: this.dialog?.props})
		
		const markerHeight = 20
		const markerRadius = 10
		const linearOffset = 25
		const popupOffsets = {
			'top': [-10, 0],
			'top-left': [0, 0],
			'top-right': [0, 0],
			'bottom': [0, -markerHeight],
			'bottom-left': [linearOffset, (markerHeight - markerRadius + linearOffset) * -1],
			'bottom-right': [-linearOffset, (markerHeight - markerRadius + linearOffset) * -1],
			'left': [markerRadius, (markerHeight - markerRadius) * -1],
			'right': [-markerRadius, (markerHeight - markerRadius) * -1]
		}
		
		this.popup = new mapboxgl.Popup({className: 'my-class', closeButton: true, offset: popupOffsets})
			.setMaxWidth('none')
			.setLngLat(this.coordinates)
			.setHTML(`<div id="${this.pupupId}"></div>`)
			.addTo(this.map)

		render(app, document.querySelector(`#${this.pupupId}`))
	}
	
	destory(){
		if(this.popup){
			this.popup.remove()
		}
		if(document.querySelector(`#${this.pupupId}`)){
			document.querySelector(`#${this.pupupId}`).remove()
		}
	}
}

export default AddPopup

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值