Closed DrYSG closed 11 years ago
I haven't used createObjectURL
before, so I'm unsure if it would work in this case.
I do know, however, that if you base64 encode the image, you can store it as a string in IndexedDB or WebSQL. This plugin can then be used to return the data uri. You do end up with some storage overhead, and processing overhead, but I know it's a reliable way of storing tiles in the browser and displaying them.
From what I recall, Leaflet uses the result of this function to populate the src
attribute of the img
tags (tiles). That's the reason the above technique works. As for createObjectUrl
, I've never tried it, so I can't say.
Actually, that sounds good to me.
See this article where he fetches blobs from IndexedDB and sets the src attribute to show the image.
https://hacks.mozilla.org/2012/02/storing-images-and-files-in-indexeddb/
I plan to do some testing of this. How would you like me to report back? (i.e. I could not find your email, but I work in Cambridge, MA in Kendall Square, so it should be easy to shout you a message!
It would be great if you could comment on this issue with what you find. I will leave it open for now.
I think it would be really helpful to the community to demonstrate something like this working. I have yet to see a web app (non-native) that can show tiles when offline. I'm working on just that, but taking a slightly different approach.
I'm in the financial district. If you wanna reach me directly, I'm on twitter @ismyrnow.
It is going to take a little head scratching. One issue is that IndexedDB get("key") function returns a async callback (promise) that one assigns a handler to grab the results. In the snippet below I show how I get the item at key showID, fetch the blob, and set the image. Your functional tile plug-in, seems to want a function that returns an immediate and not deferred result.
function setImage() {
var trans, store, req;
var id = showID;
trans = DB.transaction(["Images"], "read");
store = trans.objectStore("Images");
req = store.get(id);
req.onsuccess = function(e) {
var blob = e.target.result;
var imgURL = URL.createObjectURL(blob);
// Set img src to ObjectURL
$("#imgTile").attr("src", imgURL);
// Revoking ObjectURL
URL.revokeObjectURL(imgURL);
};
}
You should be able to set up your layer like so:
var funcLayer = new L.TileLayer.Functional(function (view) {
var trans, store, req;
var deferred = new jQuery.Deferred(); // this is what gets returned
var id = showID; // replace showID with something based on the view object
trans = DB.transaction(["Images"], "read");
store = trans.objectStore("Images");
req = store.get(id);
req.onsuccess = function(e) {
var blob = e.target.result;
var imgURL = URL.createObjectURL(blob);
deferred.resolve(imgURL); // let leaflet know we're done, and give it the URL
URL.revokeObjectURL(imgURL); // not sure if we're revoking it too soon here
};
return deferred;
});
The view
argument in the anonymous function contains a bunch of stuff you would need for identifying a tile. The README contains more info.
I just tweeted you. I have it working now. There is one bug in your code I had to fix. There are also some things I would like to chat with you about. I included my email in the tweet. But performance is identical with a local file store of tiles. Which is great news.
The bug is is the L.FunctionalLayer.js code, (you forgot a "this" in two places.)
Glad you got it working! I'll shoot you an email, and we can continue the conversation offline.
If you found a bug, feel free to submit a pull request.
You mention IndexedDB. Can one return a createObjectUrl to a blob that was stored in an IndexedDB? (I figured out how to download a full slippy PNG map via XHR2 and store it as blobs in an IndexedDB. Now I want to create a custom tile layer for displaying it.
see: https://developer.mozilla.org/en-US/docs/DOM/window.URL.createObjectURL
and see my stack overflow: http://stackoverflow.com/questions/14113278/storing-image-data-for-offline-web-application-client-side-storage-database