在 OpenLayers 3 中,负责交互的模块中,有一个负责绘制图形的交互模块,这个交互子模块是 ol.interaction.Draw。该模块允许用户通过鼠标点击(PC浏览器环境)或者手指触摸( 触屏手机浏览器环境)在地图上绘制点、线 和 面,上一篇文章 中主要介绍了绘制功能的用法,这次我们看看其底层实现及其原理。
注:绘制完成之前的要素图形我们称之为草图(sketch),绘制完成的图形称为要素(feature)。
一、实现原理
绘制交互是通过鼠标或手指的点击添加点的坐标的,OpenLayers 会自动将 屏幕坐标转换为 地图坐标,点击绘制完成后,所有的点初始化一个 geometry 对象,然后利用这个 geometry 初始化一个 feature。在上一篇介绍绘制用法时,我们知道初始化一个绘制交互,要传一个 features 参数或者 source 参数,如果是 features,那么勾绘完成的 feature 就会添加到 features 集合中,而 features 会属于一个 source,而 source 又属于 layer,layer 属于一个 map,这样,勾绘的要素(feature)就会显示到地图中。这个过程比较麻烦,估计会绕晕,我们用一张图进行说明:
该类中,有几个私有变量,维护着绘制过程中的坐标和子要素或者绘制状态等内容,主要有以下几个:
- finishCoordinate_,绘制的要素的完成点坐标,对于多边形来说是第一个点,因为多边形要闭合,所以第一个点和最后一个点是重合的。而对于多边形来说,最后一个点就是最后一个点;
- sketchFeature_,草图的要素;
- sketchPoint_,草图的点要素;
- sketchCoords_,草图的点要素的坐标集合,用于绘制要素为线或多边形时;
- sketchLine_,草图的线要素,用于绘制要素为多边形时;
- sketchLineCoords_,草图的线坐标,当绘制多边形或圆形时用到;
二、实现细节
1、私有的辅助函数
ol.interaction.Draw 类中,私有的辅助函数包括:
- ol.interaction.Draw.handleDownEvent_,处理鼠标按下的事件;
- ol.interaction.Draw.handleUpEvent_,处理松开鼠标单击的事件;
ol.interaction.Draw.getMode_,获得绘制要素的 geometry 类型,包含四种:Point、LineString、Circle和Polygon。
ol.interaction.Draw.prototype.handlePointerMove_,处理鼠标移动事件;
- ol.interaction.Draw.prototype.atFinish_,判断一个事件是否在捕捉勾绘开始坐标的容差之内;
- ol.interaction.Draw.prototype.createOrUpdateSketchPoint_,创建或者更新一个点要素的坐标;
- ol.interaction.Draw.prototype.startDrawing_,获取事件对象的点坐标,根据设置的绘制类型,初始化一些维护坐标数据的私有变量,同时触发 drawstart 事件;
- ol.interaction.Draw.prototype.modifyDrawing_,获取事件的点坐标,利用该坐标,根据绘制要素类型,修改相应要素的第一个坐标(多边形)最后一个(线或圆)坐标;
- ol.interaction.Draw.prototype.addToDrawing_,获取事件对象包含的点坐标,并添加到当前绘制的要素;
- ol.interaction.Draw.prototype.abortDrawing_, 停止绘制,并返回 sketchFeature_ ;
- ol.interaction.Draw.prototype.updateSketchFeatures_,根据不同的情况,将 sketchFeature_ 、sketchLine_ 或 sketchPoint_ 对象 push 到 sketchFeatures 中,然后 在矢量图层中移除所有要素,并重新添加 sketchFeatures 中保存的所有要素,这个函数就像 Windows 系统下的桌面刷新功能差不多;
我们看他的实现就会看得非常明白:
/**
* Redraw the sketch features.
* @private
*/
ol.interaction.Draw.prototype.updateSketchFeatures_ = function() {
var sketchFeatures = [];
if (this.sketchFeature_) {
sketchFeatures.push(this.sketchFeature_);
}
if (this.sketchLine_) {
sketchFeatures.push(this.sketchLine_);
}
if (this.sketchPoint_) {
sketchFeatures.push(this.sketchPoint_);
}
var overlaySource = this.overlay_.getSource();
overlaySource.clear(true);
overlaySource.addFeatures(sketchFeatures);
};
- ol.interaction.Draw.prototype.updateState_,这个辅助函数主要是获取 draw 交互的状态,是 active 还是 deactive,具体实现如下:
/**
* @private
*/
ol.interaction.Draw.prototype.updateState_ = function() {
var map = this.getMap();
var active = this.getActive();
if (!map || !active) {
this.abortDrawing_();