UNPKG

ol-extent

Version:

a JavaScript library for openlayers extent

592 lines (550 loc) 18.9 kB
/** * Created by FDD on 2016/11/5. * @desc 动态圆,主要用于周边搜索功能 */ import ol from 'openlayers' import '../assets/scss/freeHandCircle.scss' import StyleFactory from '../style/StyleFactory' import {uuid} from '../utils'; import { createVectorLayer } from '../layer/layerUtils'; class FreeHandCircle extends ol.interaction.Pointer { /** * 处理移动事件 * @param mapBrowserEvent */ static handleMoveEvent_ = function (mapBrowserEvent) { if (this.cursor_) { let map = mapBrowserEvent.map; let feature = map.forEachFeatureAtPixel(mapBrowserEvent.pixel, function (feature) { return feature }); let element = map.getTargetElement(); if (feature && feature.get('free-hand-circle-lable')) { if (element.style.cursor !== this.cursor_) { this.previousCursor_ = element.style.cursor; element.style.cursor = this.cursor_ } } else if (this.previousCursor_ !== undefined) { element.style.cursor = this.previousCursor_; this.previousCursor_ = undefined } } }; /** * 鼠标按下事件 * @param mapBrowserEvent * @private */ static handleDownEvent_ = function (mapBrowserEvent) { this.isMouseDown = true; if (!this.drawStart_ && mapBrowserEvent.originalEvent.button === 0) { let map = mapBrowserEvent.map; let feature = map.forEachFeatureAtPixel(mapBrowserEvent.pixel, function (feature) { return feature }) if (feature && feature.get('free-hand-circle-lable')) { this.coordinate_ = mapBrowserEvent.coordinate; this.feature_ = feature } return !!this.feature_; } }; /** * 处理鼠标抬起事件 * @param mapBrowserEvent * @private */ static handleUpEvent_ = function (mapBrowserEvent) { if (this.feature_ && this.coordinate_ && this.isDraging) { this.dispatchEvent({ type: 'changeend', target: this, geometry: this.circleFeature.getGeometry() }) } this.coordinate_ = null; this.feature_ = null this.isMouseDown = false; this.isDraging = false; return false; } /** * 处理拖拽事件 * @param mapBrowserEvent * @private */ static handleDragEvent_ = function (mapBrowserEvent) { if (!this.coordinate_ || !this.feature_) { return } this.isDraging = true; let deltaX = mapBrowserEvent.coordinate[0] - this.coordinate_[0]; let deltaY = 0; let geometry = /** @type {ol.geom.SimpleGeometry} */ (this.feature_.getGeometry()); geometry.translate(deltaX, deltaY); this.coordinate_[0] = mapBrowserEvent.coordinate[0]; this.coordinate_[1] = mapBrowserEvent.coordinate[1]; this.createCircle(this.center_, this.mathRadius(this.center_, geometry.getCoordinates())); } constructor (options = {}) { super({ handleMoveEvent: FreeHandCircle.handleMoveEvent_, handleDownEvent: FreeHandCircle.handleDownEvent_, handleUpEvent: FreeHandCircle.handleUpEvent_, handleDragEvent: FreeHandCircle.handleDragEvent_ }); /** * options * @type {{}} */ this.options = options; /** * 计算工具 * @type {ol.Sphere} */ this.wgs84Sphere = new ol.Sphere(typeof options['sphere'] === 'number' ? options['sphere'] : 6378137); /** * 当前图层layerName * @type {*} */ this.layerName = options['layerName'] || 'FREE_HAND_CIRCLE'; /** * 中心点样式 * @type {*} */ this.centerStyle = options['centerStyle'] || null; /** * 当前图层 * @type {null} */ this.layer = null; /** * 当前半径 * @type {number} */ this.radius = ''; /** * 中心点坐标 * @type {Array} * @private */ this.center_ = []; /** * 当前鼠标是否按下 * @type {boolean} */ this.isMouseDown = false; /** * 是否为拖拽状态 * @type {boolean} */ this.isDraging = false; /** * cursor * @type {string} * @private */ this.cursor_ = 'pointer'; /** * isDrawStart * @type {boolean} * @private */ this.drawStart_ = false; /** * @type {string|undefined} * @private */ this.previousCursor_ = undefined; /** * coordinate * @type {null} * @private */ this.coordinate_ = null; /** * feature * @type {null} * @private */ this.feature_ = null; /** * 文本要素 * @type {null} */ this.textOverlay = null; /** * 当前圆 * @type {null} */ this.circleFeature = null; /** * 中心点要素 * @type {null} */ this.centerFeature = null; /** * labelFeature * @type {null} */ this.labelFeature = null; /** * drawStyle * @type {{}} */ this.style_ = { fill: { fillColor: 'rgba(67, 110, 238, 0)' }, stroke: { strokeColor: 'rgba(249, 185, 154, 1)', strokeWidth: 2.5 }, image: { type: '', image: { fill: { fillColor: 'rgba(255, 255, 255, 0.8)' }, points: Infinity, radius: 4, stroke: { strokeColor: 'rgba(255, 0, 0, 1)', strokeWidth: 1.5 } } } }; if (options['style'] && typeof options['style'] === 'object') { this.style_ = options['style']; } } /** * 初始化interaction工具 * @private */ initDrawInteraction () { if (!this.getMap()) return let style_ = StyleFactory.getStyle(this.style_); this.draw = new ol.interaction.Draw({ type: 'Circle', style: style_ }) this.draw.set('uuid', uuid()); this.getMap().addInteraction(this.draw); this.draw.on('drawstart', this.drawStartHandle_, this); this.draw.on('drawend', this.drawEndHandle_, this); } /** * 移除上一次交互工具 * @private */ removeLastInteraction_ () { if (!this.getMap()) return; this.draw.un('drawstart', this.drawStartHandle_, this); this.draw.un('drawend', this.drawEndHandle_, this); this.getMap().removeInteraction(this.draw); } /** * drawStart * @param event * @private */ drawStartHandle_ (event) { this.drawStart_ = true; } /** * drawEnd * @param event * @private */ drawEndHandle_ (event) { if (event && event.feature) { let geom_ = event.feature.getGeometry(); this.center_ = geom_.getCenter(); let coordinates = geom_.getLastCoordinate(); this.radius = this.mathRadius(this.center_, coordinates); this.createCircle(this.center_, this.radius) } this.removeLastInteraction_(); this.drawStart_ = false } /** * 创建圆 * @param center * @param radius */ createCircle (center, radius) { if (!this.getMap()) return; let style_ = StyleFactory.getStyle(this.style_); if (!this.layer) { this.layer = createVectorLayer(this.getMap(), this.layerName, { create: true }); this.layer.setStyle(style_); } let params = this.transformCenterAndRadius_(center, radius); if (!this.circleFeature) { this.circleFeature = new ol.Feature({ geometry: new ol.geom.Circle(params['center'], params['radius']) }); let _uuid = (this.draw && this.draw.get('uuid')) ? this.draw.get('uuid') : uuid(); this.circleFeature.set('uuid', _uuid); this.layer.getSource().addFeature(this.circleFeature); this.circleFeature.getGeometry().on('change', evt => { let geom = evt.target; let coordinates = geom.getLastCoordinate(); this.center_ = geom.getCenter(); this.radius = this.mathRadius(this.center_, coordinates); this.addLabelFeature_(this.center_, 'center'); this.addLabelFeature_(coordinates, 'endLabel'); this.drawTextLabel_(this.radius + ' m', coordinates); if (this.drawStart_ || !(this.isMouseDown && this.isDraging)) { this.dispatchEvent({ type: 'changeend', target: this, geometry: geom }) } }); this.circleFeature.getGeometry().dispatchEvent('change'); } else { this.circleFeature.getGeometry().setCenterAndRadius(params['center'], params['radius']); } } /** * 获取要素空间信息 * @param center * @param radius * @returns {ol.geom.Geometry} * @private */ transformCenterAndRadius_ (center, radius) { let center_ = ol.proj.transform(center, this._getProjectionCode(), 'EPSG:4326'); let sourceGeom = new ol.geom.Circle(center_, (this.transformRadius(center_, radius))); let trans_ = sourceGeom.transform('EPSG:4326', this._getProjectionCode()); return { center: trans_.getCenter(), radius: trans_.getRadius() } } /** * 添加中心点和label要素 * @param coordinates * @param type * @private */ addLabelFeature_ (coordinates, type) { if (type === 'center') { if (!this.centerFeature) { this.centerFeature = new ol.Feature({ uuid: this.circleFeature.get('uuid'), geometry: new ol.geom.Point(coordinates) }) if (this.centerStyle) { let _style = StyleFactory.getStyle(this.centerStyle); this.centerFeature.setStyle(_style); } this.layer.getSource().addFeature(this.centerFeature); } else { this.centerFeature.setGeometry(new ol.geom.Point(coordinates)); } } else { if (!this.labelFeature) { this.labelFeature = new ol.Feature({ uuid: this.circleFeature.get('uuid'), geometry: new ol.geom.Point(coordinates) }); let _style = StyleFactory.getStyle({ image: { type: 'icon', image: { imageSrc: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACIAAAATCAYAAAGCZu9cAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoV2luZG93cykiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6QTAyQjQ0OTk5MUZGMTFFN0JCMzdENDYyNTY0RDI4MzAiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6QTAyQjQ0OUE5MUZGMTFFN0JCMzdENDYyNTY0RDI4MzAiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpBMDJCNDQ5NzkxRkYxMUU3QkIzN0Q0NjI1NjREMjgzMCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDpBMDJCNDQ5ODkxRkYxMUU3QkIzN0Q0NjI1NjREMjgzMCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Poms414AAAUoSURBVHjaYmxqamJg+PTJn+H//0gGBoYVtT09G1iADMm86uoNDBAQDsSMTEDi+bPHj9/9//eP4dWzZx9AMgABxAjW/vHjCrA6fv4Ixo8fPvwHAgYYYObi4rpnZmoaCLSAYfKUKSIAAcQA0nJkz54nP3/8+I+OTx858hykG2SZiJ6JifS7N28YXEqvMCDTqlpaEiCjAQIIYjkDAwvQAd0gJ0OtfAl0SD5EgoFBubys7A4DJsjr7OoC+unjxyXfv38HGw2ikdmcv36dZ2Lg4Dj5/etXhlXlEgwgGoX948cMJgZ29obZEybs5+TmZuDg5ARjEHt2f/8+Bj6+mQABBHMkI8PPn8YO9vbrbZydZZADCB0wMjIynDx06NnuLVscgR65VVtbCw4ODoYvX+aU1tScNraykgG578ePHwwOhRfANAzD+CB5PVNTqdLm5psMHz70gQwGGSLG8O+fyvcvX+B+8ai8AbYVxgdhEACJw/jfgOqBwAoW5sxA2gdoalVmebnZD6BNhAA7BwfDjK6uMwwCApZA7/wBxctfIN4IFNg9feZMTSBbCYi5cej/BsQPgPgaUP0XmCBAAMECFhK437+LMvz6lQtkq2JoB4U2IyPIn1OBAfoGJgwKWBYomxOYEFaVtbR4srKxMTPgih1gzABBfWtp6XagS7xhwqCAZWP4/HlGZUeHDzD6mP/8/s3w588f7Bgk9/s3I1CtFzAM5yEbouYTHOz+6+dPuGJQUgRhXPxfv34xRKWmBiIbog7MHiK/gbaAMCx6NzcpM8DEQGxYFMPEpBUUBIBBwAszhPPHt29//gBNB+H1NbJgDTA+DIMASA7G//v7939gAH+FGfLm6L59T0DOhNkCyjiBLY/hfBAbJAbjg9SePnr0CVDvP5ghVy5dv77q65cvH/8Cix2Yv5cVi2Bl//37F4S/Hd6/vxAWJqAofsbAyrp26ZIlDDrq6mFmtrZS3Dw8nNhiGJiaf549fvzZuXPnmhl4eDYgGwJy0nmgQS+v3Lt3EIjFQKUbFjNA6l4D8VUGTk64V0AAIMCQUywk1YIM/vVLDJhlE4EZ09vAzExMUU2ND5hfmAUEBdkZiASfP3369e3r1z9PHz78curwYZDlG4CJdQYwMt4hqwOleJhvYA7gBAacBsPXrx2egYG6RhYWEv/+/WMgFwgKC3OBaA0dHRFnb28FRiYm02sXLhRsWLbsEtBBsUAHPUdWzwKNZBFgKHjKiImVx9bWav6FJmxswK38Gpje1alFkhwIqGpriwJznfPmVasOXzl/PgXomAPIDuEHYh1gVMT5hIUp/gQWa9hKaa+a23D2thZVcHZGByBxkDqYg0B8dPAXWJa4BwQoXgElNAYGW+QczAuuy/794+Hm5maD5Q1kjOyIjfUKDNjUwDBIHtnx6PKgkAaWWUx8AgJ8wHaAKHKIgMroXwwsLM8e3b//QUxKSgjdt2uqpMF0SNtTBv/GByhiyAAkj67nN5pZzMzMDO/fvv326ePHG8jFNMgh74H4HjA/7li9aBF/YESErpS8vAiwvYARRStKxeBsbFGDTx5U8QKLf4aP799/XDpr1hlg1Z8Hqj2QHQKqia6DQ4WP79v69etNgBWPRUBUlJKMggLYQaASCJSD8NXw2OoVJiBmZmEBtibYGd69fv1h+Zw5d4BlzWJgSMwHqviCnmtg1SIohT0G6roAxPs2bNsmAWxmqAPDVhHoCn4g5iM5DzMyfmZgYnoLjPZLQDN3ACu6u0DRD9DkgAIAomQEZFjvy7gAAAAASUVORK5CYII=' } } }); this.labelFeature.set('free-hand-circle-lable', true); this.labelFeature.setStyle(_style); this.layer.getSource().addFeature(this.labelFeature); } else { this.labelFeature.setGeometry(new ol.geom.Point(coordinates)); } } } /** * 半径变化的实时显示 * @param text * @param coordinates * @private */ drawTextLabel_ (text, coordinates) { if (!this.textOverlay) { let editor = document.createElement('span'); editor.className = 'ole-free-hand-circle-label'; editor.innerHTML = text this.textOverlay = new ol.Overlay({ element: editor, position: coordinates, positioning: 'center-left', offset: [20, 0] }); this.getMap().addOverlay(this.textOverlay) } else { let element = this.textOverlay.getElement(); element.innerHTML = text; this.textOverlay.setPosition(coordinates); this.getMap().render(); } } /** * 获取更新后的icon * @param text * @returns {string} * @private */ getImageSrc_ (text) { let canvas = document.createElement('canvas'); let ctx = canvas.getContext('2d'); ctx.font = '30px Arial'; ctx.textAlign = 'center'; let width = ctx.measureText(text).width; let height = 20; canvas.width = width + 8; canvas.height = height + 4; ctx.fillText(text, 2, 10); ctx.fillStyle = 'white'; ctx.fillRect(0, 0, width, height); let image = canvas.toDataURL('image/.png', 1); return image; } /** * 转换半径 * @param center * @param meterRadius * @returns {number} */ transformRadius (center, meterRadius) { try { let lastCoords = this.wgs84Sphere.offset(center, meterRadius, (270 / 360) * 2 * Math.PI); // 计算偏移量 let [ptx, pty] = [(center[0] - lastCoords[0]), (center[1] - lastCoords[1])]; let transformRadiu = (Math.sqrt(Math.pow(ptx, 2) + Math.pow(pty, 2))); return transformRadiu } catch (e) { console.log(e) } } /** * 计算圆的半径 * @param center * @param coords * @returns {string} */ mathRadius (center, coords) { let radius_ = ''; if (center && coords) { let c1 = ol.proj.transform(this.center_, this._getProjectionCode(), 'EPSG:4326'); let c2 = ol.proj.transform(coords, this._getProjectionCode(), 'EPSG:4326'); let radius = this.wgs84Sphere.haversineDistance(c1, c2); if (this.options['maxRadius'] && radius > this.options['maxRadius']) { radius_ = this.options['maxRadius'] - 1 } else if (this.options['minRadius'] && radius < this.options['minRadius']) { radius_ = this.options['minRadius'] - 1 } else { radius_ = radius } radius_ = Math.floor(radius_) + 1 } return radius_ } /** * 获取当前视图投影 * @returns {string} * @private */ _getProjectionCode () { let code = ''; if (this.getMap()) { code = this.getMap().getView().getProjection().getCode(); } else { code = 'EPSG:3857'; } return code } /** * 重新设置半径 * @param radius */ setRadius (radius) { if (this.circleFeature && this.circleFeature.getGeometry()) { let geom = this.circleFeature.getGeometry(); let params = this.transformCenterAndRadius_(this.center_, radius); geom.setCenterAndRadius(params['center'], params['radius']); geom.dispatchEvent('change'); } else { throw new Error('未创建Circle实例。') } } /** * 重新设置中心点 * @param center */ setCenter (center) { if (this.circleFeature && this.circleFeature.getGeometry()) { let geom = this.circleFeature.getGeometry(); let params = this.transformCenterAndRadius_(center, this.radius); geom.setCenterAndRadius(params['center'], params['radius']); geom.dispatchEvent('change'); } else { throw new Error('未创建Circle实例。') } } /** * 重新设置半径和中心点 * @param center * @param radius */ setCenterRadius (center, radius) { if (this.circleFeature && this.circleFeature.getGeometry()) { let geom = this.circleFeature.getGeometry(); let params = this.transformCenterAndRadius_(center, radius); geom.setCenterAndRadius(params['center'], params['radius']); geom.dispatchEvent('change'); } else { throw new Error('未创建Circle实例。') } } /** * 设置激活状态 * @param active */ setActive (active) { super.setActive.call(this, active) } /** * 销毁 */ destroy () { if (this.draw) { this.removeLastInteraction_(); } if (this.textOverlay && this.textOverlay instanceof ol.Overlay) { this.getMap().removeOverlay(this.textOverlay); this.textOverlay = null; } if (this.layer) { this.layer.getSource().clear(); this.circleFeature = null; this.centerFeature = null; this.labelFeature = null; } this.coordinate_ = null; this.feature_ = null; this.drawStart_ = false; this.center_ = []; this.radius = ''; this.isDraging = false; this.isMouseDown = false; } } export default FreeHandCircle