ismyrnow / Leaflet.functionaltilelayer

Leaflet tile layer with functionally defined URL and support for promises.
MIT License
72 stars 15 forks source link

IndexedDB #1

Closed DrYSG closed 11 years ago

DrYSG commented 11 years ago

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

ismyrnow commented 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.

DrYSG commented 11 years ago

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!

ismyrnow commented 11 years ago

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.

DrYSG commented 11 years ago

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);
    };
}
ismyrnow commented 11 years ago

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.

DrYSG commented 11 years ago

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.

DrYSG commented 11 years ago

The bug is is the L.FunctionalLayer.js code, (you forgot a "this" in two places.)

ismyrnow commented 11 years ago

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.