同步操作将从 林鹏/WMap 强制同步,此操作会覆盖自 Fork 仓库以来所做的任何修改,且无法恢复!!!
确定后同步将在后台操作,完成时将刷新页面,请耐心等待。
import { Fill, Icon, Stroke, Style, Text } from 'ol/style'import { OlFeature, OlOverlay, OlPoint } from './type'import { getUid } from 'ol/util'import { deepClone, isObject, isString, isFunction, fromLonLat, createDomElement, computedAngle } from './utils'import { getMarkerDefaultStyle } from './defaultOptions'// 默认配置const defaultOptions = {zIndex: 3, // 图形层级id: null, //idposition: [0, 0], // 坐标经纬度angle: 0, //角度content: undefined, // VMarker 内容offset: [0, 0], //偏移量positioning: 'top-left',extData: undefined, //自定义信息icon: '',label: undefined}// WMarker 共享数据function WMarkerBus() {this.zIndexs = {}this.maxZIndex = 1this.isMoving = false}let _WMarkerBus = new WMarkerBus()// marker Icon 样式处理function createSingleIconStyle(style) {const sIconStyle = {crossOrigin: 'anonymous', // 图片跨域允许anchor: style.offset.map(n => -n), // 图标的原点位置,-即中心点anchorOrigin: 'top-left', // 原点位置偏移方向anchorXUnits: 'pixels', // 基于原点位置百分比anchorYUnits: 'pixels', // 基于原点位置像素// displacement: style.offset.map(n => -n), // 偏移量设置,相对于原点scale: 1, // 图标缩放比例opacity: 1, // 透明度src: style.icon,// img: style.img, // 图标的urlrotateWithView: style.rotateWithView, // 是否跟随视图旋转rotation: (Math.PI / 180) * style.angle // 旋转角度}// console.log(style)return sIconStyle}// 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.font || `${style.fontWeight}${style.fontSize}${style.fontFamily}`, // 字体样式backgroundFill: new Fill({// 背景颜色color: style.labelBgColor}),backgroundStroke: new Stroke({// 边框样式color: style.borderColor,width: style.borderWidth,lineCap: 'square', // 线帽风格 butt, round, 或者 square 默认 roundlineJoin: 'bevel', // 线连接方式 bevel, round, 或者 miter 默认 roundlineDash: [], // 线间隔模式 这个变化与分辨率有关 默认为undefined Internet Explorer 10和更低版本不支持lineDashOffset: 0, // 线段间隔偏移 默认0miterLimit: 10 // 默认10}),padding: style.padding}}// 处理 Marker 参数function getMarkerOptions(defaultOptions, options) {const assignOptions = Object.assign({}, defaultOptions, options)// 处理 label 为对象被合并的情况if (typeof options.label === 'object') {if (options.label.offset && Array.isArray(options.label.offset) && !options.label.offset.length) {options.label.offset = [0, 0]}assignOptions.label = deepClone(options.label)}// 去除默认的iconif (options.content && !options.icon) {delete assignOptions.icon}if (Array.isArray(assignOptions.offset) && assignOptions.offset.length !== 2) {assignOptions.offset = [0, 0]}const {position, //位置content, // VMarker 内容offset, //偏移量angle, //角度label,extData, //自定义信息positioning} = assignOptions;(!Array.isArray(position) || !position.length) && delete assignOptions.positioncontent === undefined && delete assignOptions.content;(!Array.isArray(offset) || !offset.length) && delete assignOptions.offset!angle && delete assignOptions.angleextData === undefined && delete assignOptions.extDatalabel === undefined && delete assignOptions.labelpositioning === undefined && delete assignOptions.positioningconst style = deepClone(assignOptions)const markerOptions = {geometry: new OlPoint(fromLonLat(position)),content,position,offset,angle,extData,positioning,label,id: extData && extData.id ? extData.id : null,VMarker: null,style: style // 获取到样式}content === undefined && delete markerOptions.contentlabel === undefined && delete markerOptions.labelextData === undefined && delete markerOptions.extDatapositioning === undefined && delete markerOptions.positioningreturn markerOptions}// Marker 样式处理函数function createMarkerStyle(style) {// 默认 marker 样式const defaultStyle = getMarkerDefaultStyle()// console.log('defaultStyle---',defaultStyle);const iconStyle = createSingleIconStyle({icon: style.icon || defaultStyle.icon,offset: style.offset || defaultStyle.offset,rotateWithView: style.rotateWithView || defaultStyle.rotateWithView,angle: style.angle || defaultStyle.angle})// console.log(style.icon, 1, defaultStyle, iconStyle, 'iconStyleiconStyle')const textStyle = createSingleTextStyle({label: style.label || defaultStyle.label,font: style.font || defaultStyle.font,fontSize: style.fontSize || defaultStyle.fontSize,fontFamily: style.fontFamily || defaultStyle.fontFamily,fontWeight: style.fontWeight || defaultStyle.fontWeight,fontColor: style.fontColor || defaultStyle.fontColor,labelXOffset: style.labelXOffset || defaultStyle.labelXOffset,labelYOffset: style.labelYOffset || defaultStyle.labelYOffset,labelBgColor: style.labelBgColor || defaultStyle.labelBgColor,borderColor: style.borderColor || defaultStyle.borderColor,borderWidth: style.borderWidth || defaultStyle.borderWidth,padding: style.padding || defaultStyle.padding,placement: style.placement || defaultStyle.placement,textBaseline: style.textBaseline || defaultStyle.textBaseline,textAlign: style.textAlign || defaultStyle.textAlign})const newStyle = new Style({image: new Icon(iconStyle),text: new Text(textStyle),zIndex: style.zIndex || defaultOptions.zIndex})return newStyle}// 创建 VMarker, 按理来说只在聚合条件下出现function createVMarker(options) {const { position = [0, 0], offset = [0, 0], id = '' } = options // content, angle, label, styleconst VMarker = new OlOverlay({id,position: fromLonLat(position),offset,element: undefined, // 绑定 VMarker 对象和 DOM 对象的stopEvent: true, // 停止向map 冒泡事件,并且将overlayMarker放在工具栏dom内,insertFirst: true, // 可定义在工具栏dom内时,fale显示在工具栏上方,默认 true 展示在下方autoPan: false, // 设置true后,会让第一个OverlayMarker自动平移到可视区域autoPanAnimation: {duration: 250},positioning: options.positioning, //'top-left', // 图形位于点的中心autoPanMargin: 20, // 平移动画开启后,距离可视区域边距className: 'ol-overlay-container ol-selectable' // all VMarker className})VMarker.set('options', options)return VMarker}//创建 Marker 并设置id style VMarker 等属性function createMarker(options, type) {// 初始化markerconst marker = new OlFeature(options)//设置IDif (!options.id) {const uid = getUid(marker)options.id = uidoptions.style.id = uidmarker.setId(uid)marker.set('id', uid)}if (type === 'FEATUREMARKER') {// 设置marker样式, Feature 初始化传入样式无效const style = marker.get('style') || {}marker.setStyle(createMarkerStyle({ ...style, angle: options.angle, offset: options.offset }))} else {const VMarker = createVMarker(options)const { offset = [0, 0], content, angle, label, style } = options // position = [0, 0], id = '',//创建Domconst element = createDomElement({ content, angle, offset, label, ...style })VMarker.setElement(element)options.VMarker = VMarker// 去除默认图形样式marker.setStyle(new Style()) // 在源聚合图层里应该存在clone geometrycmarker.set('VMarker', VMarker)}return marker}function WMarker({ map, ...options }) {const markerOptions = getMarkerOptions(defaultOptions, options)const events = [// "singleclick",'click','dblclick','contextmenu','moving'] // 支持的事件let clickTimeId = null //单击事件定时器this.WTYPE = !!markerOptions.content || typeof markerOptions.label === 'object' ? 'OVERLAYMARKER' : 'FEATUREMARKER'this.map = mapthis.olTarget = createMarker(markerOptions, this.WTYPE)this.options = markerOptionsthis._listion = ''this.animation = ''this.WEvents = new Map() // 存储事件this.angleFixed = false // 是否固定行驶中marker角度(理应只在轨迹中生效)this.getOriginOptions = () => deepClone(options)this.getId = function () {// return this.options.idreturn this.olTarget.getId()}this.getGeometry = function () {return this.olTarget.getGeometry()}this.getOlStyle = function () {return this.olTarget.getStyle()}// 获取 VMarkerthis.getOverlayMarker = function () {return this.olTarget.get('VMarker')}// 获取自定义信息this.getExtentData = function () {return this.options.extData}// 获取 Marker 坐标this.getPosition = function () {return this.options.position}// 获取Marker 偏移this.getOffset = function () {return this.options.offset}/*** 获取角度*/this.getAngle = function () {return this.options.angle}this.setGeometry = function (geometry) {return this.olTarget.setGeometry(geometry)}// 设置偏移this.setOffset = function (offset = [0, 0]) {this.options.offset = offsetthis.olTarget.set('offset', offset)this.getOverlayMarker().setOffset(offset)}// 删除 VMarkerthis.removeOverlayMarker = function () {this.options.VMarker = nullthis.olTarget.set('VMarker', null)}this.setTop = function () {const id = this.getId()const overlayElement = this.getVMarkerElement()if (overlayElement) {//循环遍历出最大层级 maxZIndexfor (const key in _WMarkerBus.zIndexs) {if (Object.hasOwnProperty.call(_WMarkerBus.zIndexs, key)) {const markerZIndex = _WMarkerBus.zIndexs[key]if (markerZIndex > _WMarkerBus.maxZIndex) {_WMarkerBus.maxZIndex = markerZIndex} else if (markerZIndex === _WMarkerBus.maxZIndex && key !== id) {_WMarkerBus.maxZIndex = markerZIndex + 1}}}overlayElement.style.zIndex = _WMarkerBus.maxZIndex_WMarkerBus.zIndexs[id] = _WMarkerBus.maxZIndex} else {const zIndex = this.getZIndex()if (zIndex > _WMarkerBus.maxZIndex) {_WMarkerBus.maxZIndex = zIndex} else {_WMarkerBus.maxZIndex += 1}this.setZIndex(_WMarkerBus.maxZIndex)}}// 停止行驶动画this.stopMove = () => {const vectorLayer = this.map.getVectorLayer()const eventName = 'moving'const id = this.getId()vectorLayer &&vectorLayer.dispatchEvent({type: eventName, // 订阅事件对象的名称eventName: 'WMarker(moving)' + id,marker: this,map: this.map,status: 'stopMove'})}//继续动画this.resumeMove = () => {const vectorLayer = this.map.vectorLayerconst eventName = 'moving'const id = this.getId()vectorLayer &&vectorLayer.dispatchEvent({type: eventName,eventName: 'WMarker(moving)' + id,marker: this,status: 'resumeMove'})}// 暂停行驶动画this.pauseMove = () => {const vectorLayer = this.map.vectorLayerconst eventName = 'moving'const id = this.getId()vectorLayer &&vectorLayer.dispatchEvent({type: eventName,eventName: 'WMarker(moving)' + id,marker: this,map: this.map,status: 'pauseMove'})}/*** 历史轨迹下的小车开始行驶动画* @param {*} paths 行驶路径* @param {*} angleFixed marker角度是否固定 => 默认不固定* @param {*} speed 行驶速度* @returns*/this.moveAlong = (path = [], angleFixed, speed = 60) => {if (!path.length || !Array.isArray(path)) return false_WMarkerBus.isMoving = trueconst vectorLayer = this.map.vectorLayerconst type = 'moving'const WEventName = 'WMarker(moving)' + this.getId()// 获取 path对应的轨迹线Featureconst lineFeature = vectorLayer.forEachFeature(feature => {if (feature.get('geometry').WTYPE === 'OlLineString') {return feature.get('linePath') === path && feature}})if (lineFeature) {this.angleFixed = angleFixedvectorLayer.dispatchEvent({type,eventName: WEventName,path,speed,circlable: false, //是否循环播放lineFeature,marker: this,status: 'startMove',angleFixed})} else {console.warn('未初始化轨迹线')}}// 更新速度this.updateMoveSpeed = updateSpeed => {const vectorLayer = this.map.vectorLayerconst eventName = 'moving'const id = this.getId()vectorLayer.dispatchEvent({type: eventName,eventName: 'WMarker(moving)' + id,updateSpeed,status: 'updateSpeed'})}// 更新进度this.updateMoveDistance = updateDistance => {const vectorLayer = this.map.vectorLayerconst eventName = 'moving'const id = this.getId()vectorLayer.dispatchEvent({type: eventName,eventName: 'WMarker(moving)' + id,updateDistance,status: 'updateDistance'})}// 获取进度this.getRatio = () => {const vectorLayer = this.map.vectorLayerconst id = this.getId()const WEventName = 'WMarker(moving)' + idif (vectorLayer.WEvents.has(WEventName)) {const animationObject = vectorLayer.WEvents.get(WEventName)const ratio = animationObject.getDistance() * 100// console.log(ratio);if (ratio < 100) {return parseInt(animationObject.getDistance() * 100)}return ratio}return 0}// 获取行驶路径虚拟索引this.getMoveIndex = () => {const vectorLayer = this.map.vectorLayerconst id = this.getId()const WEventName = 'WMarker(moving)' + idif (vectorLayer.WEvents.has(WEventName)) {const animationObject = vectorLayer.WEvents.get(WEventName)return animationObject.getMoveIndex()}return 0}/*** 获取行驶路径原始索引* @returns*/this.getIndex = () => {const vectorLayer = this.map.vectorLayerconst id = this.getId()const WEventName = 'WMarker(moving)' + idif (vectorLayer.WEvents.has(WEventName)) {const animationObject = vectorLayer.WEvents.get(WEventName)return animationObject.getIndex()}return 0}//事件监听this.on = (eventName, callBack = () => {}) => {if (callBack && !isFunction(callBack)) throw new Error('请传入正确的 callBack!')if (!eventName || typeof eventName !== 'string') throw new Error('请传入正确的 eventName!')if (!events.includes(eventName)) return console.warn('无效的事件:' + eventName)if (eventName === 'moving') {const vectorLayer = this.map.vectorLayerconst eventName = 'moving'const id = this.getId()vectorLayer &&vectorLayer.dispatchEvent({type: eventName,eventName: 'WMarker(moving)' + id,moveCallBack: callBack,status: 'moveCallBack'})}if (this.WTYPE === 'FEATUREMARKER' || eventName === 'moving') {const eventObject = {eventName: 'WMarker(' + eventName + ')' + this.getId(),callBack,handler: e => {const returnValue = {type: e.eventName,target: this,index: e.pathIndex,passedPath: e.passedPath,progress: e.progress, // 当前进度realLonLat: this.getPosition()}e.callBack(returnValue)}}// 未绑定过事件if (!this.WEvents.has(eventObject.eventName)) {//监听事件 - WMap 处理成 cliclkthis.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)}this.olTarget.set('WEvents', this.WEvents)} else {const element = this.getElement()const eventObject = {eventName,callBack,target: element,handler: () => {}}const clickHandler = (eventName, e, callBack) => {clickTimeId && clearTimeout(clickTimeId)clickTimeId = setTimeout(() => {callBack({type: eventName,target: this,event: e})}, 200)}const dblclickHandler = (eventName, e, callBack) => {clickTimeId && clearTimeout(clickTimeId)callBack({type: eventName,target: this,event: e})}const contextmenuHandler = (eventName, e, callBack) => {callBack({type: eventName,target: this,event: e})}//事件绑定函数const bindEvent = eventObject => {const { eventName, target, callBack } = eventObjectswitch (eventName) {case 'click':eventObject.handler = e => clickHandler(eventName, e, callBack)breakcase 'dblclick':eventObject.handler = e => dblclickHandler(eventName, e, callBack)breakcase 'contextmenu':eventObject.handler = e => contextmenuHandler(eventName, e, callBack)breakdefault:break}target.addEventListener(eventName, eventObject.handler)}// 未绑定过事件if (!this.VMarkerEvents.has(eventObject.target)) {this.VMarkerEvents.set(eventObject.target, [eventObject]) //保存监听事件并执行bindEvent(eventObject) //绑定事件} else {//绑定过事件const currentEventArray = this.VMarkerEvents.get(eventObject.target)const currentEventObject = currentEventArray.find(e => e.eventName === eventName)// 未绑定过此事件if (!currentEventObject) {currentEventArray.push(eventObject)bindEvent(eventObject)} else {//绑定过此事件,移除之前事件绑定再覆盖eventObject.target.removeEventListener(eventName, currentEventObject.handler)this.VMarkerEvents.set(eventObject.target, [eventObject]) //保存监听事件并执行bindEvent(eventObject) //绑定事件}}}}if (this.WTYPE === 'FEATUREMARKER') {//矢量marker//事件移除this.off = eventName => {eventName = 'WMarker(' + 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)}}// 设置自定义信息this.setExtentData = function (extData) {this.options.extData = extDatathis.olTarget.set('extData', extData)}// 设置 Marker 角度this.setAngle = function (angle = 0) {this.options.angle = anglethis.olTarget.set('angle', angle)this.olTarget.getStyle().getImage().setRotation((Math.PI / 180) * angle)}/*** icon + label 字符下的样式修改*/this.changeMarker = (style = {}) => {this.options.style = {...this.getStyle(),...style}this.olTarget.setStyle(createMarkerStyle(this.options.style))}// 设置 Marker 坐标this.setPosition = function (position) {if (!position) returnconst geometry = this.olTarget.getGeometry()this.options.position = positionthis.olTarget.set('position', position)geometry && geometry.setCoordinates(fromLonLat(position))}/*** 覆盖物在实时轨迹下的移动* @param {*} polyline 实时轨迹线* @param {*} curPath 当前实时轨迹点*/this.move = (polyline, curPath) => {polyline.setPath(curPath)this.setPosition(curPath)let path = polyline.activeTarget.get('options').originPathif (path.length >= 2) {const bearing = computedAngle(path[path.length - 2], path[path.length - 1])// 相同点判断if (path[path.length - 2][0] !== path[path.length - 1][0] || path[path.length - 2][1] !== path[path.length - 1][1]) {let endAngle = bearing + this.getOriginOptions().angle || 0this.setAngle(endAngle)}}}// 设置idthis.setId = function (id) {if (!id) returnthis.options.id = idthis.olTarget.setId(id)this.olTarget.set('id', id)}/*** 获取样式*/this.getStyle = function () {return this.options.style}/*** 设置样式- 会替换默认样式*/this.setStyle = function (style = {}) {const assignStyle = Object.assign(defaultOptions, style)this.options.style = assignStylethis.olTarget.setStyle(createMarkerStyle(assignStyle))}/*** 设置样式- 会替换默认样式*/this.setZIndex = function (zIndex) {// console.log(_WMarkerBus)const assignStyle = Object.assign(this.getStyle(), { zIndex })this.options.style = assignStylethis.olTarget.setStyle(createMarkerStyle(assignStyle))}/*** 设置 Feature 样式*/this.setOlStyle = function (style) {this.olTarget.setStyle(style)}/*** 设置 Feature Image 样式 透明度*/this.setOpacity = function (opacity = 1) {this.getOlStyle().getImage().setOpacity(opacity)}} else {//dom VMarkerthis.VMarkerEvents = new Map() // 存储事件//事件移除this.off = eventName => {const element = this.getElement()if (this.VMarkerEvents.has(element)) {const currentEventArray = this.VMarkerEvents.get(element)const currentEventObject = currentEventArray.find(e => e.eventName === eventName)element.removeEventListener(eventName, currentEventObject.handler)const newEventArray = currentEventArray.filter(e => e.eventName !== eventName)this.VMarkerEvents.set(element, newEventArray)}}/*** 获取 VMarker dom* @returns*/this.getVMarkerElement = function () {return this.options.VMarker.element}/*** 获取 element dom* @returns*/this.getElement = function () {return this.options.VMarker.getElement()}/*** VMarker 增加 element* @param {*} element*/this.setElement = element => {this.olTarget.get('VMarker').setElement(element)}/*** 获取 content str* @returns*/this.getContent = function () {return this.options.content}/*** 设置 content*/this.setContent = function (content) {if (!content) returnconst angle = this.options.angle || 0const offset = this.options.offset || [0, 0]this.options.content = contentthis.olTarget.set('content', content)const contentElement = this.getElement().querySelector('.WMap-marker-content')contentElement.innerHTML = contentif (angle) {container.style['transform-origin'] = `${-offset[0]}px ${-offset[1]}px 0`container.style.transform = `rotate(${angle}deg)`}}/*** 设置 label Content*/this.setLabel = function (label) {if (!label) returnconst labelElement = this.getElement().querySelector('.WMap-marker-label')const offset = this.options.offset || [0, 0]if (isObject(label)) {this.options.label = labelthis.olTarget.set('label', label)if (labelElement) {//设置偏移if (label.offset) {labelElement.style.left = label.offset[0] - offset[0] + 'px'labelElement.style.top = label.offset[1] - offset[1] + 'px'}//设置内容labelElement.innerHTML = label.content || ''} else {//不存在 labelElement时}} else if (isString(label)) {this.options.label = {content: label,offset: [0, 0]}this.olTarget.set('label', label)if (labelElement) {//设置偏移if (label.offset) {labelElement.style.left = label.offset[0] - offset[0] + 'px'labelElement.style.top = label.offset[1] - offset[1] + 'px'}//设置内容labelElement.innerHTML = label.content || ''}}}// 设置 Marker 坐标this.setPosition = function (position) {if (!position) returnconst geometry = this.olTarget.getGeometry()this.options.position = positionthis.olTarget.set('position', position)this.getOverlayMarker().setPosition(fromLonLat(position))geometry && geometry.setCoordinates(fromLonLat(position))}// 设置 Marker 弹跳动画this.setAnimation = function (animationName) {if (!this.animation) {this.animation = animationNamethis.getElement().classList.add(animationName)} else {this.getElement().classList.toggle(this.animation)this.getElement().classList.add(animationName)}if (!animationName || animationName === 'WMAP_ANIMATION_NONE') {this.getElement().classList.toggle(animationName)}}/*** 设置 Feature Image 样式 透明度*/this.setOpacity = function (opacity = 1) {this.getElement().style.opacity = opacity}// 设置 Marker 角度this.setAngle = function (angle = 0) {this.options.angle = anglethis.olTarget.set('angle', angle)this.getElement().style.transform = `rotate(${angle}deg)`}/*** 覆盖物在实时轨迹下的移动* @param {*} polyline 实时轨迹线* @param {*} curPath 当前实时轨迹点*/this.move = (polyline, curPath) => {polyline.setPath(curPath)this.setPosition(curPath)let path = polyline.activeTarget.get('options').originPathif (path.length >= 2) {const bearing = computedAngle(path[path.length - 2], path[path.length - 1])// 相同点判断if (path[path.length - 2][0] !== path[path.length - 1][0] || path[path.length - 2][1] !== path[path.length - 1][1]) {let endAngle = bearing + this.getOriginOptions().angle || 0this.setAngle(endAngle)}}}}// 初始化添加mapif (this.map && this.map.WTYPE === 'MAP') {this.map.add(this)this.map.VMarkerStyle = defaultOptions.VMarker}}export default WMarker
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。