OpenLayer学习之自定义测量控件

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测量,默认为未选中。

四、总结

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

(0)

相关推荐

  • Openlayers实现测量功能

    本文实例为大家分享了Openlayers实现测量的具体代码,供大家参考,具体内容如下 由于公司项目需要使用到openlayers,就开始学习了openlayers,其中有一个需求需要用到测量功能,就参考<WebGisOpenlayers全面解析>写了一个小demo,话不多说,直接上代码: <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content=&qu

  • Openlayers实现距离面积测量

    本文实例为大家分享了Openlayers实现距离面积测量的具体代码,供大家参考,具体内容如下 CSS .ol-tooltip { position: relative; background: rgba(0, 0, 0, 0.5); border-radius: 4px; color: white; padding: 4px 8px; opacity: 0.7; white-space: nowrap; font-size: 12px; } .ol-tooltip-measure { opaci

  • OpenLayers3实现测量功能

    本文实例为大家分享了OpenLayers3实现测量功能的具体代码,供大家参考,具体内容如下 1. 前言 测量功能实现面积的测量以及长度的测量.通过鼠标绘制区域以及长度来进行测量.OpenLayers 3 框架没有提供测量控件,但提供了相应的接口,需要需要基于几何对象的相应接口,结合图形绘制功能实现. 2. 实现思路 (1)新建一个网页,引用 openlayers 3 开发库.jQuery 库与 bootstrap 库,并参照前面显示地图的文章,加载 OSM 瓦片图层. (2)在地图容器中,创建一

  • OpenLayer3自定义测量控件MeasureTool

    一直苦恼于OpenLayer3没有现成的测量工具,看了歪果仁做的图层控件,于是自己结合了官网上的measure实例和歪果仁的模板鼓捣出了一个测量工具控件. 下载地址 描述 基于Openlayers3所做的自定义控件,支持测量距离(line)和测量面积(area)以及geodesic测量 加载css和js文件后直接引用即可 使用JavaScript原生编写,不需要引入JQuery 使用效果如图: 使用方式 在html页面中引入OpenLayer3的css和js文件后再加入下载的measuretoo

  • Openlayers测量距离与面积的实现方法

    本文实例为大家分享了Openlayers测量距离与面积的具体代码,供大家参考,具体内容如下 1.地图测量功能 一般的地图的测量功能主要表现在两个方面,一是测量距离,一是测量面积:面积的测量是根据鼠标绘制的范围,通过地理坐标系的转换而计算出实际面积大小,距离的测量是根据鼠标在地图上绘制的点,实时计算出两点之间的实际距离,下面我们就在Openlayers3中来实现这一功能: 2.代码实现 <!DOCTYPE html> <html xmlns="http://www.w3.org/

  • OpenLayer学习之自定义测量控件

    OpenLayer 学习之自定义测量控件(目前ol3的版本不会抛异常) 一.自定义控件是在继承基类空间基础上实现的,控件不是我写的(毕竟技术有限)最近也在一直在研究源码进行模仿想写出自己的功能更为强大的控件. 二.控件源码 1.css样式设置 .tooltip { position: relative; background: rgba(0, 0, 0, 0.5); border-radius: 4px; color: white; padding: 4px 24px 4px 8px; opac

  • Android自定义日历控件实例详解

    为什么要自定义控件 有时,原生控件不能满足我们对于外观和功能的需求,这时候可以自定义控件来定制外观或功能:有时,原生控件可以通过复杂的编码实现想要的功能,这时候可以自定义控件来提高代码的可复用性. 如何自定义控件 下面我通过我在github上开源的Android-CalendarView项目为例,来介绍一下自定义控件的方法.该项目中自定义的控件类名是CalendarView.这个自定义控件覆盖了一些自定义控件时常需要重写的一些方法. 构造函数 为了支持本控件既能使用xml布局文件声明,也可在ja

  • Android自定义View控件实现多种水波纹涟漪扩散效果

    效果图 实现思路 这个效果实现起来并不难,重要的是思路 此View满足了多种水波纹涟漪扩散效果,这要求它能满足很多的变化 根据上面的样式,可以看出此View需要满足以下变化 圆圈从中心可循环向外扩散 圆圈之间的扩散间距可以改变 可控制扩散圆的渐变度 圆圈可以是线条样式或者实心样式 圆圈扩散的速度可以控制 适配圆圈不同大小下的扩散效果 具体实现 创建自定义属性 首先为View创建自定义的xml属性 在工程的values目录下新建attrs.xml文件 <declare-styleable name

  • asp.net webform自定义分页控件

    做web开发一直用到分页控件,自己也动手实现了个,使用用户自定义控件. 翻页后数据加载使用委托,将具体实现放在在使用分页控件的页面进行注册. 有图有真相,给个直观的认识: 自定义分页控件前台代码: <style type="text/css"> .pager-m-l { margin-left: 10px; } .pager { font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; fo

  • asp.net web页面自定义分页控件使用详解

    这几天学习了一下自定义分页控件,现将实现方法记录下来,亲测可以实现: 1.首先创建一个.ascx文件,命名为TurnPage,然后在里面写控件前台展示的界面: 2.然后在TurnPage.ascx.cs里面写相应的后台代码,代码如下: namespace Web { public delegate void GoToPage(int PageNum); public partial class TurnPage : System.Web.UI.UserControl { private GoTo

  • Android自定义表格控件满足人们对视觉的需求

    Android平台已经给我们提供了很多标准的组件,如:TextView.EditView.Button.ImageView.Menu等,还有许多布局控件,常见的有:AbsoluteLayout.LinerLayout.RelativeLayout.TableLayout等.但随着人们对视觉的需求,基本组件已无法满足人们求新求异的要求,于是我们常常会自定义组件,用来实现更美观的UI界面. 实现自定义控件通常有两种途径,一种是继承View类,重写其中的重要方法,另一种是继承ViewGroup类,通过

  • Android使用GridLayout绘制自定义日历控件

    效果图 思路:就是先设置Gridlayout的行列数,然后往里面放置一定数目的自定义日历按钮控件,最后实现日历逻辑就可以了. 步骤: 第一步:自定义日历控件(初步) 第二步:实现自定义单个日期按钮控件 第三步:将第二步得到的控件动态添加到第一步的布局中,并实现日期逻辑 第四步:编写单个日期点击监听器接口 第一步:自定义日历控件(初步) <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmln

  • Android自定义控件之自定义组合控件(三)

    前言: 前两篇介绍了自定义控件的基础原理Android自定义控件基本原理详解(一).Android自定义控件之自定义属性(二).今天重点介绍一下如何通过自定义组合控件来提高布局的复用,降低开发成本,以及维护成本. 使用自定义组合控件的好处? 我们在项目开发中经常会遇见很多相似或者相同的布局,比如APP的标题栏,我们从三种方式实现标题栏来对比自定义组件带来的好处,毕竟好的东西还是以提高开发效率,降低开发成本为导向的.  1.)第一种方式:直接在每个xml布局中写相同的标题栏布局代码 <?xml v

  • Android中View自定义组合控件的基本编写方法

    有很多情况下,我们只要运用好Android给我提供好的控件,经过布局巧妙的结合在一起,就是一个新的控件,我称之为"自定义组合控件". 那么,这种自定义组合控件在什么情况下用呢?或者大家在做项目时候会发现,某些布局会被重复的利用,同一个布局的XML代码块会被重复的复制黏贴多次,这样会造成代码结构混乱不说,代码量也会增大,各种控件都需要在Java代码中被申明和处理相应的逻辑,工作量着实不小,所以,必须要找到一个合理的"偷懒"的方式,开动脑经去怎么简化以上说的不必要的麻烦

随机推荐