OpenLayers源码分析(五) ? Canvas.js | 少将全栈
  • 欢迎访问少将全栈,学会感恩,乐于付出,珍惜缘份,成就彼此、推荐使用最新版火狐浏览器和Chrome浏览器访问本网站。
  • 吐槽,投稿,删稿,交个朋友
  • 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏少将全栈吧

OpenLayers源码分析(五) ? Canvas.js

点滴 admin 9年前 (2016-05-18) 2327次浏览 已收录 扫描二维码

直接继承至Renderer抽象类;

Properties

hitDetection     {Boolean} Allow for hit detection of features.

hitOverflow     {Number} The method for converting feature identifiers to color values supports 16777215 sequential values.

canvas     {Canvas} The canvas context object.

features     {Object} Internal object of feature/style pairs for use in redrawing the layer.

pendingRedraw     {Boolean} The renderer needs a redraw call to render features added while the renderer was locked.



hitDetection : feature碰撞检测; 用于解决extranelGraphics绘制与获取. 详见: http://trac.osgeo.org/openlayers/ticket/3238

hitOverflow : 存储碰撞溢出值, 用于分辨两个不同的要素, 最多16777215; 如果两个要素id相差超过这个值将不能够被正确检测;

canvas : Canvas容器;

features : 缓存feature/style组合对, 用于layer.redraw;

pendingRedraw : 如果renderer.locked == true, 则暂缓redraw操作;



initialize : 构造函数, 首先执行父类构造函数;

OpenLayers.Renderer.prototype.initialize.apply(this, arguments);

root用于存储document.createElement(“canvas”)创建出来的Canvas对象;

container则将root作为元素储存, container.appendChild(this.root);

canvas则是root.getContext(“2d”)

如果设置了hitDetection, 则另外创建hitCanvas后台hitContext;



supported : 通过创建canvas元素, 调用getContext方法测试浏览器是否支持;



eraseGeometry : 在this.features缓存里通过featureId查找feature, 然后earseFeatures();



earseFeatures : 删除this.features里具体feature对象引用, 然后redraw();



redraw : 遍历所有数据然后重绘; 并不像Elements-based基于Elements的渲染器, 一旦要素绘制完成之后是无法再交互的,  所以每次你都只能重新绘制( draw from scratch);

绘制过程分三步, 一是清空绘制区域; 二是绘制geometry, 三是绘制label, 绘制均基于feature/style键值对;



drawFeature : 原理是保存feature到this.features;然后重绘redraw();

判断style.display/bounds/bounds.intersectsBounds(this.extent), 如果需要绘制, 则保存到this.features, 通过feature.id索引; 如果不需要绘制, 则从this.features里删除;



drawGeometry : Facade模式, 统一绘制过程, 内部判断geometry类型, 如果是聚合要素类型, 则递归调用; 如果是单一要素类型, 则调用相应的绘制函数, 如drawPoint, drawLineString, drawLinearRing, drawPolygon;



drawPoint : 必须具有style.graphic属性, 如果包含externalGraphic, 则通过drawExternalGraphic方法绘制;

首先, 通过getLocalXY方法将geometry(point)的地理xy转换成像素xy;

然后, 根据style设置canvas绘制样式, 这里分两种类型, 一是fill, 则设置globalAlpha, fillStyle, 二是stroke, 则设置globalAlpha, strokeStyle, lineWidth;

然后beginPath(); arc(); fill()/stroke();

arc()方法定义的参数包括: x,y,radius,startAngle,endAngle,anticlockwise;

对应的点要素绘制参数: p0, p1, radius, 0, twoPi, true;

其中, 半径值radius由style.pointRadius设置;

最后, 清空canvas绘制样式, globalAlpha = 0; lineWidth = 1;



drawExternalGraphic : 绘制外部图像; 创建new Image()对象; 绑定onload事件, 调用canvas.drawImage方法绘制图像;



drawLineString : 内部调用drawLinearRing方法, 只不过之前设置style样式的fill : false;



drawLinearRing : 内部调用renderPath方法; 绘制线型环, 样式能够fill或者stroke;



renderPath : 方法参数: context, geometry, style, featureId, type;

Path绘制方法: 首先ctx.beginPath(), moveTo()第一个点; lineTo()下一个点; fill()/stroke();



drawPolygon : 首先绘制外层多边形components[0], 调用drawLinearRing; 然后擦除内部环;

擦除内部环, 在2.11里采用了一种激进的绘制方式; 在同一个canvas里处理holes, 而这之前可能已经绘制其他多边形;

更好的处理办法是: 在临时canvas里绘制包含holes的多边形, 然后复制到layer canvas里;

http://trac.osgeo.org/openlayers/ticket/3130

那么, 这里的处理方式是设置canvas.globalCompositeOperation = ”destination-out”;

然后以{stroke: false, fillOpacity: 1.0}样式绘制内部环;

这一步是为了清除内环填充;

再设置canvas.globalCompositeOperation = “source-over”;

然后以{fill: false}样式绘制内部环;

这一步是为了绘制内环边界;

至于, canvas.globalCompositeOperation属性设置详见: http://elementstorm.iteye.com/blog/757605

幸好, 不同的浏览器对于destination-out和source-over支持是一致的;

对于浏览器的支持效果, 详见: https://developer.mozilla.org/samples/canvas-tutorial/6_1_canvas_composite.html



drawText : 需要设置canvas的属性较多, 包括fillStyle, globalAlpha, font, textAlign, textBaseline;

最后使用fillText的HTML5方法绘制; 其次采用mozDrawText方法绘制;

label里如果包含
, 将会分行绘制;


fillText方法参数text,x,y,maxWidth;

所以分行绘制需要计算每行的y值;

行高计算方法: var lineHeight =

this.canvas.measureText(‘Mg’).height ||

this.canvas.measureText(‘xx’).width;



clear : 主要完成两个动作: 其一this.canvas.clearRect(0, 0, width, height);其二.features = {};



featureIdToHex : 将feature.id转换成RGB Hex值;



setHitContextStyle : 利用featureIdToHex将featureId转换成rgb颜色值, 然后根据图形形状在hitContext绘制对应颜色的要素;

这样, 就实现了通过hit方式方向查询到featureId的解决方案; 最终都在getFeatureIdFromEvent方法里得到体现;



getFeatureIdFromEvent :  只有在hitDetection开启时返回feature, 否则返回

var data = this.hitContext.getImageData(x, y, 1, 1).data; -> 获取RGB像素值;

然后将RGB像素值转换成Hex值;

Hex值再经过处理, id ? 1 + this.hitOverflow 即是 featureId;

Hex值FFFFFF : 16777215;


http://www.openlayers.cn/forum.php?mod=viewthread&tid=44&extra=page%3D5

喜欢 (0)
[🍬谢谢你请我吃糖果🍬🍬~]
分享 (0)
关于作者:
少将,关注Web全栈开发、项目管理,持续不断的学习、努力成为一个更棒的开发,做最好的自己,让世界因你不同。