Skip to content

Instantly share code, notes, and snippets.

@coomsie
Forked from leplatrem/gist:1415767
Created December 8, 2011 11:36
Show Gist options
  • Save coomsie/1446773 to your computer and use it in GitHub Desktop.
Save coomsie/1446773 to your computer and use it in GitHub Desktop.
Leaflet Offline Tiles using SQL Storage
/*
* L.TileLayer.LocalCache : A tile layer using SQL Storage, if available.
*/
L.TileLayer.LocalCache = L.TileLayer.extend({
options: {
minZoom: 0,
maxZoom: 18,
tileSize: 256,
subdomains: 'abc',
errorTileUrl: '',
attribution: '',
opacity: 1,
scheme: 'xyz',
noWrap: false,
unloadInvisibleTiles: L.Browser.mobileWebkit,
updateWhenIdle: L.Browser.mobileWebkit,
TOPO250_ZOOM_MIN : 5,
TOPO250_ZOOM_MAX : 12,
TOPO50_ZOOM_MIN :13,
TOPO50_ZOOM_MAX : 15,
PROVIDER: "Topo",
mimetype:'image/png'
},
initialize: function(url, tilestorage, options) {
this._url = url;
this.tilestorage = storage;
if (typeof this.options.subdomains == 'string') {
this.options.subdomains = this.options.subdomains.split('');
}
L.Util.setOptions(this, options);
},
_loadTile: function(tile, tilePoint, zoom) {
tile._layer = this;
tile.onload = this._tileOnLoad;
tile.onerror = this._tileOnError;
this.getTileUrl(tile, tilePoint, zoom);
},
getTileUrl: function(tile, tilePoint, zoom) {
var fallback;
var subdomains = this.options.subdomains,
s = this.options.subdomains[(tilePoint.x + tilePoint.y) % subdomains.length];
if(zoom >= this.options.TOPO250_ZOOM_MIN && zoom <= this.options.TOPO250_ZOOM_MAX) {
this._url= "http://{s}.domainname/{z}-{x}-{y}.png";
fallback = this._url
.replace('{s}', s)
.replace('{z}', zoom)
.replace('{x}', tilePoint.x)
.replace('{y}', tilePoint.y);
}
else if(zoom >= this.options.TOPO50_ZOOM_MIN && zoom <= this.options.TOPO50_ZOOM_MAX) {
this._url= "http://{s}.domainanme/{z}-{x}-{y}.png";
fallback = this._url
.replace('{s}', s)
.replace('{z}', zoom)
.replace('{x}', tilePoint.x)
.replace('{y}', tilePoint.y);
} else {
fallback = blankTile;
}
//Ti.API.log(fallback);
// fallback = this._url
// .replace('{s}', s)
// .replace('{z}', zoom)
// .replace('{x}', tilePoint.x)
// .replace('{y}', tilePoint.y);
this.tilestorage.loadTile(this.options.mimetype, this.options.PROVIDER,tile, zoom, tilePoint.x, tilePoint.y, fallback);
}
});
/*
* $.TileStorage : A tile SQL storage. (using Jquery, TODO: rewrite for Leaflet class model!)
*/
(function($){
$.TileStorage = function(options) {
var self = this;
var settings = $.extend({
dbname: 'TilesDB',
version: '1.0',
comment: 'Leaflet Tile Database',
size: 20000
}, options || {});
self.db = null;
self.initTiles = function (reset) {
self.db = openDatabase(settings.dbname, settings.version, settings.comment, settings.size);
if(!self.db) {
alert('Database open failed.');
}
if (reset) {
console.log("Creating tables...");
self.db.transaction(function(tx) {
tx.executeSql("DROP TABLE tiles;", [], function(tx, result) {}, function(tx, error) {});
tx.executeSql("CREATE TABLE tiles (z INT, x INT, y INT, data TEXT);", [],
function(tx, result) {
console.log('Database created.');
},
function(tx, error) {
self.__dbError(error);
}
);
});
}
};
self.storeTiles = function (data) {
if (!self.db) {
self.initTiles(true);
}
var nbtiles = 0;
$(data.tiles).each(function (index, value) {
var z = value.tile[0],
x = value.tile[1],
y = value.tile[2],
tiledata = "data:" + data.mimetype + ";base64," + value.data;
self._storeTile(z, x, y, tiledata, function(tx, result) {
nbtiles++;
});
});
console.log("Stored " + nbtiles + "/" + data.tiles.length + " tiles.");
};
self._storeTile = function (z, x, y, data, success) {
self.db.transaction(function (tx) {
tx.executeSql("INSERT INTO tiles (z, x, y, data) VALUES (?, ?, ?, ?);", [z, x, y, data],
success,
function(tx, error) {
self.__dbError(error);
}
);
});
};
self.loadTile = function (mimetype,provider, tile, z, x, y, fallback) {
if (!self.db) {
self.initTiles();
}
self.db.transaction(function (tx) {
tx.executeSql("INSERT INTO tiles (z, x, y, data) VALUES (?, ?, ?, ?);", [z, x, y, data],
success,
function(tx, error) {
self.__dbError(error);
}
);
});
//Create tile Object for saving tiles
var tileObject = new Object;
tileObject.image = new Image(); //tile;
tileObject.provider = provider;
tileObject.x = x;
tileObject.y = y;
tileObject.z = z;
tileObject.xyz = x +","+y+","+z;
tileObject.src = fallback;
tileObject.mimetype=mimetype;
var xyz = new String("");
xyz = x +","+y+","+z;
self.db.transaction(function (tx) {
//tx.executeSql("SELECT data FROM tiles WHERE z = ? AND x = ? AND y = ?", [z, x, y],
//Ti.API.log(xyz);
tx.executeSql("SELECT data FROM tiles WHERE provider = ? AND xyz = ?",[tileObject.provider , tileObject.xyz],
function(tx, result) {
if (result.rows.length > 0) {
tile.style.border = 'dotted 3px blue';
tile.src = result.rows.item(0).data;
}
else {
tile.style.border = 'dotted 3px red';
self.populateCache(tileObject);
tile.src = fallback;
}
},
function(tx, error) {
self.__dbError(error);
}
);
});
};
self.__dbError = function (err) {
Ti.API.log(err);
};
/*
* Functions for storing tiles while online to SQL Storage, if available.
*/
// from http://stackoverflow.com/questions/934012/get-image-data-in-javascript
self.getBase64Image = function (img,mimetype) {
canvas = document.createElement("canvas");
canvas.width = img.width;
canvas.height = img.height;
ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0);
return canvas.toDataURL(mimetype,'quality=20');
};
self.populateCache = function(tileObject){
// using canvas toDataURL method to generate base64 string
tileObject.image.src=tileObject.src;
tileObject.image.onload = function(){
tileObject.data = self.getBase64Image(tileObject.image, tileObject.mimetype);
self.writeTileToCache(tileObject);
}
};
self.writeTileToCache = function(tileObject){
var d=new Date();
d.toLocaleDateString();
var timestamp = d;
var provider = tileObject.provider;
var xyz=tileObject.xyz;
var x = tileObject.x;
var y = tileObject.y;
var z = tileObject.z;
var data = tileObject.data;
self.db.transaction(function (tx) {
tx.executeSql("INSERT INTO tiles (provider,xyz, x, y, z, timestamp,data) VALUES (?,?,?,?,?,?,?);", [provider,xyz,x,y,z,timestamp,data],
function(tx, result) {
},
function(tx, error) {
self.__dbError(error);
}
);
});
tileObject = null; //release tileObject
};
};
})(jQuery);
@coomsie
Copy link
Author

coomsie commented Dec 8, 2011

added some save back to db options when browsing via the internet

also can cope with my different urls at different zoom levels

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment