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 相关文章推荐
javascript xml为数据源的下拉框控件
Jul 07 Javascript
js中文逗号转英文实现
Feb 11 Javascript
jquery实现的导航固定效果
Apr 28 Javascript
js自定义鼠标右键的实现原理及源码
Jun 23 Javascript
JS实现状态栏跑马灯文字效果代码
Oct 24 Javascript
jQuery动态修改字体大小的方法【测试可用】
Sep 09 Javascript
详解webpack 打包文件体积过大解决方案(code splitting)
Apr 10 Javascript
vue组件表单数据回显验证及提交的实例代码
Aug 30 Javascript
微信小程序动态显示项目倒计时
Jun 20 Javascript
JS前端知识点总结之页面加载事件,数组操作,DOM节点操作,循环和分支
Jul 04 Javascript
vue数据更新UI不刷新显示的解决办法
Aug 06 Javascript
vue实现动态给id赋值,点击事件获取当前点击的元素的id操作
Nov 09 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生成静态页面详解
2006/12/05 PHP
php trim 去除空字符的定义与语法介绍
2010/05/31 PHP
PHP fgetcsv 定义和用法(附windows与linux下兼容问题)
2012/05/29 PHP
php页面消耗内存过大的处理办法
2013/03/18 PHP
php 表单提交大量数据发生丢失的解决方法
2014/03/03 PHP
PHP去除字符串最后一个字符的三种方法实例
2017/03/01 PHP
nodejs文件操作模块FS(File System)常用函数简明总结
2014/06/05 NodeJs
JavaScript原生对象之Date对象的属性和方法详解
2015/03/13 Javascript
微信小程序 保留小数(toFixed)详细介绍
2016/11/16 Javascript
JS中如何实现复选框全选功能
2016/12/19 Javascript
Vue.js学习教程之列表渲染详解
2017/05/17 Javascript
Vue仿手机qq的实例代码(demo)
2017/09/08 Javascript
微信小程序实现自上而下字幕滚动
2018/07/14 Javascript
angular4 获取wifi列表中文显示乱码问题的解决
2018/10/20 Javascript
vue组件中iview的modal组件爬坑问题之modal的显示与否应该是使用v-show
2019/04/12 Javascript
Promise扫盲贴
2019/06/24 Javascript
微信小程序实现3D轮播图效果(非swiper组件)
2019/09/21 Javascript
Vue+ElementUI table实现表格分页
2019/12/14 Javascript
vue中 v-for循环的用法详解
2020/02/19 Javascript
vue单应用在ios系统中实现微信分享功能操作
2020/09/07 Javascript
angular8.5集成TinyMce5的使用和详细配置(推荐)
2020/11/16 Javascript
[03:49]DOTA2英雄基础教程 光之守卫
2014/01/14 DOTA
Python Selenium Cookie 绕过验证码实现登录示例代码
2018/04/10 Python
Python Flask 搭建微信小程序后台详解
2019/05/06 Python
python读取图片的方式,以及将图片以三维数组的形式输出方法
2019/07/03 Python
python中比较两个列表的实例方法
2019/07/04 Python
一款纯css3实现的颜色渐变按钮的代码教程
2014/11/12 HTML / CSS
原装进口全世界:天猫国际
2016/08/03 全球购物
JD Sports丹麦:英国领先的运动时尚零售商
2020/11/24 全球购物
《锄禾》教学反思
2014/04/08 职场文书
厨房领班竞聘演讲稿
2014/04/23 职场文书
运动会广播稿150字(9篇)
2014/09/20 职场文书
烛光里的微笑观后感
2015/06/17 职场文书
经营场所使用证明
2015/06/19 职场文书
医院保洁员管理制度
2015/08/05 职场文书
如何在python中实现ECDSA你知道吗
2021/11/23 Python