OpenLayers源码学习19:瓦片 Posted on 2015-03-18 | In OpenLayers学习 | 看完grid终于知道wmts怎么组织瓦片的了…这回看看tile和子类image, 看看具体到某一张怎么操作 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487OpenLayers.Tile = OpenLayers.Class({ /** * 事件 * tile.events.register(type, obj, listener); * 支持事件类型: * beforedraw,loadstart,loadend,loaderror,reload,unload */ events: null, /** * 瓦片事件监听器: * new OpenLayers.Layer.OSM('osm', 'http://tile.openstreetmap.org/${z}/${x}/${y}.png', { * tileOptions: { * eventListeners: { * 'loadend': function(evt) { * // do something on loadend * } * } * } * }); */ eventListeners: null, id: null, //缓存自身所属的 <OpenLayers.Layer> layer: null, //请求的url url: null, //<OpenLayers.Bounds> bounds: null, // <OpenLayers.Size> size: null, //瓦片左上角的像素坐标 position: null, //加载标志 isLoading: false, // 构造 //参数: 所属图层, 像素位置, 边界, url, 大小, 配置项 initialize: function(layer, position, bounds, url, size, options) { this.layer = layer; this.position = position.clone(); this.setBounds(bounds); this.url = url; if (size) { this.size = size.clone(); }//自身缓存项 //唯一id this.id = OpenLayers.Util.createUniqueID("Tile_"); OpenLayers.Util.extend(this, options); this.events = new OpenLayers.Events(this); if (this.eventListeners instanceof Object) {//初始化监听 this.events.on(this.eventListeners); } }, // 销毁之前触发个事件 unload: function() { if (this.isLoading) { this.isLoading = false; this.events.triggerEvent("unload"); } }, //销毁 destroy:function() { this.layer = null; this.bounds = null; this.size = null; this.position = null; if (this.eventListeners) { this.events.un(this.eventListeners); } this.events.destroy(); this.eventListeners = null; this.events = null; }, //绘制, draw: function(force) { if (!force) { //强制的话, 会清掉此瓦片 this.clear(); } var draw = this.shouldDraw();//判断是否需要重绘 //事件 if (draw && !force && this.events.triggerEvent("beforedraw") === false) { draw = null; } return draw; }, // 判断是否需要重绘, 超出界限的不应该重绘 shouldDraw: function() { var withinMaxExtent = false, maxExtent = this.layer.maxExtent; if (maxExtent) { var map = this.layer.map;//map对象 var worldBounds = map.baseLayer.wrapDateLine && map.getMaxExtent();//优先用换日线 if (this.bounds.intersectsBounds(maxExtent, {inclusive: false, worldBounds: worldBounds})) { withinMaxExtent = true; } } return withinMaxExtent || this.layer.displayOutsideMaxExtent; }, //设置边界 setBounds: function(bounds) { bounds = bounds.clone(); if (this.layer.map.baseLayer.wrapDateLine) { var worldExtent = this.layer.map.getMaxExtent(), tolerance = this.layer.map.getResolution(); //计算换日线 bounds = bounds.wrapDateLine(worldExtent, { leftTolerance: tolerance, rightTolerance: tolerance }); } this.bounds = bounds; }, //瓦片移动 moveTo: function (bounds, position, redraw) { if (redraw == null) { redraw = true; } this.setBounds(bounds);//设置缓存 this.position = position.clone(); if (redraw) { this.draw(); } }, clear: function(draw) { // to be extended by subclasses }, CLASS_NAME: "OpenLayers.Tile"}); /* ====================================================================== OpenLayers/Tile/Image.js ====================================================================== */OpenLayers.Tile.Image = OpenLayers.Class(OpenLayers.Tile, { /** * tile.events.register(type, obj, listener); * 支持事件类型: beforeload */ //图片请求的地址 layer.getURL()拼出来的 url: null, //缓存dom元素 imgDiv: null, // 边框, 给gutter用的 frame: null, // 图片重载次数(Attempt-尝试) imageReloadAttempts: null, // 图层透明度 layerAlphaHack: null, // 异步请求id asyncRequestId: null, // 超过此配置的长度请求将会走post, 而不是get maxGetUrlLength: null, // canvas的画布 canvasContext: null, // 跨域关键字: 'anonymous' 或 'use-credentials', 对应头Access-Control-Allow-Origin crossOriginKeyword: null, //构造一个新<OpenLayers.Tile.Image>实例 initialize: function(layer, position, bounds, url, size, options) { //先是父类构造 OpenLayers.Tile.prototype.initialize.apply(this, arguments); this.url = url; //缓存url this.layerAlphaHack = this.layer.alpha && OpenLayers.Util.alphaHack();//透明度 if (this.maxGetUrlLength != null || this.layer.gutter || this.layerAlphaHack) { // 有gutter时候需要边框 this.frame = document.createElement("div"); this.frame.style.position = "absolute"; this.frame.style.overflow = "hidden"; } if (this.maxGetUrlLength != null) { OpenLayers.Util.extend(this, OpenLayers.Tile.Image.IFrame);//未指定 } }, //销毁 destroy: function() { if (this.imgDiv) { this.clear(); this.imgDiv = null; this.frame = null; } // 异步请求id this.asyncRequestId = null; OpenLayers.Tile.prototype.destroy.apply(this, arguments); }, //绘制 draw: function() { //父类绘制 var shouldDraw = OpenLayers.Tile.prototype.draw.apply(this, arguments); if (shouldDraw) { // 不是baselayer if (this.layer != this.layer.map.baseLayer && this.layer.reproject) { this.bounds = this.getBoundsFromBaseLayer(this.position); } if (this.isLoading) { //正在加载, 没加载 this._loadEvent = "reload"; } else { //置正在加载标志位 this.isLoading = true; this._loadEvent = "loadstart"; } //渲染, 定位 this.renderTile(); this.positionTile(); } else if (shouldDraw === false) { //不该绘制的就是卸载掉 this.unload(); } return shouldDraw;//返回标志位 }, //渲染瓦片 renderTile: function() { if (this.layer.async) { // 异步图层的话, 需要调用getURLasync var id = this.asyncRequestId = (this.asyncRequestId || 0) + 1; this.layer.getURLasync(this.bounds, function(url) { if (id == this.asyncRequestId) { this.url = url; this.initImage();//初始化image } }, this); } else { // 同步图层的话, 调用getURL this.url = this.layer.getURL(this.bounds); this.initImage(); } }, //定位瓦片 positionTile: function() { var style = this.getTile().style, size = this.frame ? this.size : this.layer.getImageSize(this.bounds),//有guuter的考虑边框 ratio = 1; if (this.layer instanceof OpenLayers.Layer.Grid) { //表格图层都是计算分辨率的比率 ratio = this.layer.getServerResolution() / this.layer.map.getResolution(); } style.left = this.position.x + "px"; style.top = this.position.y + "px"; style.width = Math.round(ratio * size.w) + "px";//四舍五入的 style.height = Math.round(ratio * size.h) + "px"; }, //从dom树上清理瓦片 clear: function() { //父类清理 OpenLayers.Tile.prototype.clear.apply(this, arguments); var img = this.imgDiv; if (img) { var tile = this.getTile(); //确定在layer上 if (tile.parentNode === this.layer.div) { this.layer.div.removeChild(tile); } this.setImgSrc();// if (this.layerAlphaHack === true) { img.style.filter = ""; } OpenLayers.Element.removeClass(img, "olImageLoadError");//删掉css样式 } this.canvasContext = null;//画布 }, //获得图片 getImage: function() { //存在图片 if (!this.imgDiv) { //克隆dom上的图片 this.imgDiv = OpenLayers.Tile.Image.IMAGE.cloneNode(false); var style = this.imgDiv.style;//拿到原有的样式 if (this.frame) { var left = 0, top = 0; if (this.layer.gutter) { left = this.layer.gutter / this.layer.tileSize.w * 100; top = this.layer.gutter / this.layer.tileSize.h * 100; } style.left = -left + "%"; style.top = -top + "%"; style.width = (2 * left + 100) + "%"; style.height = (2 * top + 100) + "%"; } style.visibility = "hidden";//先hidden, 再操作透明度 style.opacity = 0; if (this.layer.opacity < 1) { style.filter = 'alpha(opacity=' + (this.layer.opacity * 100) + ')'; } style.position = "absolute"; if (this.layerAlphaHack) { style.paddingTop = style.height; style.height = "0"; style.width = "100%"; } if (this.frame) { this.frame.appendChild(this.imgDiv); } } return this.imgDiv; }, // 传入{HTMLImageElement} setImage: function(img) { this.imgDiv = img; }, //初始化一张图片 initImage: function() { if (!this.url && !this.imgDiv) { // 没法加载 this.isLoading = false; return; } this.events.triggerEvent('beforeload');//事件 this.layer.div.appendChild(this.getTile());//添加dom this.events.triggerEvent(this._loadEvent);//触发自定义事件 var img = this.getImage();//初始化一个img var src = img.getAttribute('src') || '';//试图去取src if (this.url && OpenLayers.Util.isEquivalentUrl(src, this.url)) { this._loadTimeout = window.setTimeout( OpenLayers.Function.bind(this.onImageLoad, this), 0 );//在队列末尾onImageLoad } else { this.stopLoading();//停止加载 if (this.crossOriginKeyword) {//跨域标记 img.removeAttribute("crossorigin"); } OpenLayers.Event.observe(img, "load",//图片加载事件 OpenLayers.Function.bind(this.onImageLoad, this) ); OpenLayers.Event.observe(img, "error", OpenLayers.Function.bind(this.onImageError, this) ); this.imageReloadAttempts = 0; this.setImgSrc(this.url);//设置img的src } }, // 设置图片的src setImgSrc: function(url) { var img = this.imgDiv; if (url) { //先隐藏 img.style.visibility = 'hidden'; img.style.opacity = 0; // 如果是"data:"开头的 就加跨域标记 if (this.crossOriginKeyword) { if (url.substr(0, 5) !== 'data:') { img.setAttribute("crossorigin", this.crossOriginKeyword); } else { img.removeAttribute("crossorigin"); } } img.src = url; } else { // 没url的就的删掉img this.stopLoading(); this.imgDiv = null; if (img.parentNode) { img.parentNode.removeChild(img); } } }, // 判断img getTile: function() { return this.frame ? this.frame : this.getImage(); }, // 创建bb createBackBuffer: function() { if (!this.imgDiv || this.isLoading) { //正在加载不创建 return; } var backBuffer; if (this.frame) { backBuffer = this.frame.cloneNode(false); backBuffer.appendChild(this.imgDiv); } else { //bb是图片div backBuffer = this.imgDiv; } this.imgDiv = null; return backBuffer; }, // 图片加载. onImageLoad: function() { var img = this.imgDiv; this.stopLoading();//停止加载 img.style.visibility = 'inherit'; img.style.opacity = this.layer.opacity;//继承透明度 this.isLoading = false; this.canvasContext = null; this.events.triggerEvent("loadend"); if (this.layerAlphaHack === true) {//如需滤镜 img.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + img.src + "', sizingMethod='scale')"; } }, //加载失败 有个重新尝试的计数器 onImageError: function() { var img = this.imgDiv; if (img.src != null) { this.imageReloadAttempts++; if (this.imageReloadAttempts <= OpenLayers.IMAGE_RELOAD_ATTEMPTS) { this.setImgSrc(this.layer.getURL(this.bounds)); } else { OpenLayers.Element.addClass(img, "olImageLoadError"); this.events.triggerEvent("loaderror"); this.onImageLoad(); } } }, // 解绑事件 stopLoading: function() { OpenLayers.Event.stopObservingElement(this.imgDiv); window.clearTimeout(this._loadTimeout); delete this._loadTimeout; }, //CanvasContext getCanvasContext: function() { if (OpenLayers.CANVAS_SUPPORTED && this.imgDiv && !this.isLoading) { if (!this.canvasContext) { var canvas = document.createElement("canvas"); canvas.width = this.size.w; canvas.height = this.size.h; this.canvasContext = canvas.getContext("2d"); this.canvasContext.drawImage(this.imgDiv, 0, 0);//利用canvas绘制 } return this.canvasContext;//返回绘制结果 } }, CLASS_NAME: "OpenLayers.Tile.Image" }); 12345678//静态方法 , OpenLayers.Tile.Image.IMAGE = (function() { var img = new Image(); img.className = "olTileImage"; // 低版本ie兼容 img.galleryImg = "no"; return img;}());