Newer
Older
DH_Apicture / public / static / libs / mapbox / extend / WMTSLayer.js
@zhangqy zhangqy on 29 Nov 15 KB first commit
  1. (function (global, factory) {
  2. typeof exports === 'object' && typeof module !== 'undefined' ?
  3. module.exports = factory() :
  4. typeof define === 'function' && define.amd ? define(factory) :
  5. (global = typeof globalThis !== 'undefined' ? globalThis :
  6. global || self, global.mapboxgl1.WMTSLayer = factory(global));
  7. }(window,(function(global){
  8. function clamp(value,min,max){
  9. return value < min ? min : value > max ? max: value
  10. }
  11.  
  12. var caches = {
  13. data:{},
  14. get:function(key){
  15. return this.data[key];
  16. },
  17. put:function(key,value){
  18. this.data[key] = value;
  19. },
  20. clear:function(){
  21. this.data = {};
  22. }
  23. };
  24.  
  25. var lib = mapboxgl1;
  26.  
  27. var transparentPngUrl = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAC0lEQVQYV2NgAAIAAAUAAarVyFEAAAAASUVORK5CYII=';
  28.  
  29. var transparentImage = (function(){
  30. var canvas = document.createElement("canvas");
  31. canvas.width = 256;
  32. canvas.height = 256;
  33. var context = canvas.getContext("2d");
  34. context.fillStyle = "rgba(0,0,0,0)";
  35. context.fillRect(0,0,256,256);
  36. return canvas;
  37. })();
  38.  
  39. var vetexShaderSource = `
  40. uniform mat4 u_Matrix;
  41. uniform vec4 u_Translate;
  42. attribute vec3 a_Position;
  43. attribute vec2 a_UV;
  44. varying vec2 v_UV;
  45. void main(){
  46. v_UV = a_UV;
  47. gl_Position = u_Matrix * vec4( (a_Position.xy + u_Translate.xy), 0.0 ,1.0 );
  48. }
  49. `;
  50.  
  51. var fragmentShaderSource = `
  52. #ifdef GL_ES
  53. precision mediump float;
  54. #endif
  55. varying vec2 v_UV;
  56. uniform sampler2D texture;
  57. void main(){
  58. vec4 textureColor = texture2D(texture,v_UV);
  59. gl_FragColor = textureColor;
  60. }
  61. `;
  62.  
  63. function WMTSLayer(options){
  64.  
  65. this._options = Object.assign({
  66. minzoom:3,
  67. maxzoom:22,
  68. tileSize:256
  69. },options);
  70.  
  71. this._extent = this._options.extent || [-180,-90,180,90];
  72.  
  73. this.map = null;
  74. this._transform = null;
  75. this._program = null;
  76. this._gl = null;
  77.  
  78. //当前可视区域的切片
  79. this._tiles = {};
  80.  
  81. }
  82.  
  83. WMTSLayer.prototype = {
  84.  
  85. constructor:WMTSLayer,
  86.  
  87. addTo:function(map){
  88.  
  89. this.map = map;
  90. this._transform = map.transform;
  91. this._layerId = "vectorTileLayer_"+Date.now();
  92.  
  93. map.addLayer({
  94. id:this._layerId,
  95. type: 'custom',
  96. onAdd: (function(_this){
  97. return function(map,gl){
  98. return _this._onAdd(map,gl,this);
  99. }
  100. })(this),
  101. render: (function(_this){
  102. return function(gl, matrix){
  103. return _this._render(gl, matrix, this);
  104. }
  105. })(this)
  106. });
  107.  
  108. map.on("remove",function(){
  109. caches.clear();
  110. });
  111. },
  112.  
  113. _onAdd: function(map,gl){
  114. var _this = this;
  115.  
  116. this._gl = gl;
  117.  
  118. this.transparentTexture = gl.createTexture();
  119. gl.bindTexture(gl.TEXTURE_2D, this.transparentTexture);
  120. gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MIN_FILTER,gl.LINEAR);
  121. gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, transparentImage);
  122. gl.bindTexture(gl.TEXTURE_2D,null);
  123.  
  124. var vetexShader = gl.createShader(gl.VERTEX_SHADER)
  125. gl.shaderSource(vetexShader,vetexShaderSource);
  126. gl.compileShader(vetexShader);
  127.  
  128. if (!gl.getShaderParameter(vetexShader,gl.COMPILE_STATUS)) {
  129. throw "Shader Compile Error: " + (gl.getShaderInfoLog(vetexShader));
  130. }
  131.  
  132. var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
  133. gl.shaderSource(fragmentShader,fragmentShaderSource);
  134. gl.compileShader(fragmentShader);
  135.  
  136. if (!gl.getShaderParameter(fragmentShader,gl.COMPILE_STATUS)) {
  137. throw "Shader Compile Error: " + (gl.getShaderInfoLog(fragmentShader));
  138. }
  139.  
  140. var program = this._program = gl.createProgram();
  141. gl.attachShader(program, vetexShader);
  142. gl.attachShader(program, fragmentShader);
  143. gl.linkProgram(program);
  144. /**
  145. * 属性
  146. */
  147. var attributes = this._attributes = {
  148. aPosition:{
  149. name:"a_Position",
  150. location:gl.getAttribLocation(this._program,"a_Position"),
  151. },
  152. aUV:{
  153. name:"a_UV",
  154. location:gl.getAttribLocation(this._program,"a_UV"),
  155. }
  156. };
  157.  
  158. /**
  159. * 缓冲区
  160. */
  161. this._buffers = {
  162. aPositionBuffer:{
  163. buffer:gl.createBuffer(),
  164. size:3,
  165. attribute: attributes["aPosition"],
  166. points: new Float32Array(3 * 6),
  167. update:function(extent){
  168. },
  169. update1:function(extent){
  170. gl.bindBuffer(gl.ARRAY_BUFFER,this.buffer);
  171. var centerMecatorExtent = extent;
  172. var minx = centerMecatorExtent[0],
  173. miny = centerMecatorExtent[1],
  174. maxx = centerMecatorExtent[2],
  175. maxy = centerMecatorExtent[3];
  176. var points = this.points;
  177. points[0] = minx ,points[1] = maxy, points[2] = 0.0 ,
  178. points[3] = maxx ,points[4] = maxy, points[5] = 0.0,
  179. points[6] = minx ,points[7] = miny, points[8] = 0.0 ,
  180. points[9] = maxx ,points[10] = maxy, points[11] = 0.0 ,
  181. points[12] = minx,points[13] = miny, points[14] = 0.0,
  182. points[15] = maxx,points[16] = miny, points[17] = 0.0 ;
  183. gl.bufferData(gl.ARRAY_BUFFER,points, gl.STATIC_DRAW);
  184. gl.enableVertexAttribArray(this.attribute.location);
  185. gl.vertexAttribPointer(this.attribute.location,this.size,gl.FLOAT,false,0,0);
  186. }
  187. },
  188. aUVBuffer:{
  189. buffer:gl.createBuffer(),
  190. size:2,
  191. attribute:attributes["aUV"],
  192. points:new Float32Array( [0,0,1,0,0,1,1,0,0,1,1,1] ),
  193. hasBufferData:false,
  194. update:function(){
  195. gl.bindBuffer(gl.ARRAY_BUFFER,this.buffer);
  196. if(!this.hasBufferData){
  197. gl.bufferData(gl.ARRAY_BUFFER, this.points, gl.STATIC_DRAW);
  198. this.hasBufferData = true;
  199. }
  200. gl.enableVertexAttribArray(this.attribute.location);
  201. gl.vertexAttribPointer(this.attribute.location,this.size,gl.FLOAT,false,0,0);
  202. }
  203. }
  204. }
  205. /**
  206. * 变量
  207. */
  208. this._uniforms = {
  209. uMatrix:{
  210. value:null,
  211. location:gl.getUniformLocation(this._program,"u_Matrix"),
  212. update:function(matrix){
  213. if(this.value !== matrix){
  214. gl.uniformMatrix4fv(this.location,false,matrix);
  215. }
  216. }
  217. },
  218. uTranslate:{
  219. value:[0,0],
  220. location:gl.getUniformLocation(this._program,"u_Translate"),
  221. update:function(){}
  222. },
  223. uTexture:{
  224. value:null,
  225. location:gl.getUniformLocation(this._program, 'texture'),
  226. update:function(){}
  227. }
  228. };
  229. },
  230. /**
  231. * 渲染
  232. * @param {*} gl
  233. * @param {*} matrix
  234. */
  235. _render:function(gl, matrix){
  236. if(this._program){
  237.  
  238. var transform = this._transform;
  239. var options = this._options;
  240. var tileSize = options.tileSize ||256;
  241.  
  242. var z = transform.coveringZoomLevel({
  243. tileSize:tileSize,
  244. roundZoom:true
  245. });
  246.  
  247. this.realz = z;
  248.  
  249. z = z < 5 ? 5 : z;
  250.  
  251. this.z = z;
  252.  
  253. if (options.minzoom !== undefined && z < options.minzoom) { z = 0; }
  254.  
  255. if (options.maxzoom !== undefined && z > options.maxzoom) { z = options.maxzoom; }
  256.  
  257. var resolution = this.resolution = this.getResolutionFromZ(z);
  258.  
  259. var center = transform.center;
  260.  
  261. //var centerCoord = lib.MercatorCoordinate.fromLngLat(transform.center);
  262. var maxx = clamp (center.lng + resolution * tileSize, -180, 180);
  263. var miny = clamp (center.lat - resolution * tileSize, -90, 90);
  264. var minx = clamp (center.lng, -180, 180) ,maxy = clamp(center.lat, -90,90) ;
  265. var leftBottom = lib.MercatorCoordinate.fromLngLat([minx,miny]);
  266. var topRight = lib.MercatorCoordinate.fromLngLat([maxx,maxy]);
  267.  
  268. this.centerMecatorExtent = [leftBottom.x,leftBottom.y,topRight.x,topRight.y];
  269.  
  270. gl.useProgram(this._program);
  271.  
  272. gl.enable(gl.BLEND);
  273.  
  274. gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
  275.  
  276.  
  277. for(let key in this._uniforms){
  278. this._uniforms[key].update(matrix);
  279. }
  280.  
  281. for(let key in this._buffers){
  282. this._buffers[key].update();
  283. }
  284.  
  285. this.calcTilesInView();
  286.  
  287. this.renderTiles();
  288.  
  289. }
  290. },
  291. renderTiles(){
  292. var gl = this._gl;
  293. var tiles = this._tiles;
  294. var tile;
  295.  
  296. for(var key in tiles){
  297.  
  298. tile = tiles[key];
  299.  
  300. tile.calcExtent();
  301.  
  302. this._buffers.aPositionBuffer.update1(tile.extent);
  303.  
  304. gl.uniform4fv(this._uniforms.uTranslate.location,tile.translate);
  305. gl.activeTexture(gl.TEXTURE0);
  306. if(tile.texture){
  307. gl.bindTexture(gl.TEXTURE_2D, tile.texture);
  308. }else{
  309. gl.bindTexture(gl.TEXTURE_2D, this.transparentTexture);
  310. }
  311. gl.uniform1i(this._uniforms.uTexture.location, 0);
  312. gl.drawArrays(gl.TRIANGLES, 0, 6);
  313. }
  314.  
  315. },
  316. /**
  317. * 计算当前可视范围内的切片
  318. */
  319. calcTilesInView:function(){
  320. var z = this.z;
  321. var options = this._options;
  322. var tileSize = options.tileSize ||256;
  323.  
  324. var resolution = this.resolution;
  325.  
  326. var extent = this._extent;
  327. var tileRes = resolution * tileSize;
  328. var viewExtent = this.getViewExtent();
  329.  
  330. var startX = Math.floor((viewExtent[0] - extent[0]) / tileRes);
  331. var startY = Math.floor((extent[3] - viewExtent[3]) / tileRes);
  332. var endX = Math.ceil((viewExtent[2] - extent[0]) / tileRes);
  333. var endY = Math.ceil((extent[3] - viewExtent[1]) / tileRes);
  334.  
  335. // startX = startX < 20 ? 20 : startX;
  336. startY = startY < 1 ? 1 : startY;
  337. // endX = endX < 31 ? 31 : endX;
  338. //endY = endY < 20 ? 20 : endY;
  339. if(this.realz < 5){
  340. endY = endY > 10 ? 10 : endY
  341. }
  342.  
  343.  
  344. var i,j,key,tile;
  345.  
  346. var tiles = this._tiles;
  347.  
  348. var newTiles = {}
  349.  
  350. for(i = startX ; i < endX; i ++){
  351. for(j = startY; j < endY ; j ++){
  352. key = this._key(z,i,j);
  353. if(!tiles[key]){
  354. caches.get(key);
  355. if(caches.get(key)){
  356. newTiles[key] = caches.get(key);
  357. }else{
  358. tile = new Tile(z,i,j,resolution,this);
  359. newTiles[key] = tile;
  360. }
  361. }else{
  362. newTiles[key] = tiles[key];
  363. delete tiles[key];
  364. }
  365. }
  366. };
  367.  
  368. for(var key in tiles){
  369. if(tiles[key].request){
  370. tiles[key].request.cancel();
  371. }
  372. }
  373.  
  374. this._tiles = newTiles;
  375.  
  376. },
  377. _key:function(z,x,y){
  378. return z+'/'+x+"/"+y;
  379. },
  380. /**
  381. * 计算分辨率
  382. */
  383. getResolutionFromZ:function(z){
  384. return 1.4062500000000002 / Math.pow(2,z);
  385. },
  386. /**
  387. * 计算extent
  388. */
  389. getViewExtent:function(){
  390. var transform = this._transform;
  391. var bounds = [
  392. transform.pointLocation(new lib.Point(0, 0)),
  393. transform.pointLocation(new lib.Point(transform.width, 0)),
  394. transform.pointLocation(new lib.Point(transform.width, transform.height)),
  395. transform.pointLocation(new lib.Point(0, transform.height))
  396. ];
  397.  
  398. var minx , miny , maxx, maxy;
  399.  
  400. for(var i = 0,point = null ; i < bounds.length ; i ++ ){
  401. point = bounds[i];
  402. if(i == 0 ){
  403. minx = point.lng;
  404. miny = point.lat;
  405. maxx = point.lng;i
  406. maxy = point.lat;
  407. }else {
  408. if(minx > point.lng) minx = point.lng;
  409. if(miny > point.lat) miny = point.lat;
  410. if(maxx < point.lng) maxx = point.lng;
  411. if(maxy < point.lat) maxy = point.lat;
  412. }
  413. }
  414.  
  415. return [
  416. clamp(minx,-180,180),
  417. clamp(miny,-90,90),
  418. clamp(maxx,-180,180),
  419. clamp(maxy,-90,90)
  420. ]
  421. },
  422. /**
  423. * 重绘
  424. */
  425. repaint:function(){
  426. this.map.triggerRepaint();
  427. },
  428. hide: function(){
  429. this.map.setLayoutProperty(this._layerId, 'visibility', 'none');
  430. },
  431. show: function(){
  432. this.map.setLayoutProperty(this._layerId, 'visibility', 'visible');
  433. }
  434. }
  435.  
  436. /**
  437. * 请求
  438. * @param {*} url
  439. * @param {*} callback
  440. * @param {*} async
  441. */
  442. var getImage = (function(){
  443.  
  444. var MAX_REQUEST_NUM = 16;
  445.  
  446. var requestNum = 0;
  447. var requestQuenes = [];
  448.  
  449. function getImage(url,callback){
  450. if(requestNum > MAX_REQUEST_NUM){
  451. var quene = {
  452. url:url,
  453. callback:callback,
  454. canceled:false,
  455. cancel:function(){
  456. this.canceled = true;
  457. }
  458. }
  459. requestQuenes.push(quene);
  460. return quene;
  461. }
  462.  
  463. var advanced = false;
  464. var advanceImageRequestQueue = function () {
  465. if (advanced) { return; }
  466. advanced = true;
  467. requestNum--;
  468. while (requestQuenes.length && requestNum < MAX_REQUEST_NUM) { // eslint-disable-line
  469. var request = requestQuenes.shift();
  470. var url = request.url;
  471. var callback = request.callback;
  472. var canceled = request.canceled;
  473. if (!canceled) {
  474. request.cancel = getImage(url, callback).cancel;
  475. }
  476. }
  477. };
  478.  
  479. requestNum ++ ;
  480. var req = get(url,function(error,data){
  481. advanceImageRequestQueue();
  482. if(!error){
  483. var URL = window.URL || window.webkitURL;
  484. var blob = new Blob([data],{type:"image/png"});
  485. var blobUrl = URL.createObjectURL(blob)
  486. var image = new Image();
  487. image.src = blobUrl;
  488. image.onload = function(){
  489. callback(image);
  490. URL.revokeObjectURL(image.src);
  491. };
  492. image.src = data.byteLength ? URL.createObjectURL(blob) : transparentPngUrl;
  493. }
  494.  
  495. });
  496.  
  497. return {
  498. cancel:function(){
  499. req.abort();
  500. }
  501. }
  502. }
  503.  
  504. function get(url, callback, async) {
  505. var xhr = new XMLHttpRequest();
  506. xhr.open('GET', url, async === false ? false : true);
  507. xhr.responseType = "arraybuffer";
  508. xhr.onabort = function (event) {
  509. callback(true, null);
  510. };
  511. xhr.onload = function (event) {
  512. if (!xhr.status || xhr.status >= 200 && xhr.status < 300) {
  513. var source;
  514. source = xhr.response;
  515. if (source) {
  516. try {
  517. source = eval("(" + source + ")");
  518. } catch (e) {
  519. }
  520. }
  521. if (source) {
  522. callback(false, source);
  523. } else {
  524. callback(false, null);
  525. }
  526. }
  527. };
  528. xhr.onerror = function (e) {
  529. callback(true, null);
  530. };
  531. xhr.send(null);
  532. return xhr;
  533. }
  534.  
  535. return getImage;
  536. })()
  537.  
  538.  
  539.  
  540. function Tile(z,x,y,resolution,layer){
  541. this._resolution = resolution;
  542. this._layer = layer;
  543. this._coord = [z,x,y];
  544. this._gl = layer._gl;
  545. this._url = layer._options.url;
  546. this.texture = null;
  547. this.loaded = false;
  548. this.tileSize = layer._options.tileSize;
  549. this.worldExtent = layer._extent;
  550. this.subdomains = layer._options.subdomains || [];
  551. this.extent = [0,0,0,0];
  552. this.translate = [0,0,0,0];
  553. this._load();
  554. }
  555.  
  556. Tile.prototype = {
  557. constructor:Tile,
  558.  
  559. calcExtent:function(){
  560.  
  561. var gl = this._gl;
  562. var worldExtent = this.worldExtent;
  563. var tileSize = this.tileSize;
  564. var resolution = this._resolution;
  565. var coord = this._coord;
  566. var x = coord[1],y = coord[2];
  567.  
  568. var maxTileNum = Math.ceil((worldExtent[3] - worldExtent[1]) / resolution / tileSize);
  569.  
  570. var minx = clamp(x * tileSize * resolution - worldExtent[2],-180,180);
  571. var maxx = clamp(minx + tileSize * resolution, -180,180);
  572. var maxy = clamp(worldExtent[3] - y * tileSize * resolution, -90 , 90 );
  573. var miny = clamp(maxy - tileSize * resolution, -90,90);
  574.  
  575. var y1 = y + 1;
  576. y1 = y1 > maxTileNum ? maxTileNum : y1;
  577. maxy1 = worldExtent[3] - y1 * tileSize * resolution;
  578.  
  579.  
  580. var bl = lib.MercatorCoordinate.fromLngLat([minx,miny]);
  581. var tr = lib.MercatorCoordinate.fromLngLat([maxx,maxy]);
  582.  
  583. this.extent[0] = bl.x;
  584. this.extent[1] = bl.y;
  585. this.extent[2] = tr.x;
  586. this.extent[3] = tr.y;
  587.  
  588. //var centerMecatorExtent = this._layer.centerMecatorExtent;
  589.  
  590. // if(!this.translate){
  591. // this.translate = [0,0,0,0];
  592. // }
  593.  
  594. // this.translate[0] = bl.x - centerMecatorExtent[0];
  595. // this.translate[1] = bl.y - centerMecatorExtent[1];
  596. // this.translate[2] = tr.x - centerMecatorExtent[2];
  597. // this.translate[3] = tr.y - centerMecatorExtent[3];
  598.  
  599. },
  600. _load: function(){
  601. var gl = this._gl
  602. var _this = this;
  603. var z = this._coord[0];
  604. var x = this._coord[1];
  605. var y = this._coord[2];
  606. var url = this._url.replace("{s}",this.subdomains[Math.floor(Math.random() * this.subdomains.length)]).replace("{x}",x).replace("{y}",y).replace("{z}",z);
  607.  
  608. this.request = getImage(url,function(img){
  609. delete _this .request;
  610. if(_this._gl){
  611. var texture = _this.texture = gl.createTexture();
  612. gl.bindTexture(gl.TEXTURE_2D, texture);
  613. gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false);
  614. gl.pixelStorei(gl.UNPACK_ALIGNMENT, 1);
  615. gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true);
  616. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
  617. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
  618. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
  619. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
  620. gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, img);
  621. gl.bindTexture(gl.TEXTURE_2D, null);
  622. caches.put(z+"/"+x+"/"+y,_this);
  623. _this.loaded = true;
  624. _this._layer.repaint();
  625. }
  626. });
  627. }
  628. }
  629.  
  630. return WMTSLayer;
  631. })));