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使用手册之二 DOM操作
Mar 24 Javascript
JavaScript定义类或函数的几种方式小结
Jan 09 Javascript
javascript获取URL参数与参数值的示例代码
Dec 20 Javascript
详解JavaScript权威指南之对象
Sep 27 Javascript
网络传输协议(http协议)
Nov 18 Javascript
利用JS判断客户端类型你应该知道的四种方法
Dec 22 Javascript
关于express与koa的使用对比详解
Jan 25 Javascript
vue.js,ajax渲染页面的实例
Feb 11 Javascript
JavaScript类型相关的常用操作总结
Feb 14 Javascript
微信小程序 下拉刷新及上拉加载原理解析
Nov 06 Javascript
ElementUI Tree 树形控件的使用并给节点添加图标
Feb 27 Javascript
Element图表初始大小及窗口自适应实现
Jul 10 Javascript
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
php获取数组长度的方法(有实例)
2013/10/27 PHP
PHP基于mssql扩展远程连接MSSQL的简单实现方法
2016/10/08 PHP
PHPExcel中文帮助手册|PHPExcel使用方法(分享)
2017/06/09 PHP
PHP的PDO大对象(LOBs)
2019/01/27 PHP
读jQuery之三(构建选择器)
2011/06/11 Javascript
Jquery遍历节点的方法小集
2014/01/22 Javascript
JavaScript 动态加载脚本和样式的方法
2015/04/13 Javascript
jQuery实现的多滑动门,多选项卡效果代码
2016/03/28 Javascript
vue数据双向绑定原理解析(get &amp; set)
2017/03/08 Javascript
HTML中使背景图片自适应浏览器大小实例详解
2017/04/06 Javascript
Easyui ueditor 整合解决不能编辑的问题(推荐)
2017/06/25 Javascript
详解如何在angular2中获取节点
2017/11/23 Javascript
JavaScript中严格判断NaN的方法
2018/02/16 Javascript
搭建element-ui的Vue前端工程操作实例
2018/02/23 Javascript
ES6中Set和Map数据结构,Map与其它数据结构互相转换操作实例详解
2019/02/28 Javascript
vue 解决无法对未定义的值,空值或基元值设置反应属性报错问题
2020/07/31 Javascript
详解React的回调渲染模式
2020/09/10 Javascript
vue-router 控制路由权限的实现
2020/09/24 Javascript
Python最长公共子串算法实例
2015/03/07 Python
Django Highcharts制作图表
2016/08/27 Python
Tornado 多进程实现分析详解
2018/01/12 Python
django 实现编写控制登录和访问权限控制的中间件方法
2019/01/15 Python
深入理解Django-Signals信号量
2019/02/19 Python
Keras loss函数剖析
2020/07/06 Python
暇步士官网:Hush Puppies
2016/09/22 全球购物
英国网上超市:Ocado
2020/03/05 全球购物
工商管理专业职业生涯规划
2014/01/01 职场文书
经典促销广告词大全
2014/03/19 职场文书
超市仓管员岗位职责
2014/04/07 职场文书
三八红旗集体先进事迹材料
2014/05/22 职场文书
2014乡镇机关党员个人对照检查材料思想汇报
2014/10/09 职场文书
会计岗位职责范本
2015/04/02 职场文书
2015年世界无烟日活动方案
2015/05/04 职场文书
给领导敬酒词
2015/08/12 职场文书
篮球拉拉队口号
2015/12/25 职场文书
《现实主义勇者的王国再建记》第三弹OST全曲试听片段公开
2022/04/04 日漫