OpenLayer学习之自定义测量控件


Posted in Javascript onSeptember 28, 2020

OpenLayer 学习之自定义测量控件(目前ol3的版本不会抛异常)

一、自定义控件是在继承基类空间基础上实现的,控件不是我写的(毕竟技术有限)最近也在一直在研究源码进行模仿想写出自己的功能更为强大的控件。

二、控件源码

1、css样式设置

.tooltip {
 position: relative;
 background: rgba(0, 0, 0, 0.5);
 border-radius: 4px;
 color: white;
 padding: 4px 24px 4px 8px;
 opacity: 0.7;
 white-space: nowrap;
}
.tooltip-measure {
 opacity: 1;
 font-weight: bold;
}
.tooltip-static {
 background-color: #ffcc33;
 color: black;
 border: 1px solid white;
}
.tooltip-measure:before,
.tooltip-static:before {
 border-top: 6px solid rgba(0, 0, 0, 0.5);
 border-right: 6px solid transparent;
 border-left: 6px solid transparent;
 content: "";
 position: absolute;
 bottom: -6px;
 margin-left: -7px;
 left: 50%;
}
.tooltip-static:before {
 border-top-color: #ffcc33;
}
.ol-popup-closer {
  text-decoration: none;
  position: absolute;
  top: 4px;
  right: 8px;
  color: red;
}
.ol-popup-closer:after {
  content: "✖";
}
/*MeasureTool*/

.MeasureTool{
 position: absolute;
 top: 2.0em;
 right: 5em;
 text-align: left;
 padding: 0;
}
.MeasureTool .ulbody{
 display: none;
}
.MeasureTool.shown .ulbody{
 display: block;
}
.ulbody li input:focus, .ulbody li input:hover {
 background-color: white;
 color: blue;
 font-weight: bold;
}
.MeasureTool ul {
 padding: 0;
 list-style: none;
 margin: 0;
}
.MeasureTool ul li{
 text-align: center;
}
.MeasureTool>ul>li>input{
 background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAABiUlEQVRIS8WUQU7CQBSG/ze6lxsoJxCPYMpePIG4almJW2giJq1xJ6ykbuAG6p6GIwgnkBsYtwb7zGsZLKUk0tI4m6btzP/N/+bNTyh4UMH6+D+A7fkdACwOHdO4TTq1vVENoGP9PW2O/NvowPb8UDwafO6Y1Zc4xO77ExDigFStvwEYPccymhrQGYxL86/gIw50TCM7gBkz1zLKWrD16NeVwgCMqXaRGcDgTwIdzANVvm+czgTS9kZDAl0AkLO5WZxTNgfM/EpEZwxcu6bRjQD+jIDDgNSJ4uAtFyAIcCnlEJBrVWutp3FFRMWZa1ZLuhkyl0hKs6+Cd73Ltuc3CXjQwNwA2ZkuibQrM+pSMnF21zCGOwHYfb8LwhUYPSauxw99N4Do1j7/3jtMHcuoyHsegESFxET4lN7Hnpoo/j6Kvkc3exEpy3nJSCk+7OKhtinYton0pB6thlooFZYkx1hZnwbIob2+NA2wlv1bEsNs0kMAK5Z012wpupye1Cu+i7Lu9K/rCnfwA90A1i8VnCB2AAAAAElFTkSuQmCC') /*logo.png*/;
 background-position: center center;
 background-repeat: no-repeat;
}
.MeasureTool input[type="button"]{
 background-color: rgba(255, 255, 255, 0.4);
 width: 60px;
 height: 26px;
 border: 0;
}
.MeasureTool .ulbody li{
 border-top: 1px solid rgba(221, 221, 221, 0.4);
}

2、JS源码

/**
 * OpenLayers 3 MeasureTool Control.
 * See [the examples](./examples) for usage.
 * @constructor
 * @extends {ol.control.Control}
 * @param {Object} opt_options Control options, extends olx.control.ControlOptions adding:
 *               **`tipLabel`** `String` - the button tooltip.
 */
//构造函数
ol.control.MeasureTool = function(opt_options) {

 var options = opt_options || {};

 this.sphereradius = options.sphereradius ?
  options.sphereradius : 6378137;

 this.mapListeners = [];

 // hiddenclass
 this.hiddenClassName = 'ol-control MeasureTool';
 if (ol.control.MeasureTool.isTouchDevice_()) {
   this.hiddenClassName += ' touch';
 }
 // shownClass
 this.shownClassName = this.hiddenClassName + ' shown';

 var element = document.createElement('div');
 element.className = this.hiddenClassName;

 this.panel = document.createElement('ul');
 element.appendChild(this.panel);

 var ulheader = document.createElement('li');
 this.panel.appendChild(ulheader);

 var inputMeasure = document.createElement('input');
 inputMeasure.type = "button";
 ulheader.appendChild(inputMeasure);

 var ulbody = document.createElement('li');
 this.panel.appendChild(ulbody);

 var html = '';
 html += '<ul class="ulbody">';
 html += '<li><input type="button" value="Line"></li>';
 html += '<li><input type="button" value="Area"></li>';
 html += '<li><input type="checkbox" value="no"></li>';
 html += '</ul>';
 ulbody.innerHTML = html;

 var this_ = this;

 inputMeasure.onmouseover = function(e) {
  this_.showPanel();
 };
 inputMeasure.onclick = function(e) {
   e = e || window.event;
   this_.showPanel();
   e.preventDefault();
 };

 var lis = ulbody.getElementsByTagName("li");

 this.sourceMesure = new ol.source.Vector();
 this.vectorMesure = new ol.layer.Vector({
   source: this.sourceMesure,
  style: new ol.style.Style({
   fill: new ol.style.Fill({
    color: 'rgba(255, 255, 255, 0.2)'
   }),
   stroke: new ol.style.Stroke({
    color: '#ffcc33',
    width: 2
   }),
   image: new ol.style.Circle({
    radius: 7,
    fill: new ol.style.Fill({
     color: '#ffcc33'
    })
   })
  })
 });

 //type length or area
 var typeSelect={};
 //Line start
 lis[0].onclick = function(e) {
  typeSelect.value = 'length';
  typeSelect.check = lis[2].getElementsByTagName("input")[0].checked;
  this_.mapmeasure(typeSelect);
 };
 //Area start
 lis[1].onclick = function(e) {
  typeSelect.value = 'area';
  typeSelect.check = lis[2].getElementsByTagName("input")[0].checked;
  this_.mapmeasure(typeSelect);
 };

 this_.panel.onmouseout = function(e) {
   e = e || window.event;
   if (!this_.panel.contains(e.toElement || e.relatedTarget)) {
     this_.hidePanel();
   }
 };

 ol.control.Control.call(this, {
   element: element,
 });

};
//继承
ol.inherits(ol.control.MeasureTool, ol.control.Control);

ol.control.MeasureTool.prototype.mapmeasure = function(typeSelect) {
  var source = this.sourceMesure;
  var vector = this.vectorMesure;
 var wgs84Sphere = new ol.Sphere(this.sphereradius);

 var sketch;
 var helpTooltipElement;
 var measureTooltipElement;
 var measureTooltip;

 var map = this.getMap();
 map.addLayer(vector);

 map.getViewport().addEventListener('mouseout', function() {
  helpTooltipElement.classList.add('hidden');
 });

 var draw; // global so we can remove it later

 var formatLength = function(line) {
  var length;
  if (typeSelect.check) {
   var coordinates = line.getCoordinates();
   length = 0;
   var sourceProj = map.getView().getProjection();
   for (var i = 0, ii = coordinates.length - 1; i < ii; ++i) {
    var c1 = ol.proj.transform(coordinates[i], sourceProj, 'EPSG:4326');
    var c2 = ol.proj.transform(coordinates[i + 1], sourceProj, 'EPSG:4326');
    length += wgs84Sphere.haversineDistance(c1, c2);
   }
  } else {
   var sourceProj = map.getView().getProjection();
   var geom = /** @type {ol.geom.Polygon} */(line.clone().transform(
     sourceProj, 'EPSG:3857'));
   length = Math.round(geom.getLength() * 100) / 100;
   // length = Math.round(line.getLength() * 100) / 100;
  }
  var output;
  if (length > 100) {
   output = (Math.round(length / 1000 * 100) / 100) +
     ' ' + 'km';
  } else {
   output = (Math.round(length * 100) / 100) +
     ' ' + 'm';
  }
  return output;
 };

 var formatArea = function(polygon) {
  if (typeSelect.check) {
   var sourceProj = map.getView().getProjection();
   var geom = /** @type {ol.geom.Polygon} */(polygon.clone().transform(
     sourceProj, 'EPSG:4326'));
   var coordinates = geom.getLinearRing(0).getCoordinates();
   area = Math.abs(wgs84Sphere.geodesicArea(coordinates));
  } else {
   var sourceProj = map.getView().getProjection();
   var geom = /** @type {ol.geom.Polygon} */(polygon.clone().transform(
     sourceProj, 'EPSG:3857'));
   area = geom.getArea();
   // area = polygon.getArea();
  }
  var output;
  if (area > 10000) {
   output = (Math.round(area / 1000000 * 100) / 100) +
     ' ' + 'km<sup>2</sup>';
  } else {
   output = (Math.round(area * 100) / 100) +
     ' ' + 'm<sup>2</sup>';
  }
  return output;
 };

 var popupcloser = document.createElement('a');
 popupcloser.href = 'javascript:void(0);';
 popupcloser.classList.add('ol-popup-closer');

 function addInteraction() {
  var type = (typeSelect.value == 'area' ? 'Polygon' : 'LineString');
  draw = new ol.interaction.Draw({
   source: source,
   type: /** @type {ol.geom.GeometryType} */ (type),
   style: new ol.style.Style({
    fill: new ol.style.Fill({
     color: 'rgba(255, 255, 255, 0.2)'
    }),
    stroke: new ol.style.Stroke({
     color: 'rgba(0, 0, 0, 0.5)',
     lineDash: [10, 10],
     width: 2
    }),
    image: new ol.style.Circle({
     radius: 5,
     stroke: new ol.style.Stroke({
      color: 'rgba(0, 0, 0, 0.7)'
     }),
     fill: new ol.style.Fill({
      color: 'rgba(255, 255, 255, 0.2)'
     })
    })
   })
  });
  map.addInteraction(draw);

  createMeasureTooltip();
  createHelpTooltip();

  var listener;
  draw.on('drawstart',
   function(evt) {
    // set sketch
    sketch = evt.feature;

    /** @type {ol.Coordinate|undefined} */
    var tooltipCoord = evt.coordinate;

    listener = sketch.getGeometry().on('change', function(evt) {
     try {
      var geom = evt.target;
      var output;
      if (geom instanceof ol.geom.Polygon) {
       output = formatArea(geom);
       tooltipCoord = geom.getInteriorPoint().getCoordinates();
      } else if (geom instanceof ol.geom.LineString) {
       output = formatLength(geom);
       tooltipCoord = geom.getLastCoordinate();
      }
      measureTooltipElement.innerHTML = output;
      measureTooltip.setPosition(tooltipCoord);
     } catch (e) {
      map.removeInteraction(draw);
     } finally {
     }

    });
   }, this);

  draw.on('drawend',
    function() {
     measureTooltipElement.appendChild(popupcloser);
     measureTooltipElement.className = 'tooltip tooltip-static';
     measureTooltip.setOffset([0, -7]);
     // unset sketch
     sketch = null;
     // unset tooltip so that a new one can be created
     measureTooltipElement = null;
     createMeasureTooltip();
     ol.Observable.unByKey(listener);
     //end
     map.removeInteraction(draw);
     // map.getInteractions().item(1).setActive(false);
    }, this);
 }

 function createHelpTooltip() {
  if (helpTooltipElement) {
   helpTooltipElement.parentNode.removeChild(helpTooltipElement);
  }
  helpTooltipElement = document.createElement('div');
  helpTooltipElement.className = 'tooltip hidden';
 }
 function createMeasureTooltip() {
  if (measureTooltipElement) {
   measureTooltipElement.parentNode.removeChild(measureTooltipElement);
  }
  measureTooltipElement = document.createElement('div');
  measureTooltipElement.className = 'tooltip tooltip-measure';
  measureTooltip = new ol.Overlay({
   element: measureTooltipElement,
   offset: [0, -15],
   positioning: 'bottom-center'
  });
  map.addOverlay(measureTooltip);
 }

 //clear
 popupcloser.onclick = function(e) {
  map.getOverlays().clear();
  vector.getSource().clear();
  // map.removeLayer(vector);
 };

 addInteraction();
};

/**
 * Show the MeasureTool.
 */
ol.control.MeasureTool.prototype.showPanel = function() {
  if (this.element.className != this.shownClassName) {
    this.element.className = this.shownClassName;
  }
};

/**
 * Hide the MeasureTool.
 */
ol.control.MeasureTool.prototype.hidePanel = function() {
  if (this.element.className != this.hiddenClassName) {
    this.element.className = this.hiddenClassName;
  }
};

/**
 * Set the map instance the control is associated with.
 * @param {ol.Map} map The map instance.
 */
ol.control.MeasureTool.prototype.setMap = function(map) {
  // Clean up listeners associated with the previous map
  for (var i = 0, key; i < this.mapListeners.length; i++) {
    this.getMap().unByKey(this.mapListeners[i]);
  }
  this.mapListeners.length = 0;
  // Wire up listeners etc. and store reference to new map
  ol.control.Control.prototype.setMap.call(this, map);
  if (map) {
    var this_ = this;
    this.mapListeners.push(map.on('pointerdown', function() {
      this_.hidePanel();
    }));
  }
};

/**
 * Generate a UUID
 * @returns {String} UUID
 *
 * Adapted from http://stackoverflow.com/a/2117523/526860
 */
ol.control.MeasureTool.uuid = function() {
  return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
    var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
    return v.toString(16);
  });
}

/**
* @private
* @desc Apply workaround to enable scrolling of overflowing content within an
* element. Adapted from https://gist.github.com/chrismbarr/4107472
*/
ol.control.MeasureTool.enableTouchScroll_ = function(elm) {
  if(ol.control.MeasureTool.isTouchDevice_()){
    var scrollStartPos = 0;
    elm.addEventListener("touchstart", function(event) {
      scrollStartPos = this.scrollTop + event.touches[0].pageY;
    }, false);
    elm.addEventListener("touchmove", function(event) {
      this.scrollTop = scrollStartPos - event.touches[0].pageY;
    }, false);
  }
};

/**
 * @private
 * @desc Determine if the current browser supports touch events. Adapted from
 * https://gist.github.com/chrismbarr/4107472
 */
ol.control.MeasureTool.isTouchDevice_ = function() {
  try {
    document.createEvent("TouchEvent");
    return true;
  } catch(e) {
    return false;
  }
};

三、使用控件

1、js控件引入

<script src="ol3-measuretool-master/measuretool.js"></script>

2、声明控件

new ol.control.MeasureTool( {sphereradius : 6378137}),

其中的参数sphereradius 是用来支持geodesic测量设置球体半径的,可根据不同的模型设置不同的半径大小,默认大小为6378137,在引入时也可以不传入该参数。

NOTE:测量工具中的checkbox选中为使用geodesic测量,未选中为不使用geodesic测量,默认为未选中。

四、总结

通过这几天的研究我发现如果要实现自定义控件,里面有部分函数我们不需要改动,在构造函数那一部分我们需要创建自己定义的标签,其他后面最后的几个函数是不需要改动的,待下次继续完善

Javascript 相关文章推荐
基于jquery的仿百度的鼠标移入图片抖动效果
Sep 17 Javascript
jQuery学习笔记之控制页面实现代码
Feb 27 Javascript
JavaScript中字符串与Unicode编码互相转换的实现方法
Dec 18 Javascript
jQuery实现左侧导航模块的显示与隐藏效果
Jul 04 Javascript
JavaScript面向对象分层思维全面解析
Nov 22 Javascript
使用mock.js随机数据和使用express输出json接口的实现方法
Jan 07 Javascript
Vue中保存数据到磁盘文件的方法
Sep 06 Javascript
微信小程序自定义组件传值 页面和组件相互传数据操作示例
May 05 Javascript
vuex根据不同的用户权限展示不同的路由列表功能
Sep 20 Javascript
JavaScript实现随机五位数验证码
Sep 27 Javascript
微信小程序返回上一级页面的实现代码
Jun 19 Javascript
VUE中鼠标滚轮使div左右滚动的方法详解
Dec 14 Vue.js
Vue中父子组件的值传递与方法传递
Sep 28 #Javascript
JSONObject与JSONArray使用方法解析
Sep 28 #Javascript
OpenLayer3自定义测量控件MeasureTool
Sep 28 #Javascript
Openlayers实现距离面积测量
Sep 28 #Javascript
Openlayers+EasyUI Tree动态实现图层控制
Sep 28 #Javascript
JS sort排序详细使用方法示例解析
Sep 27 #Javascript
vue中实现点击变成全屏的多种方法
Sep 27 #Javascript
You might like
给多个地址发邮件的类
2006/10/09 PHP
php中批量删除Mysql中相同前缀的数据表的代码
2011/07/01 PHP
浅谈php优化需要注意的地方
2014/11/27 PHP
php使用NumberFormatter格式化货币的方法
2015/03/21 PHP
PHP使用SOAP扩展实现WebService的方法
2016/04/01 PHP
php微信公众平台配置接口开发程序
2016/09/22 PHP
PDO的安全处理与事物处理方法
2016/10/31 PHP
php中static 静态变量和普通变量的区别
2016/12/01 PHP
php7安装yar扩展的方法详解
2017/08/03 PHP
PHP编程实现脚本异步执行的方法
2017/08/09 PHP
PHP析构函数destruct与垃圾回收机制的讲解
2019/03/22 PHP
日期函数扩展类Ver0.1.1
2006/09/07 Javascript
jquery的Tooltip插件 qtip使用详细说明
2010/09/08 Javascript
js 页面关闭前的出现提示的实现代码
2011/05/25 Javascript
this,this,再次讨论javascript中的this,超全面(经典)
2016/01/05 Javascript
JavaScript中获取时间的函数集
2016/08/16 Javascript
JavaScript学习笔记整理_简单实现枚举类型,扑克牌应用
2016/09/19 Javascript
promise处理多个相互依赖的异步请求(实例讲解)
2017/08/03 Javascript
移动端滑动切换组件封装 vue-swiper-router实例详解
2018/11/25 Javascript
详解使用React制作一个模态框
2019/03/14 Javascript
JS实现扫码枪扫描二维码功能
2020/01/03 Javascript
jquery简易手风琴插件的封装
2020/10/13 jQuery
Javascript柯里化实现原理及作用解析
2020/10/22 Javascript
用vite搭建vue3应用的实现方法
2021/02/22 Vue.js
[00:23]DOTA2群星共贺开放测试 25日无码时代来袭
2013/09/23 DOTA
[47:03]完美世界DOTA2联赛PWL S3 Galaxy Racer vs Phoenix 第二场 12.10
2020/12/13 DOTA
python爬取指定微信公众号文章
2018/12/20 Python
Pytorch实现神经网络的分类方式
2020/01/08 Python
Iconfont(矢量图标)+iconmoon(图标svg互转)配合javascript实现社交分享系统
2020/04/21 Python
美国著名手表网站:Timepiece
2017/11/15 全球购物
解释i节点在文件系统中的作用
2013/11/26 面试题
男方父母证婚词
2014/01/12 职场文书
幼儿教师师德承诺书
2014/05/23 职场文书
2015出纳试用期工作总结
2014/12/12 职场文书
钢琴师观后感
2015/06/12 职场文书
2016国庆节67周年红领巾广播稿
2015/12/18 职场文书