diff --git a/CHANGELOG.md b/CHANGELOG.md index b9e6b4c..45f8b27 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,16 @@ # offline-editor-js - Changelog +## Version 3.4.0 - September 13, 2016 + +Possible breaking changes. + +**Enhancements** +* Added base64 re-encoding to the tile database that results in a 2.7x (16/6) reduction in storage size. + +**Known Issues** +* Firefox v48.x is showing tiles as hidden when they should be visible. This issue existed at v3.3.2. + + ## Version 3.3.2 - August 24, 2016 No breaking changes. diff --git a/Gruntfile.js b/Gruntfile.js index 505a392..72e505e 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -33,6 +33,7 @@ module.exports = function(grunt) { 'lib/tiles/OfflineTilesNS.js', 'lib/tiles/TilesCore.js', 'lib/tiles/TilesStore.js', + 'lib/tiles/base64string.js', 'lib/tiles/tilingScheme.js', 'lib/tpk/autoCenterMap.js', 'lib/tpk/OfflineTpkNS.js', @@ -74,6 +75,7 @@ module.exports = function(grunt) { 'lib/tiles/OfflineTilesBasic.js', 'lib/tiles/OfflineTilesNS.js', 'lib/tiles/base64utils.js', + 'lib/tiles/base64string.js', 'lib/tiles/FileSaver.js', 'lib/tiles/TilesCore.js', 'lib/tiles/TilesStore.js', @@ -87,6 +89,7 @@ module.exports = function(grunt) { 'lib/tiles/OfflineTilesAdvanced.js', 'lib/tiles/OfflineTilesNS.js', 'lib/tiles/base64utils.js', + 'lib/tiles/base64string.js', 'lib/tiles/FileSaver.js', 'lib/tiles/TilesCore.js', 'lib/tiles/TilesStore.js', diff --git a/dist/offline-edit-advanced-src.js b/dist/offline-edit-advanced-src.js index eb953c2..cc5dd9e 100644 --- a/dist/offline-edit-advanced-src.js +++ b/dist/offline-edit-advanced-src.js @@ -1,4 +1,4 @@ -/*! esri-offline-maps - v3.3.0 - 2016-07-12 +/*! esri-offline-maps - v3.4.0 - 2016-09-13 * Copyright (c) 2016 Environmental Systems Research Institute, Inc. * Apache License*/ // Configure offline/online detection diff --git a/dist/offline-edit-basic-src.js b/dist/offline-edit-basic-src.js index 3205403..c38cd2c 100644 --- a/dist/offline-edit-basic-src.js +++ b/dist/offline-edit-basic-src.js @@ -1,4 +1,4 @@ -/*! esri-offline-maps - v3.3.0 - 2016-07-12 +/*! esri-offline-maps - v3.4.0 - 2016-09-13 * Copyright (c) 2016 Environmental Systems Research Institute, Inc. * Apache License*/ // Configure offline/online detection diff --git a/dist/offline-tiles-advanced-min.js b/dist/offline-tiles-advanced-min.js index a94b1e2..dee7390 100644 --- a/dist/offline-tiles-advanced-min.js +++ b/dist/offline-tiles-advanced-min.js @@ -30,7 +30,69 @@ return d<<16|65535&c},O.esri.Tiles.Base64Utils.stringToWord=function(a){for(var return d},O.esri.Tiles.Base64Utils.wordToString=function(a){for(var b=8,c=(1<e;e+=b)d.push(String.fromCharCode(a[e>>5]>>>e%32&c)) return d.join("")},O.esri.Tiles.Base64Utils.wordToHex=function(a){for(var b="0123456789abcdef",c=[],d=0,e=4*a.length;e>d;d++)c.push(b.charAt(a[d>>2]>>d%4*8+4&15)+b.charAt(a[d>>2]>>d%4*8&15)) return c.join("")},O.esri.Tiles.Base64Utils.wordToBase64=function(a){for(var b="=",c="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",d=[],e=0,f=4*a.length;f>e;e+=3)for(var g=(a[e>>2]>>8*(e%4)&255)<<16|(a[e+1>>2]>>8*((e+1)%4)&255)<<8|a[e+2>>2]>>8*((e+2)%4)&255,h=0;4>h;h++)8*e+6*h>32*a.length?d.push(b):d.push(c.charAt(g>>6*(3-h)&63)) -return d.join("")},O.esri.Tiles.saveAs=function(a){"use strict" +return d.join("")},O.esri.Tiles.Base64String={compressToUTF16:function(a){var b,c,d,e=[],f=0 +for(a=this.compress(a),b=0;b>1)+32)),d=(1&c)<<14 +break +case 1:e.push(String.fromCharCode(d+(c>>2)+32)),d=(3&c)<<13 +break +case 2:e.push(String.fromCharCode(d+(c>>3)+32)),d=(7&c)<<12 +break +case 3:e.push(String.fromCharCode(d+(c>>4)+32)),d=(15&c)<<11 +break +case 4:e.push(String.fromCharCode(d+(c>>5)+32)),d=(31&c)<<10 +break +case 5:e.push(String.fromCharCode(d+(c>>6)+32)),d=(63&c)<<9 +break +case 6:e.push(String.fromCharCode(d+(c>>7)+32)),d=(127&c)<<8 +break +case 7:e.push(String.fromCharCode(d+(c>>8)+32)),d=(255&c)<<7 +break +case 8:e.push(String.fromCharCode(d+(c>>9)+32)),d=(511&c)<<6 +break +case 9:e.push(String.fromCharCode(d+(c>>10)+32)),d=(1023&c)<<5 +break +case 10:e.push(String.fromCharCode(d+(c>>11)+32)),d=(2047&c)<<4 +break +case 11:e.push(String.fromCharCode(d+(c>>12)+32)),d=(4095&c)<<3 +break +case 12:e.push(String.fromCharCode(d+(c>>13)+32)),d=(8191&c)<<2 +break +case 13:e.push(String.fromCharCode(d+(c>>14)+32)),d=(16383&c)<<1 +break +case 14:e.push(String.fromCharCode(d+(c>>15)+32,(32767&c)+32)),f=0}return e.push(String.fromCharCode(d+32)),e.join("")},decompressFromUTF16:function(a){for(var b,c,d=[],e=0,f=0;f>14)),b=(16383&c)<<2 +break +case 2:d.push(String.fromCharCode(b|c>>13)),b=(8191&c)<<3 +break +case 3:d.push(String.fromCharCode(b|c>>12)),b=(4095&c)<<4 +break +case 4:d.push(String.fromCharCode(b|c>>11)),b=(2047&c)<<5 +break +case 5:d.push(String.fromCharCode(b|c>>10)),b=(1023&c)<<6 +break +case 6:d.push(String.fromCharCode(b|c>>9)),b=(511&c)<<7 +break +case 7:d.push(String.fromCharCode(b|c>>8)),b=(255&c)<<8 +break +case 8:d.push(String.fromCharCode(b|c>>7)),b=(127&c)<<9 +break +case 9:d.push(String.fromCharCode(b|c>>6)),b=(63&c)<<10 +break +case 10:d.push(String.fromCharCode(b|c>>5)),b=(31&c)<<11 +break +case 11:d.push(String.fromCharCode(b|c>>4)),b=(15&c)<<12 +break +case 12:d.push(String.fromCharCode(b|c>>3)),b=(7&c)<<13 +break +case 13:d.push(String.fromCharCode(b|c>>2)),b=(3&c)<<14 +break +case 14:d.push(String.fromCharCode(b|c>>1)),b=(1&c)<<15 +break +case 15:d.push(String.fromCharCode(b|c)),e=0}f++}return this.decompress(d.join(""))},_keyStr:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",decompress:function(a){for(var b,c,d,e,f,g,h,i=[],j=1,k=a.charCodeAt(0)>>8;j<2*a.length&&(j<2*a.length-1||0===k);)j%2===0?(b=a.charCodeAt(j/2)>>8,c=255&a.charCodeAt(j/2),d=j/2+1>8:NaN):(b=255&a.charCodeAt((j-1)/2),(j+1)/2>8,d=255&a.charCodeAt((j+1)/2)):c=d=NaN),j+=3,e=b>>2,f=(3&b)<<4|c>>4,g=(15&c)<<2|d>>6,h=63&d,isNaN(c)||j==2*a.length+1&&k?g=h=64:(isNaN(d)||j==2*a.length&&k)&&(h=64),i.push(this._keyStr.charAt(e)),i.push(this._keyStr.charAt(f)),i.push(this._keyStr.charAt(g)),i.push(this._keyStr.charAt(h)) +return i.join("")},compress:function(a){var b,c,d,e,f,g,h,i,j=[],k=1,l=0,m=!1 +for(a=a.replace(/[^A-Za-z0-9\+\/\=]/g,"");l>4,d=(15&g)<<4|h>>2,e=(3&h)<<6|i,k%2===0?(b=c<<8,m=!0,64!=h&&(j.push(String.fromCharCode(b|d)),m=!1),64!=i&&(b=e<<8,m=!0)):(j.push(String.fromCharCode(b|c)),m=!1,64!=h&&(b=d<<8,m=!0),64!=i&&(j.push(String.fromCharCode(b|e)),m=!1)),k+=3 +return m?(j.push(String.fromCharCode(b)),j=j.join(""),j=String.fromCharCode(256|j.charCodeAt(0))+j.substring(1)):j=j.join(""),j}},O.esri.Tiles.saveAs=function(a){"use strict" var b=a.document,c=function(){return a.URL||a.webkitURL||a},d=a.URL||a.webkitURL||a,e=b.createElementNS("http://www.w3.org/1999/xhtml","a"),f=!a.externalHost&&"download"in e,g=a.webkitRequestFileSystem,h=a.requestFileSystem||g||a.mozRequestFileSystem,i=function(b){(a.setImmediate||a.setTimeout)(function(){throw b},0)},j="application/octet-stream",k=0,l=[],m=function(){for(var a=l.length;a--;){var b=l[a] "string"==typeof b?d.revokeObjectURL(b):b.remove()}l.length=0},n=function(a,b,c){b=[].concat(b) for(var d=b.length;d--;){var e=a["on"+b[d]] @@ -69,10 +131,12 @@ return c.level=b.level,c.resolution=b.resolution,c.scale=b.scale,b.hasOwnPropert var k=new f(parseFloat(d.initialExtent.xmin),parseFloat(d.initialExtent.ymin),parseFloat(d.initialExtent.xmax),parseFloat(d.initialExtent.ymax),i),l=new f(parseFloat(d.fullExtent.xmin),parseFloat(d.fullExtent.ymin),parseFloat(d.fullExtent.xmax),parseFloat(d.fullExtent.ymax),i),m=new g(d.tileInfo),n=new h(m.origin.x,m.origin.y,i) m.origin=n,m.lods=j,b({initExtent:k,fullExtent:l,tileInfo:m,resultObj:d})})}},O.esri.Tiles.TilesStore=function(){this._db=null,this.dbName="offline_tile_store",this.objectStoreName="tilepath",this.isSupported=function(){return!(!window.indexedDB&&!window.openDatabase)},this.store=function(a,b){try{var c=this._db.transaction([this.objectStoreName],"readwrite") c.oncomplete=function(){b(!0)},c.onerror=function(a){b(!1,a.target.error.message)} -var d=c.objectStore(this.objectStoreName),e=d.put(a) +var d=c.objectStore(this.objectStoreName) +a.img=O.esri.Tiles.Base64String.compress(a.img) +var e=d.put(a) e.onsuccess=function(){}}catch(f){b(!1,f.stack)}},this.retrieve=function(a,b){if(null!==this._db){var c=this._db.transaction([this.objectStoreName]).objectStore(this.objectStoreName),d=c.get(a) d.onsuccess=function(a){var c=a.target.result -void 0===c?b(!1,"not found"):b(!0,c)},d.onerror=function(a){b(!1,a)}}},this.deleteAll=function(a){if(null!==this._db){var b=this._db.transaction([this.objectStoreName],"readwrite").objectStore(this.objectStoreName).clear() +void 0===c?b(!1,"not found"):(c.img=O.esri.Tiles.Base64String.decompress(c.img),b(!0,c))},d.onerror=function(a){b(!1,a)}}},this.deleteAll=function(a){if(null!==this._db){var b=this._db.transaction([this.objectStoreName],"readwrite").objectStore(this.objectStoreName).clear() b.onsuccess=function(){a(!0)},b.onerror=function(b){a(!1,b)}}else a(!1,null)},this["delete"]=function(a,b){if(null!==this._db){var c=this._db.transaction([this.objectStoreName],"readwrite").objectStore(this.objectStoreName)["delete"](a) c.onsuccess=function(){b(!0)},c.onerror=function(a){b(!1,a)}}else b(!1,null)},this.getAllTiles=function(a){if(null!==this._db){var b=this._db.transaction([this.objectStoreName]).objectStore(this.objectStoreName).openCursor() b.onsuccess=function(b){var c=b.target.result diff --git a/dist/offline-tiles-advanced-src.js b/dist/offline-tiles-advanced-src.js index fcfa560..f9bcd48 100644 --- a/dist/offline-tiles-advanced-src.js +++ b/dist/offline-tiles-advanced-src.js @@ -1,4 +1,4 @@ -/*! esri-offline-maps - v3.3.0 - 2016-07-12 +/*! esri-offline-maps - v3.4.0 - 2016-09-13 * Copyright (c) 2016 Environmental Systems Research Institute, Inc. * Apache License*/ define([ @@ -661,6 +661,299 @@ O.esri.Tiles.Base64Utils.wordToBase64=function(/* word[] */wa){ }; /*jslint bitwise: false */ +// Copyright (c) 2013 Pieroxy +// This work is free. You can redistribute it and/or modify it +// under the terms of the WTFPL, Version 2 +// For more information see LICENSE.txt or http://www.wtfpl.net/ +// +// This lib is part of the lz-string project. +// For more information, the home page: +// http://pieroxy.net/blog/pages/lz-string/index.html +// +// Base64 compression / decompression for already compressed content (gif, png, jpg, mp3, ...) +// version 1.4.1 + +/*jslint bitwise: true */ +O.esri.Tiles.Base64String = { + + compressToUTF16 : function (input) { + var output = [], + i,c, + current, + status = 0; + + input = this.compress(input); + + for (i=0 ; i> 1)+32)); + current = (c & 1) << 14; + break; + case 1: + output.push(String.fromCharCode((current + (c >> 2))+32)); + current = (c & 3) << 13; + break; + case 2: + output.push(String.fromCharCode((current + (c >> 3))+32)); + current = (c & 7) << 12; + break; + case 3: + output.push(String.fromCharCode((current + (c >> 4))+32)); + current = (c & 15) << 11; + break; + case 4: + output.push(String.fromCharCode((current + (c >> 5))+32)); + current = (c & 31) << 10; + break; + case 5: + output.push(String.fromCharCode((current + (c >> 6))+32)); + current = (c & 63) << 9; + break; + case 6: + output.push(String.fromCharCode((current + (c >> 7))+32)); + current = (c & 127) << 8; + break; + case 7: + output.push(String.fromCharCode((current + (c >> 8))+32)); + current = (c & 255) << 7; + break; + case 8: + output.push(String.fromCharCode((current + (c >> 9))+32)); + current = (c & 511) << 6; + break; + case 9: + output.push(String.fromCharCode((current + (c >> 10))+32)); + current = (c & 1023) << 5; + break; + case 10: + output.push(String.fromCharCode((current + (c >> 11))+32)); + current = (c & 2047) << 4; + break; + case 11: + output.push(String.fromCharCode((current + (c >> 12))+32)); + current = (c & 4095) << 3; + break; + case 12: + output.push(String.fromCharCode((current + (c >> 13))+32)); + current = (c & 8191) << 2; + break; + case 13: + output.push(String.fromCharCode((current + (c >> 14))+32)); + current = (c & 16383) << 1; + break; + case 14: + output.push(String.fromCharCode((current + (c >> 15))+32, (c & 32767)+32)); + status = 0; + break; + } + } + output.push(String.fromCharCode(current + 32)); + return output.join(''); + }, + + + decompressFromUTF16 : function (input) { + var output = [], + current,c, + status=0, + i = 0; + + while (i < input.length) { + c = input.charCodeAt(i) - 32; + + switch (status++) { + case 0: + current = c << 1; + break; + case 1: + output.push(String.fromCharCode(current | (c >> 14))); + current = (c&16383) << 2; + break; + case 2: + output.push(String.fromCharCode(current | (c >> 13))); + current = (c&8191) << 3; + break; + case 3: + output.push(String.fromCharCode(current | (c >> 12))); + current = (c&4095) << 4; + break; + case 4: + output.push(String.fromCharCode(current | (c >> 11))); + current = (c&2047) << 5; + break; + case 5: + output.push(String.fromCharCode(current | (c >> 10))); + current = (c&1023) << 6; + break; + case 6: + output.push(String.fromCharCode(current | (c >> 9))); + current = (c&511) << 7; + break; + case 7: + output.push(String.fromCharCode(current | (c >> 8))); + current = (c&255) << 8; + break; + case 8: + output.push(String.fromCharCode(current | (c >> 7))); + current = (c&127) << 9; + break; + case 9: + output.push(String.fromCharCode(current | (c >> 6))); + current = (c&63) << 10; + break; + case 10: + output.push(String.fromCharCode(current | (c >> 5))); + current = (c&31) << 11; + break; + case 11: + output.push(String.fromCharCode(current | (c >> 4))); + current = (c&15) << 12; + break; + case 12: + output.push(String.fromCharCode(current | (c >> 3))); + current = (c&7) << 13; + break; + case 13: + output.push(String.fromCharCode(current | (c >> 2))); + current = (c&3) << 14; + break; + case 14: + output.push(String.fromCharCode(current | (c >> 1))); + current = (c&1) << 15; + break; + case 15: + output.push(String.fromCharCode(current | c)); + status=0; + break; + } + + + i++; + } + + return this.decompress(output.join('')); + //return output; + + }, + + + // private property + _keyStr : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=", // jshint ignore:line + + decompress : function (input) { + var output = []; + var chr1, chr2, chr3, enc1, enc2, enc3, enc4; + var i = 1; + var odd = input.charCodeAt(0) >> 8; + + while (i < input.length*2 && (i < input.length*2-1 || odd===0)) { + + if (i%2===0) { + chr1 = input.charCodeAt(i/2) >> 8; + chr2 = input.charCodeAt(i/2) & 255; + if (i/2+1 < input.length) { + chr3 = input.charCodeAt(i / 2 + 1) >> 8; + } + else { + chr3 = NaN; + } + } else { + chr1 = input.charCodeAt((i-1)/2) & 255; + if ((i+1)/2 < input.length) { + chr2 = input.charCodeAt((i+1)/2) >> 8; + chr3 = input.charCodeAt((i+1)/2) & 255; + } else { + chr2 = chr3 = NaN; + } + } + i+=3; + + enc1 = chr1 >> 2; + enc2 = ((chr1 & 3) << 4) | (chr2 >> 4); + enc3 = ((chr2 & 15) << 2) | (chr3 >> 6); + enc4 = chr3 & 63; + + if (isNaN(chr2) || (i==input.length*2+1 && odd)) { + enc3 = enc4 = 64; + } else if (isNaN(chr3) || (i==input.length*2 && odd)) { + enc4 = 64; + } + + output.push(this._keyStr.charAt(enc1)); + output.push(this._keyStr.charAt(enc2)); + output.push(this._keyStr.charAt(enc3)); + output.push(this._keyStr.charAt(enc4)); + } + + return output.join(''); + }, + + compress : function (input) { + var output = [], + ol = 1, + output_, + chr1, chr2, chr3, + enc1, enc2, enc3, enc4, + i = 0, flush=false; + + input = input.replace(/[^A-Za-z0-9\+\/\=]/g, ""); // jshint ignore:line + + while (i < input.length) { + + enc1 = this._keyStr.indexOf(input.charAt(i++)); + enc2 = this._keyStr.indexOf(input.charAt(i++)); + enc3 = this._keyStr.indexOf(input.charAt(i++)); + enc4 = this._keyStr.indexOf(input.charAt(i++)); + + chr1 = (enc1 << 2) | (enc2 >> 4); + chr2 = ((enc2 & 15) << 4) | (enc3 >> 2); + chr3 = ((enc3 & 3) << 6) | enc4; + + if (ol%2===0) { + output_ = chr1 << 8; + flush = true; + + if (enc3 != 64) { + output.push(String.fromCharCode(output_ | chr2)); + flush = false; + } + if (enc4 != 64) { + output_ = chr3 << 8; + flush = true; + } + } else { + output.push(String.fromCharCode(output_ | chr1)); + flush = false; + + if (enc3 != 64) { + output_ = chr2 << 8; + flush = true; + } + if (enc4 != 64) { + output.push(String.fromCharCode(output_ | chr3)); + flush = false; + } + } + ol+=3; + } + + if (flush) { + output.push(String.fromCharCode(output_)); + output = output.join(''); + output = String.fromCharCode(output.charCodeAt(0)|256) + output.substring(1); + } else { + output = output.join(''); + } + + return output; + + } +}; + +/*jslint bitwise: false */ + /* FileSaver.js * A saveAs() FileSaver implementation. * 2013-10-21 @@ -918,7 +1211,7 @@ O.esri.Tiles.TilesCore = function(){ */ this._getTiles = function(image,imageType,url,tileid,store,query,showBlankTiles){ store.retrieve(url, function(success, offlineTile) - { console.log("TILE RETURN " + success + ", " + offlineTile.url); + { console.log("TILE RETURN " + success + ", " + offlineTile.url + ", " + tileid); /* when the .getTileUrl() callback is triggered we replace the temporary URL originally returned by the data:image url */ // search for the img with src="void:"+level+"-"+row+"-"+col and replace with actual url image = query("img[src="+tileid+"]")[0]; @@ -1348,6 +1641,7 @@ O.esri.Tiles.TilesStore = function(){ }; var objectStore = transaction.objectStore(this.objectStoreName); + urlDataPair.img = O.esri.Tiles.Base64String.compress(urlDataPair.img); var request = objectStore.put(urlDataPair); request.onsuccess = function() { @@ -1381,6 +1675,7 @@ O.esri.Tiles.TilesStore = function(){ } else { + result.img = O.esri.Tiles.Base64String.decompress(result.img); callback(true,result); } }; diff --git a/dist/offline-tiles-basic-min.js b/dist/offline-tiles-basic-min.js index f83c8aa..8201b18 100644 --- a/dist/offline-tiles-basic-min.js +++ b/dist/offline-tiles-basic-min.js @@ -19,7 +19,69 @@ return d<<16|65535&c},O.esri.Tiles.Base64Utils.stringToWord=function(a){for(var return d},O.esri.Tiles.Base64Utils.wordToString=function(a){for(var b=8,c=(1<e;e+=b)d.push(String.fromCharCode(a[e>>5]>>>e%32&c)) return d.join("")},O.esri.Tiles.Base64Utils.wordToHex=function(a){for(var b="0123456789abcdef",c=[],d=0,e=4*a.length;e>d;d++)c.push(b.charAt(a[d>>2]>>d%4*8+4&15)+b.charAt(a[d>>2]>>d%4*8&15)) return c.join("")},O.esri.Tiles.Base64Utils.wordToBase64=function(a){for(var b="=",c="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",d=[],e=0,f=4*a.length;f>e;e+=3)for(var g=(a[e>>2]>>8*(e%4)&255)<<16|(a[e+1>>2]>>8*((e+1)%4)&255)<<8|a[e+2>>2]>>8*((e+2)%4)&255,h=0;4>h;h++)8*e+6*h>32*a.length?d.push(b):d.push(c.charAt(g>>6*(3-h)&63)) -return d.join("")},O.esri.Tiles.saveAs=function(a){"use strict" +return d.join("")},O.esri.Tiles.Base64String={compressToUTF16:function(a){var b,c,d,e=[],f=0 +for(a=this.compress(a),b=0;b>1)+32)),d=(1&c)<<14 +break +case 1:e.push(String.fromCharCode(d+(c>>2)+32)),d=(3&c)<<13 +break +case 2:e.push(String.fromCharCode(d+(c>>3)+32)),d=(7&c)<<12 +break +case 3:e.push(String.fromCharCode(d+(c>>4)+32)),d=(15&c)<<11 +break +case 4:e.push(String.fromCharCode(d+(c>>5)+32)),d=(31&c)<<10 +break +case 5:e.push(String.fromCharCode(d+(c>>6)+32)),d=(63&c)<<9 +break +case 6:e.push(String.fromCharCode(d+(c>>7)+32)),d=(127&c)<<8 +break +case 7:e.push(String.fromCharCode(d+(c>>8)+32)),d=(255&c)<<7 +break +case 8:e.push(String.fromCharCode(d+(c>>9)+32)),d=(511&c)<<6 +break +case 9:e.push(String.fromCharCode(d+(c>>10)+32)),d=(1023&c)<<5 +break +case 10:e.push(String.fromCharCode(d+(c>>11)+32)),d=(2047&c)<<4 +break +case 11:e.push(String.fromCharCode(d+(c>>12)+32)),d=(4095&c)<<3 +break +case 12:e.push(String.fromCharCode(d+(c>>13)+32)),d=(8191&c)<<2 +break +case 13:e.push(String.fromCharCode(d+(c>>14)+32)),d=(16383&c)<<1 +break +case 14:e.push(String.fromCharCode(d+(c>>15)+32,(32767&c)+32)),f=0}return e.push(String.fromCharCode(d+32)),e.join("")},decompressFromUTF16:function(a){for(var b,c,d=[],e=0,f=0;f>14)),b=(16383&c)<<2 +break +case 2:d.push(String.fromCharCode(b|c>>13)),b=(8191&c)<<3 +break +case 3:d.push(String.fromCharCode(b|c>>12)),b=(4095&c)<<4 +break +case 4:d.push(String.fromCharCode(b|c>>11)),b=(2047&c)<<5 +break +case 5:d.push(String.fromCharCode(b|c>>10)),b=(1023&c)<<6 +break +case 6:d.push(String.fromCharCode(b|c>>9)),b=(511&c)<<7 +break +case 7:d.push(String.fromCharCode(b|c>>8)),b=(255&c)<<8 +break +case 8:d.push(String.fromCharCode(b|c>>7)),b=(127&c)<<9 +break +case 9:d.push(String.fromCharCode(b|c>>6)),b=(63&c)<<10 +break +case 10:d.push(String.fromCharCode(b|c>>5)),b=(31&c)<<11 +break +case 11:d.push(String.fromCharCode(b|c>>4)),b=(15&c)<<12 +break +case 12:d.push(String.fromCharCode(b|c>>3)),b=(7&c)<<13 +break +case 13:d.push(String.fromCharCode(b|c>>2)),b=(3&c)<<14 +break +case 14:d.push(String.fromCharCode(b|c>>1)),b=(1&c)<<15 +break +case 15:d.push(String.fromCharCode(b|c)),e=0}f++}return this.decompress(d.join(""))},_keyStr:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",decompress:function(a){for(var b,c,d,e,f,g,h,i=[],j=1,k=a.charCodeAt(0)>>8;j<2*a.length&&(j<2*a.length-1||0===k);)j%2===0?(b=a.charCodeAt(j/2)>>8,c=255&a.charCodeAt(j/2),d=j/2+1>8:NaN):(b=255&a.charCodeAt((j-1)/2),(j+1)/2>8,d=255&a.charCodeAt((j+1)/2)):c=d=NaN),j+=3,e=b>>2,f=(3&b)<<4|c>>4,g=(15&c)<<2|d>>6,h=63&d,isNaN(c)||j==2*a.length+1&&k?g=h=64:(isNaN(d)||j==2*a.length&&k)&&(h=64),i.push(this._keyStr.charAt(e)),i.push(this._keyStr.charAt(f)),i.push(this._keyStr.charAt(g)),i.push(this._keyStr.charAt(h)) +return i.join("")},compress:function(a){var b,c,d,e,f,g,h,i,j=[],k=1,l=0,m=!1 +for(a=a.replace(/[^A-Za-z0-9\+\/\=]/g,"");l>4,d=(15&g)<<4|h>>2,e=(3&h)<<6|i,k%2===0?(b=c<<8,m=!0,64!=h&&(j.push(String.fromCharCode(b|d)),m=!1),64!=i&&(b=e<<8,m=!0)):(j.push(String.fromCharCode(b|c)),m=!1,64!=h&&(b=d<<8,m=!0),64!=i&&(j.push(String.fromCharCode(b|e)),m=!1)),k+=3 +return m?(j.push(String.fromCharCode(b)),j=j.join(""),j=String.fromCharCode(256|j.charCodeAt(0))+j.substring(1)):j=j.join(""),j}},O.esri.Tiles.saveAs=function(a){"use strict" var b=a.document,c=function(){return a.URL||a.webkitURL||a},d=a.URL||a.webkitURL||a,e=b.createElementNS("http://www.w3.org/1999/xhtml","a"),f=!a.externalHost&&"download"in e,g=a.webkitRequestFileSystem,h=a.requestFileSystem||g||a.mozRequestFileSystem,i=function(b){(a.setImmediate||a.setTimeout)(function(){throw b},0)},j="application/octet-stream",k=0,l=[],m=function(){for(var a=l.length;a--;){var b=l[a] "string"==typeof b?d.revokeObjectURL(b):b.remove()}l.length=0},n=function(a,b,c){b=[].concat(b) for(var d=b.length;d--;){var e=a["on"+b[d]] @@ -58,10 +120,12 @@ return c.level=b.level,c.resolution=b.resolution,c.scale=b.scale,b.hasOwnPropert var k=new f(parseFloat(d.initialExtent.xmin),parseFloat(d.initialExtent.ymin),parseFloat(d.initialExtent.xmax),parseFloat(d.initialExtent.ymax),i),l=new f(parseFloat(d.fullExtent.xmin),parseFloat(d.fullExtent.ymin),parseFloat(d.fullExtent.xmax),parseFloat(d.fullExtent.ymax),i),m=new g(d.tileInfo),n=new h(m.origin.x,m.origin.y,i) m.origin=n,m.lods=j,b({initExtent:k,fullExtent:l,tileInfo:m,resultObj:d})})}},O.esri.Tiles.TilesStore=function(){this._db=null,this.dbName="offline_tile_store",this.objectStoreName="tilepath",this.isSupported=function(){return!(!window.indexedDB&&!window.openDatabase)},this.store=function(a,b){try{var c=this._db.transaction([this.objectStoreName],"readwrite") c.oncomplete=function(){b(!0)},c.onerror=function(a){b(!1,a.target.error.message)} -var d=c.objectStore(this.objectStoreName),e=d.put(a) +var d=c.objectStore(this.objectStoreName) +a.img=O.esri.Tiles.Base64String.compress(a.img) +var e=d.put(a) e.onsuccess=function(){}}catch(f){b(!1,f.stack)}},this.retrieve=function(a,b){if(null!==this._db){var c=this._db.transaction([this.objectStoreName]).objectStore(this.objectStoreName),d=c.get(a) d.onsuccess=function(a){var c=a.target.result -void 0===c?b(!1,"not found"):b(!0,c)},d.onerror=function(a){b(!1,a)}}},this.deleteAll=function(a){if(null!==this._db){var b=this._db.transaction([this.objectStoreName],"readwrite").objectStore(this.objectStoreName).clear() +void 0===c?b(!1,"not found"):(c.img=O.esri.Tiles.Base64String.decompress(c.img),b(!0,c))},d.onerror=function(a){b(!1,a)}}},this.deleteAll=function(a){if(null!==this._db){var b=this._db.transaction([this.objectStoreName],"readwrite").objectStore(this.objectStoreName).clear() b.onsuccess=function(){a(!0)},b.onerror=function(b){a(!1,b)}}else a(!1,null)},this["delete"]=function(a,b){if(null!==this._db){var c=this._db.transaction([this.objectStoreName],"readwrite").objectStore(this.objectStoreName)["delete"](a) c.onsuccess=function(){b(!0)},c.onerror=function(a){b(!1,a)}}else b(!1,null)},this.getAllTiles=function(a){if(null!==this._db){var b=this._db.transaction([this.objectStoreName]).objectStore(this.objectStoreName).openCursor() b.onsuccess=function(b){var c=b.target.result diff --git a/dist/offline-tiles-basic-src.js b/dist/offline-tiles-basic-src.js index 769fba4..5ba52b5 100644 --- a/dist/offline-tiles-basic-src.js +++ b/dist/offline-tiles-basic-src.js @@ -1,4 +1,4 @@ -/*! esri-offline-maps - v3.3.0 - 2016-07-12 +/*! esri-offline-maps - v3.4.0 - 2016-09-13 * Copyright (c) 2016 Environmental Systems Research Institute, Inc. * Apache License*/ define([ @@ -492,6 +492,299 @@ O.esri.Tiles.Base64Utils.wordToBase64=function(/* word[] */wa){ }; /*jslint bitwise: false */ +// Copyright (c) 2013 Pieroxy +// This work is free. You can redistribute it and/or modify it +// under the terms of the WTFPL, Version 2 +// For more information see LICENSE.txt or http://www.wtfpl.net/ +// +// This lib is part of the lz-string project. +// For more information, the home page: +// http://pieroxy.net/blog/pages/lz-string/index.html +// +// Base64 compression / decompression for already compressed content (gif, png, jpg, mp3, ...) +// version 1.4.1 + +/*jslint bitwise: true */ +O.esri.Tiles.Base64String = { + + compressToUTF16 : function (input) { + var output = [], + i,c, + current, + status = 0; + + input = this.compress(input); + + for (i=0 ; i> 1)+32)); + current = (c & 1) << 14; + break; + case 1: + output.push(String.fromCharCode((current + (c >> 2))+32)); + current = (c & 3) << 13; + break; + case 2: + output.push(String.fromCharCode((current + (c >> 3))+32)); + current = (c & 7) << 12; + break; + case 3: + output.push(String.fromCharCode((current + (c >> 4))+32)); + current = (c & 15) << 11; + break; + case 4: + output.push(String.fromCharCode((current + (c >> 5))+32)); + current = (c & 31) << 10; + break; + case 5: + output.push(String.fromCharCode((current + (c >> 6))+32)); + current = (c & 63) << 9; + break; + case 6: + output.push(String.fromCharCode((current + (c >> 7))+32)); + current = (c & 127) << 8; + break; + case 7: + output.push(String.fromCharCode((current + (c >> 8))+32)); + current = (c & 255) << 7; + break; + case 8: + output.push(String.fromCharCode((current + (c >> 9))+32)); + current = (c & 511) << 6; + break; + case 9: + output.push(String.fromCharCode((current + (c >> 10))+32)); + current = (c & 1023) << 5; + break; + case 10: + output.push(String.fromCharCode((current + (c >> 11))+32)); + current = (c & 2047) << 4; + break; + case 11: + output.push(String.fromCharCode((current + (c >> 12))+32)); + current = (c & 4095) << 3; + break; + case 12: + output.push(String.fromCharCode((current + (c >> 13))+32)); + current = (c & 8191) << 2; + break; + case 13: + output.push(String.fromCharCode((current + (c >> 14))+32)); + current = (c & 16383) << 1; + break; + case 14: + output.push(String.fromCharCode((current + (c >> 15))+32, (c & 32767)+32)); + status = 0; + break; + } + } + output.push(String.fromCharCode(current + 32)); + return output.join(''); + }, + + + decompressFromUTF16 : function (input) { + var output = [], + current,c, + status=0, + i = 0; + + while (i < input.length) { + c = input.charCodeAt(i) - 32; + + switch (status++) { + case 0: + current = c << 1; + break; + case 1: + output.push(String.fromCharCode(current | (c >> 14))); + current = (c&16383) << 2; + break; + case 2: + output.push(String.fromCharCode(current | (c >> 13))); + current = (c&8191) << 3; + break; + case 3: + output.push(String.fromCharCode(current | (c >> 12))); + current = (c&4095) << 4; + break; + case 4: + output.push(String.fromCharCode(current | (c >> 11))); + current = (c&2047) << 5; + break; + case 5: + output.push(String.fromCharCode(current | (c >> 10))); + current = (c&1023) << 6; + break; + case 6: + output.push(String.fromCharCode(current | (c >> 9))); + current = (c&511) << 7; + break; + case 7: + output.push(String.fromCharCode(current | (c >> 8))); + current = (c&255) << 8; + break; + case 8: + output.push(String.fromCharCode(current | (c >> 7))); + current = (c&127) << 9; + break; + case 9: + output.push(String.fromCharCode(current | (c >> 6))); + current = (c&63) << 10; + break; + case 10: + output.push(String.fromCharCode(current | (c >> 5))); + current = (c&31) << 11; + break; + case 11: + output.push(String.fromCharCode(current | (c >> 4))); + current = (c&15) << 12; + break; + case 12: + output.push(String.fromCharCode(current | (c >> 3))); + current = (c&7) << 13; + break; + case 13: + output.push(String.fromCharCode(current | (c >> 2))); + current = (c&3) << 14; + break; + case 14: + output.push(String.fromCharCode(current | (c >> 1))); + current = (c&1) << 15; + break; + case 15: + output.push(String.fromCharCode(current | c)); + status=0; + break; + } + + + i++; + } + + return this.decompress(output.join('')); + //return output; + + }, + + + // private property + _keyStr : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=", // jshint ignore:line + + decompress : function (input) { + var output = []; + var chr1, chr2, chr3, enc1, enc2, enc3, enc4; + var i = 1; + var odd = input.charCodeAt(0) >> 8; + + while (i < input.length*2 && (i < input.length*2-1 || odd===0)) { + + if (i%2===0) { + chr1 = input.charCodeAt(i/2) >> 8; + chr2 = input.charCodeAt(i/2) & 255; + if (i/2+1 < input.length) { + chr3 = input.charCodeAt(i / 2 + 1) >> 8; + } + else { + chr3 = NaN; + } + } else { + chr1 = input.charCodeAt((i-1)/2) & 255; + if ((i+1)/2 < input.length) { + chr2 = input.charCodeAt((i+1)/2) >> 8; + chr3 = input.charCodeAt((i+1)/2) & 255; + } else { + chr2 = chr3 = NaN; + } + } + i+=3; + + enc1 = chr1 >> 2; + enc2 = ((chr1 & 3) << 4) | (chr2 >> 4); + enc3 = ((chr2 & 15) << 2) | (chr3 >> 6); + enc4 = chr3 & 63; + + if (isNaN(chr2) || (i==input.length*2+1 && odd)) { + enc3 = enc4 = 64; + } else if (isNaN(chr3) || (i==input.length*2 && odd)) { + enc4 = 64; + } + + output.push(this._keyStr.charAt(enc1)); + output.push(this._keyStr.charAt(enc2)); + output.push(this._keyStr.charAt(enc3)); + output.push(this._keyStr.charAt(enc4)); + } + + return output.join(''); + }, + + compress : function (input) { + var output = [], + ol = 1, + output_, + chr1, chr2, chr3, + enc1, enc2, enc3, enc4, + i = 0, flush=false; + + input = input.replace(/[^A-Za-z0-9\+\/\=]/g, ""); // jshint ignore:line + + while (i < input.length) { + + enc1 = this._keyStr.indexOf(input.charAt(i++)); + enc2 = this._keyStr.indexOf(input.charAt(i++)); + enc3 = this._keyStr.indexOf(input.charAt(i++)); + enc4 = this._keyStr.indexOf(input.charAt(i++)); + + chr1 = (enc1 << 2) | (enc2 >> 4); + chr2 = ((enc2 & 15) << 4) | (enc3 >> 2); + chr3 = ((enc3 & 3) << 6) | enc4; + + if (ol%2===0) { + output_ = chr1 << 8; + flush = true; + + if (enc3 != 64) { + output.push(String.fromCharCode(output_ | chr2)); + flush = false; + } + if (enc4 != 64) { + output_ = chr3 << 8; + flush = true; + } + } else { + output.push(String.fromCharCode(output_ | chr1)); + flush = false; + + if (enc3 != 64) { + output_ = chr2 << 8; + flush = true; + } + if (enc4 != 64) { + output.push(String.fromCharCode(output_ | chr3)); + flush = false; + } + } + ol+=3; + } + + if (flush) { + output.push(String.fromCharCode(output_)); + output = output.join(''); + output = String.fromCharCode(output.charCodeAt(0)|256) + output.substring(1); + } else { + output = output.join(''); + } + + return output; + + } +}; + +/*jslint bitwise: false */ + /* FileSaver.js * A saveAs() FileSaver implementation. * 2013-10-21 @@ -749,7 +1042,7 @@ O.esri.Tiles.TilesCore = function(){ */ this._getTiles = function(image,imageType,url,tileid,store,query,showBlankTiles){ store.retrieve(url, function(success, offlineTile) - { console.log("TILE RETURN " + success + ", " + offlineTile.url); + { console.log("TILE RETURN " + success + ", " + offlineTile.url + ", " + tileid); /* when the .getTileUrl() callback is triggered we replace the temporary URL originally returned by the data:image url */ // search for the img with src="void:"+level+"-"+row+"-"+col and replace with actual url image = query("img[src="+tileid+"]")[0]; @@ -1179,6 +1472,7 @@ O.esri.Tiles.TilesStore = function(){ }; var objectStore = transaction.objectStore(this.objectStoreName); + urlDataPair.img = O.esri.Tiles.Base64String.compress(urlDataPair.img); var request = objectStore.put(urlDataPair); request.onsuccess = function() { @@ -1212,6 +1506,7 @@ O.esri.Tiles.TilesStore = function(){ } else { + result.img = O.esri.Tiles.Base64String.decompress(result.img); callback(true,result); } }; diff --git a/dist/offline-tpk-min.js b/dist/offline-tpk-min.js index ae7c08a..4b6e738 100644 --- a/dist/offline-tpk-min.js +++ b/dist/offline-tpk-min.js @@ -51,10 +51,12 @@ return 1===b.length?"000"+b:2===b.length?"00"+b:3===b.length?"0"+b:b.substr(0,b. return 16+5*f},_getCacheFilePath:function(a,b,c,d){var e=[] return e.push(a),e.push("/"),e.push("L"),e.push(10>b?"0"+b:b),e.push("/"),e.push("R"),e.push(this._int2HexString(c)),e.push("C"),e.push(this._int2HexString(d)),e.join("")},_bytes2MBs:function(a){return(a>>>20)+"."+(2046&a)}})}),"undefined"!=typeof O?O.esri.TPK={}:(O={},O.esri={TPK:{},Tiles:{}}),O.esri.Tiles.TilesStore=function(){this._db=null,this.dbName="offline_tile_store",this.objectStoreName="tilepath",this.isSupported=function(){return!(!window.indexedDB&&!window.openDatabase)},this.store=function(a,b){try{var c=this._db.transaction([this.objectStoreName],"readwrite") c.oncomplete=function(){b(!0)},c.onerror=function(a){b(!1,a.target.error.message)} -var d=c.objectStore(this.objectStoreName),e=d.put(a) +var d=c.objectStore(this.objectStoreName) +a.img=O.esri.Tiles.Base64String.compress(a.img) +var e=d.put(a) e.onsuccess=function(){}}catch(f){b(!1,f.stack)}},this.retrieve=function(a,b){if(null!==this._db){var c=this._db.transaction([this.objectStoreName]).objectStore(this.objectStoreName),d=c.get(a) d.onsuccess=function(a){var c=a.target.result -void 0===c?b(!1,"not found"):b(!0,c)},d.onerror=function(a){b(!1,a)}}},this.deleteAll=function(a){if(null!==this._db){var b=this._db.transaction([this.objectStoreName],"readwrite").objectStore(this.objectStoreName).clear() +void 0===c?b(!1,"not found"):(c.img=O.esri.Tiles.Base64String.decompress(c.img),b(!0,c))},d.onerror=function(a){b(!1,a)}}},this.deleteAll=function(a){if(null!==this._db){var b=this._db.transaction([this.objectStoreName],"readwrite").objectStore(this.objectStoreName).clear() b.onsuccess=function(){a(!0)},b.onerror=function(b){a(!1,b)}}else a(!1,null)},this["delete"]=function(a,b){if(null!==this._db){var c=this._db.transaction([this.objectStoreName],"readwrite").objectStore(this.objectStoreName)["delete"](a) c.onsuccess=function(){b(!0)},c.onerror=function(a){b(!1,a)}}else b(!1,null)},this.getAllTiles=function(a){if(null!==this._db){var b=this._db.transaction([this.objectStoreName]).objectStore(this.objectStoreName).openCursor() b.onsuccess=function(b){var c=b.target.result diff --git a/dist/offline-tpk-src.js b/dist/offline-tpk-src.js index 6fd468f..40a00a8 100644 --- a/dist/offline-tpk-src.js +++ b/dist/offline-tpk-src.js @@ -1,4 +1,4 @@ -/*! esri-offline-maps - v3.3.0 - 2016-07-12 +/*! esri-offline-maps - v3.4.0 - 2016-09-13 * Copyright (c) 2016 Environmental Systems Research Institute, Inc. * Apache License*/ /** @@ -794,6 +794,7 @@ O.esri.Tiles.TilesStore = function(){ }; var objectStore = transaction.objectStore(this.objectStoreName); + urlDataPair.img = O.esri.Tiles.Base64String.compress(urlDataPair.img); var request = objectStore.put(urlDataPair); request.onsuccess = function() { @@ -827,6 +828,7 @@ O.esri.Tiles.TilesStore = function(){ } else { + result.img = O.esri.Tiles.Base64String.decompress(result.img); callback(true,result); } }; diff --git a/lib/tiles/TilesStore.js b/lib/tiles/TilesStore.js index 08dd376..861f177 100644 --- a/lib/tiles/TilesStore.js +++ b/lib/tiles/TilesStore.js @@ -53,6 +53,7 @@ O.esri.Tiles.TilesStore = function(){ }; var objectStore = transaction.objectStore(this.objectStoreName); + urlDataPair.img = O.esri.Tiles.Base64String.compress(urlDataPair.img); var request = objectStore.put(urlDataPair); request.onsuccess = function() { @@ -86,6 +87,7 @@ O.esri.Tiles.TilesStore = function(){ } else { + result.img = O.esri.Tiles.Base64String.decompress(result.img); callback(true,result); } }; diff --git a/package.json b/package.json index 0e59a8b..315948d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "esri-offline-maps", - "version": "3.3.2", + "version": "3.4.0", "description": "Lightweight set of libraries for working offline with map tiles and editing with ArcGIS feature services", "author": "Andy Gup (http://blog.andygup.net)", "license": "Apache 2.0", diff --git a/samples/package.json b/samples/package.json index c9ffcdc..02ba734 100644 --- a/samples/package.json +++ b/samples/package.json @@ -9,7 +9,7 @@ "appHomePage": "appcache-tiles.html", "optimizedApiURL": "../samples/jsolib", "arcGISBaseURL": "http://js.arcgis.com/3.14", - "version": "3.3.2", + "version": "3.4.0", "private": true, "description": "manifest generator project", "repository": {