OpenLayer3 之 实现拉框放大功能


几天前,有人给我发邮件询问如何实现划定一个矩形区域实现放大功能,即所谓的“拉框放大”,在 ol3 中,其实已有实现鼠标拖拽放大地图功能,默认需要配合 shift,按住shift,拖拽鼠标的同时,地图会放大,该组件名为 ol.interaction.DragZoom,该组件的缺点是不实用(哪一个非专业人员会想的按住shift拖动)。本文首先介绍该组件的实现,随后基于该组件,在地图上放置拉框按钮,实现一个较为实用的拖拽放大功能。

本文完整代码共享在了GitHub中:https://github.com/QingyaFan/openlayers3-examples

ol.interaction.DragZoom

拉框放大,首先你要拉框,然后根据用户拉出的矩形区域放大到合适地图视口的最大级别。拉框也不必我们实现,ol3 也已经有实现:ol.interaction.DragBox,为了基于 dragbox 组件实现拉框,ol.interaction.DragZoom继承了ol.interaction.DragBox。具体实现如下:

// dragzoom 构造函数
ol.interaction.DragZoom = function(opt_options) {
  var options = opt_options ? opt_options : {};
  // 触发拉框放大功能的情形
  // 此处为按下 shift 键,mac 是 cmd 键
  var condition = options.condition ? options.condition :  ol.events.condition.shiftKeyOnly;
  // 放大过程的时间
  this.duration_ = options.duration !== undefined ? options.duration : 200;
  // 是放大还是缩小,默认放大
  this.out_ = options.out !== undefined ? options.out : false;
  // 调用 dragbox 的构造函数,并将样式赋予 dragbox,如果没有指定,默认 `ol-dragzoom`
  ol.interaction.DragBox.call(this, {
    condition: condition,
    className: options.className || 'ol-dragzoom'
  });
};
// 继承 dragzoom
ol.inherits(ol.interaction.DragZoom, ol.interaction.DragBox);

处理完拉框,那么当拉框结束时,需要获取用户框定的区域,并实现地图的缩放,这里利用了 dragbox 的 boxend 事件:

ol.interaction.DragZoom.prototype.onBoxEnd = function() {

  // 获取 map 实例
  var map = this.getMap();

  var view = /** @type {!ol.View} */ (map.getView());
  var size = /** @type {!ol.Size} */ (map.getSize());

  // 获取用户框定的坐标范围
  var extent = this.getGeometry().getExtent();

  // 设置为拉框缩小时应进行的处理
  if (this.out_) {
    var mapExtent = view.calculateExtent(size);
    var boxPixelExtent = ol.extent.createOrUpdateFromCoordinates([
      map.getPixelFromCoordinate(ol.extent.getBottomLeft(extent)),
      map.getPixelFromCoordinate(ol.extent.getTopRight(extent))]);
    var factor = view.getResolutionForExtent(boxPixelExtent, size);

    ol.extent.scaleFromCenter(mapExtent, 1 / factor);
    extent = mapExtent;
  }

  var resolution = view.constrainResolution(view.getResolutionForExtent(extent, size));

  var center = ol.extent.getCenter(extent);
  center = view.constrainCenter(center);

  // 设置缩放时动画效果
  view.animate({
    resolution: resolution,
    center: center,
    duration: this.duration_,
    easing: ol.easing.easeOut
  });

};

实现拉框放大控件

在地图上放置拉框按钮,样式依赖了 bootstrap:

<div id="map" class="map">
  <div class="x-zoom-icons">
    <span id="zoom_in" class="glyphicon glyphicon-zoom-in"></span>
  </div>
</div>

接下来初始化空间,并绑定触发事件:

var dragzoomActive = false;
// 初始化一个拉框控件
var dragZoom = new ol.interaction.DragZoom({
  condition: ol.events.condition.always,
  // out: true, // 此处为设置拉框完成时放大还是缩小
});
map.addInteraction(dragZoom);
dragZoom.setActive(false);
// 绑定放大缩小按钮事件
document.querySelector("#zoom_in").addEventListener('click', function() {
  if (dragzoomActive) {
    dragZoom.setActive(false);
    dragzoomActive = false;
    document.querySelector("#map").style.cursor = "default";
  } else {
    dragZoom.setActive(true);
    dragzoomActive = true;
    document.querySelector("#map").style.cursor = "crosshair";
  }
}, false);

这样就可以很好的实现拉框放大,当然,如果你不喜欢默认的框样式,你可以修改,默认使用的 ol-dragzoom这个类名,你也可以在初始化时指定,这在上面的代码注释中说明了。实现的效果如下:


这里写图片描述

拉框后:


这里写图片描述

总结

实现起来还是很容易,不过这个交互组件并不能动态设置 out_ 属性,这样我们不得不实例化两个 dragzoom 实例,才能同时实现放大和缩小,有待改进,有时间看看能不能 push 一下。

好的,就这样。

本文完整代码共享在了GitHub中:https://github.com/QingyaFan/openlayers3-examples

转载自:https://blog.csdn.net/qingyafan/article/details/57127724

You may also like...