同步操作将从 林鹏/WMap 强制同步,此操作会覆盖自 Fork 仓库以来所做的任何修改,且无法恢复!!!
确定后同步将在后台操作,完成时将刷新页面,请耐心等待。
import { getUid } from 'ol/util'import { boundingExtent } from 'ol/extent'import { fromExtent } from 'ol/geom/Polygon'import VectorSource from 'ol/source/Vector'import { Fill, Icon, Stroke, Style, Text } from 'ol/style'import * as turf from '@turf/turf'import { OlCluster, OlFeature, OlVectorLayer } from './type'import { getMarkerClusterDefaultStyle } from './defaultOptions'import { isFunction, debounce } from './utils'import img0 from './images/m0.png'import img1 from './images/m1.png'import img2 from './images/m2.png'import img3 from './images/m3.png'const defaultOptions = {zIndex: 3, // 覆盖物的叠加顺序noClusterZoom: 18, // 在zoom及以上不聚合distance: 40, // 要素将聚集在一起的距离(以像素为单位)minDistance: 30, // 簇之间的最小距离(以像素为单位)showViewExtent: true, // 只展示可视区域 MarkerzoomOnClick: true, // 是否点击展开 ClusteraverageCenter: false, // 聚合点的图标位置是否是所有聚合内点的中心点。默认为否styles: [] // 自定义1-10 ,11-100,101-1000,10001- 聚合物的样式}// marker Text样式处理function createSingleTextStyle(style) {return {placement: style.placement, // 默认为pointtext: style.label,offsetX: style.labelXOffset,offsetY: style.labelYOffset,fill: new Fill({// 字体颜色color: style.fontColor}),font: `${style.fontWeight}${style.fontSize}${style.fontFamily}`, // 字体样式backgroundFill: new Fill({// 背景颜色color: style.labelBgColor}),backgroundStroke: new Stroke({// 边框样式color: style.borderColor,width: 10,lineCap: 'round', // 线帽风格 butt, round, 或者 square 默认 roundlineJoin: 'round', // 线连接方式 bevel, round, 或者 miter 默认 roundlineDash: [], // 线间隔模式 控制虚线lineDashOffset: 0, // 线段间隔偏移 默认0miterLimit: 10 // 默认10}),padding: style.padding,textBaseline: style.textBaseline, // 似乎无效textAlign: style.textAlign //文本对齐方式,似乎无效}}function createSingleIconStyle(style) {const sIconStyle = {crossOrigin: 'anonymous', // 图片跨域允许anchor: [0.5, 0.5], // 原点位置anchorOrigin: 'top-left', // 原点位置偏移方向anchorXUnits: 'fraction', // 基于原点位置百分比anchorYUnits: 'fraction', // 基于原点位置像素offset: [0, 0], // 偏移量设置,相对于原点scale: 1, // 图标缩放比例opacity: 1, // 透明度src: style.icon,// img: style.img, // 图标的urlrotateWithView: style.rotateWithView, // 是否旋转rotation: style.rotation // 旋转角度}return sIconStyle}// 设置聚合物不同数量的自定义样式const getClusterStyle = (img, size, defaultStyle, style = {}) => {const { url, offset, angle, textColor, textSize, textWeight } = styleconst iconStyle = createSingleIconStyle({icon: url || img,offset: offset || [0, 0],angle: angle || defaultStyle.angle,rotateWithView: defaultStyle.rotateWithView})const textStyle = createSingleTextStyle({label: size.toString() || defaultStyle.label,font: defaultStyle.font,fontSize: textSize || defaultStyle.fontSize,fontFamily: defaultStyle.fontFamily,fontWeight: textWeight || defaultStyle.fontWeight,fontColor: textColor || defaultStyle.fontColor,labelXOffset: defaultStyle.labelXOffset,labelYOffset: defaultStyle.labelYOffset,labelBgColor: defaultStyle.labelBgColor,borderColor: defaultStyle.borderColor,borderWidth: defaultStyle.borderWidth,padding: defaultStyle.padding,placement: defaultStyle.placement,textBaseline: defaultStyle.textBaseline,textAlign: defaultStyle.textAlign})return {textStyle,iconStyle}}// 设置聚合要素样式function createClusterStyle(styleCache, defaultStyle, assignOptions, feature) {const size = feature.get('features').length // 获取该要素所在聚合群的要素数量let style = styleCache[size]const styles = assignOptions.styles || []// stylesif (!style) {let clusterStyle = {textStyle: {},iconStyle: {}}if (size == 1) {// 处理 VMarker 和 正常 Markerconst marker = feature.get('features')[0]return !marker.get('VMarker') ? marker.getStyle() : null} else if (size < 11) {clusterStyle = getClusterStyle(img0, size, defaultStyle, styles[0])} else if (size < 101) {clusterStyle = getClusterStyle(img1, size, defaultStyle, styles[1])} else if (size < 1001) {clusterStyle = getClusterStyle(img2, size, defaultStyle, styles[2])} else {clusterStyle = getClusterStyle(img3, size, defaultStyle, styles[3])}style = [new Style({image: new Icon(clusterStyle.iconStyle),text: new Text(clusterStyle.textStyle),zIndex: defaultStyle.zIndex // 设置层级})]styleCache[size] = style}return style}// Cluster change 单个 marker 添加const addOverlaysAction = (map, clusterSource, features, showViewExtent) => {//获取可视区域范围的1.2倍const mapsize = map.getSize().map(it_ => it_ * 1.2)const extent = map.getView().calculateExtent(mapsize)//获取可视区域范围的几何对象const viewGeometry = fromExtent(extent)// console.log(viewGeometry.getBottomLeft())features.forEach(feature => {const markers = feature.get('features')const showZoomFeature = feature.get('showZoomFeature')if (!markers) {//不存在 features 即为 单个 VMarkerconst VMarker = feature.get('VMarker')if (VMarker) {// 获取 VMarker idconst id = VMarker.getId()// 获取 VMarker 经纬度const coordinate = VMarker.getPosition()// 判断是否在可视区域内const inViewGeometry = viewGeometry.intersectsCoordinate(coordinate)// 判断是否已经添加const inOverlaysList = clusterSource.overlayIds.includes(id)if (!inOverlaysList) {// 未被添加的 VMarkerif (inViewGeometry && showViewExtent) {//只添加在可视区域clusterSource.overlayIds.push(id)map.add(VMarker)}if (!showViewExtent) {// 可视区域外的也添加clusterSource.overlayIds.push(id)map.add(VMarker)}}} else {// 获取 idconst id = feature.getId()// 获取 feature 经纬度const position = feature.get('position')const coordinate = [position.olng, position.olat]// 判断是否在可视区域内const inViewGeometry = viewGeometry.intersectsCoordinate(coordinate)// 判断是否已经添加const inOverlaysList = clusterSource.showZoomFeatureIds.includes(id)clusterSource.singleFeatureIds.add(id)if (!inOverlaysList) {// 未被添加if (inViewGeometry && showViewExtent) {//只添加在可视区域clusterSource.showZoomFeatureIds.push(id)map.add(feature)}if (!showViewExtent) {// 可视区域外的也添加clusterSource.showZoomFeatureIds.push(id)map.add(feature)}}}} else if (showZoomFeature) {//处理zoom 不聚合情况feature.setGeometry(null) // 清空聚合图形addOverlaysAction(map, clusterSource, markers, showViewExtent)}})}//创建要素聚合数据来源function createClusterSource(map, vectorSource, options) {const { distance, minDistance, showViewExtent, noClusterZoom, averageCenter } = options// 创建要素聚合数据来源const clusterSource = new OlCluster({distance: parseInt(distance, 10),minDistance: parseInt(minDistance, 10),source: vectorSource,createCluster(point, features) {let cluster = nullconst zoom = map.getZoom()const showZoomFeature = zoom >= noClusterZoomif (features.length == 1) {const VMarker = features[0].get('VMarker')clusterSource.singleFeatureIds.add(features[0].getId())// 创建聚合对象时候,只有一个聚合物情况cluster = VMarker? new OlFeature({VMarker}): new OlFeature({geometry: point,features,// 聚合下一个要素,其唯一子 feature 已经注册监听事件,传递 WEvents,在 WMap dispatchActionWEvents: features[0].get('WEvents')})} else {if (averageCenter) {const turfFeatures = features.map(feature => {return turf.point(feature.getGeometry().getCoordinates())})const featureCollection = turf.featureCollection(turfFeatures)const centerCoordinates = turf.center(featureCollection).geometry.coordinatespoint.setCoordinates(centerCoordinates)}cluster = new OlFeature({geometry: point,features,showZoomFeature})cluster.setId(getUid(cluster))}cluster.WTYPE = 'ClusterMarker'return cluster}})// 拖动变化-主动触发 clusterSource change// 拖动时,判断Feature是否有变化,可优化map.on('moveend', e => clusterSource.changed(e))const clusterSourceChangeCallback = function (e) {const features = e.target.getFeatures()// 添加前先清除所有 VMarkerclusterSource.overlayIds.forEach(id => {const VMarker = map.getOverlayById(id)map.remove(VMarker)})clusterSource.showZoomFeatureIds.forEach(id => {const feature = map.getFeatureById(id)map.remove(feature)})clusterSource.overlayIds = []clusterSource.showZoomFeatureIds = []if (features.length > 0) {// 添加每个聚合物相应的 OverlayMarkeraddOverlaysAction(map, clusterSource, features, showViewExtent)}}/*** 监听聚合物体变化 ,用于清除聚合状态下 自定义overlays数量* addFeatures/removeFeature 也会触发*/clusterSource.on('change',debounce(e => {clusterSourceChangeCallback(e)}, 200))return clusterSource}/*** 创建聚合物覆盖群* @param {object} map* @param {object} options distance = 40, minDistance = 30* @param {object} features* @returns*/function createMarkerCluster(map, markers, options) {const styleCache = {}const assignOptions = Object.assign({}, defaultOptions, options)const features = markers.map(marker => {// 聚合对象单个矢量要素需要重新注册return marker.olTarget})// 创建要素数据来源const vectorSource = new VectorSource({features})// 创建要素聚合数据来源const clusterSource = createClusterSource(map, vectorSource, assignOptions)const defaultStyle = getMarkerClusterDefaultStyle()// 创建一个图层const clusterLayer = new OlVectorLayer({className: 'WMap-clusterer-layer',source: clusterSource,zIndex: 1,style: feature => createClusterStyle(styleCache, defaultStyle, assignOptions, feature)})// 默认添加图层map.addLayer(clusterLayer) // 初始默认数据添加图层return { clusterLayer, assignOptions }}function WMarkerCluster(map, features = [], options) {if (!map || map.WTYPE !== 'MAP') throw new Error('WMarkerCluster warn: 请传入正确的map对象~')const events = ['click', 'dblclick', 'contextmenu'] // 支持的事件const { clusterLayer, assignOptions } = createMarkerCluster(map, features, options) // 聚合图层this.olTarget = clusterLayer // 聚合图层this.options = assignOptionsthis.map = mapthis.WTYPE = 'MARKERCLUSTER'this.WEvents = new Map() // 存储事件this.getView = () => this.map.getView() // 获取地图的初始化 View 信息this.getMaxZoom = () => this.getView().getMaxZoom() // 获取地图设置的最大放大this.getVectorSource = () => this.olTarget.getSource().getSource() // Marker集合数据对象this.getClusterSource = () => this.olTarget.getSource() // 聚合物集合数据对象this.getDistance = () => this.getClusterSource().getDistance() // 聚合的距离this.setDistance = distance => this.olTarget.getSource().setDistance(distance)this.getMinDistance = () => this.olTarget.getSource().getMinDistance() // 聚合物的最小间距this.setMinDistance = minDistance => this.olTarget.getSource().setMinDistance(minDistance)this.hasFeature = feature => this.getVectorSource().hasFeature(feature) // 矢量要素是否在聚合图层上this.getId = function () {return getUid(this.olTarget)}// 获取聚合类的所有基础Marker集合this.getMarkers = () => {return this.getVectorSource().getFeatures()}// 将Marker集合添加到聚合this.setMarkers = features => {const distance = this.getDistance()const minDistance = this.getMinDistance()if (Array.isArray(features) && features.length > 0) {this.olTarget && this.map.removeLayer(this.olTarget)const { clusterLayer, assignOptions } = createMarkerCluster(this.map, features, {distance,minDistance})this.options = assignOptionsthis.olTarget = clusterLayerreturn this.olTarget}}// 添加Markerthis.add = (...args) => {if (args.length === 1) {if (Array.isArray(args[0])) {this.add(...args[0])} else if (args[0].WTYPE === 'OVERLAYMARKER' || args[0].WTYPE === 'FEATUREMARKER') {const olTarget = args[0].olTarget ? args[0].olTarget : args[0]this.getVectorSource().addFeature(olTarget)}} else {const markers = args.map(marker => {if (marker.WTYPE === 'OVERLAYMARKER' || marker.WTYPE === 'FEATUREMARKER') {return marker.olTarget}})this.getVectorSource().addFeatures(markers)}}// 删除Markerthis.remove = (...args) => {if (args.length === 1) {// 单参数或者数组if (Array.isArray(args[0])) {this.remove(...args[0])} else if (args[0].WTYPE === 'FEATUREMARKER' || args[0].WTYPE === 'OVERLAYMARKER') {// removeFeature 时候 触发 change 事件,并且会 remove VMarkerconst olTarget = args[0].olTarget ? args[0].olTarget : args[0]console.log(this.hasFeature(olTarget))this.getVectorSource().removeFeature(olTarget)}} else {// 多个参数args.forEach(marker => this.remove(marker))}}// 清空 Markersthis.clearMarkers = () => {// 遍历清空已经渲染 OverlayMarkersthis.getClusterSource().overlayIds.forEach(id => {const VMarker = this.map.getOverlayById(id)this.map.remove(VMarker)})this.getClusterSource().overlayIds = [] // 清空overlayMarkers 数据this.getClusterSource().showZoomFeatureIds = [] // 清空 showZoomFeaturethis.getVectorSource().clear() // 清空 Marker集合数据对象}// 点击散开属性this.setZoomOnClick = function (zoomOnClick = false) {this.options.zoomOnClick = zoomOnClick}/* 聚合物放大展开,视野适应地图*@param{object} target 聚合features 对象*@param{Array} options 组成聚合物的 feature 集合*@return {object} target*@存在问题,会使 zoom 出现小数*/this.setClusterExtentView = function (target, options = {}) {// 所有要素坐标集合if (!target || target.WTYPE !== 'ClusterMarker') returnconst features = target.get('features')const coordinates = features.length > 1 ? features.map(r => r.getGeometry().getCoordinates()) : features.getGeometry().getCoordinates()// 放大地图,让要素刚好出现在视野this.getView().fit(boundingExtent(coordinates), {maxZoom: this.getMaxZoom(),duration: 300,padding: [100, 100, 100, 100], // 点要素距离视野边距nearest: true,...options})return target}//事件监听this.on = (eventName, callBack = () => {}) => {if (callBack && !isFunction(callBack)) throw new Error('请传入正确的 callBack!')if (!eventName || typeof eventName !== 'string') throw new Error('请传入正确的 eventName!')const WEventName = !events.includes(eventName) ? eventName : 'WCluster(' + eventName + ')' + this.getId()const eventObject = {eventName: WEventName,callBack,handler: e => {// if (this.options.zoomOnClick) {// this.setClusterExtentView(e.eventTarget)// }e.callBack({type: e.eventName,target: this,event: e.event,eventTarget: e.eventTarget})}}// 未绑定过事件if (!this.WEvents.has(eventObject.eventName)) {//事件监听- 传递如:WMarkerCluster(cliclk)this.olTarget.on(eventObject.eventName, eventObject.handler)//储存事件this.WEvents.set(eventObject.eventName, eventObject)} else {const currentEventObject = this.WEvents.get(eventObject.eventName)// 移除事件this.olTarget.un(currentEventObject.eventName, currentEventObject.handler)// 重新设置监听事件this.olTarget.on(currentEventObject.eventName, eventObject.handler)//储存新事件this.WEvents.set(currentEventObject.eventName, eventObject)}//设置 WEventsthis.olTarget.set('WEvents', this.WEvents)}//事件移除this.off = eventName => {eventName = 'WCluster(' + eventName + ')' + this.getId()if (this.WEvents.has(eventName)) {// 获取事件对象const currentEventObject = this.WEvents.get(eventName)// 移除事件this.olTarget.un(currentEventObject.eventName, currentEventObject.handler)// 删除事件存储this.WEvents.delete(eventName)this.olTarget.set('WEvents', this.WEvents)callBack()}}map.setMarkerClusterer(this) // map 上添加 markerCluster}export default WMarkerCluster
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。