This repository has been archived by the owner on Nov 21, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 68
improvement proposal #31
Comments
Turning this into a diff to see the difference: I don't see the problem to create a PR
|
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
By using xhr requests instead of canvas rendering you could have a major performance improvement.
I do not have time for a proper pull request, but here is my take on pouchdb caching
import L from 'leaflet'
import PouchDB from '/imports/ui/components/pouchdb'
import qwest from 'qwest'
import logger from '../../logger'
L.TileLayer.addInitHook(function () {
if (this.options.cache) {
this.pouch = new PouchDB(
tiles-${this.options.cacheName}
, {size: 1000,
auto_compaction: true,
revs_limit: 1
})
logger.info(
pouchdb: ${this.pouch.name}, adapter: ${this.pouch.adapter}
)}
})
// Whether to use a PouchDB cache on this tile layer, or not
L.TileLayer.prototype.options.cache = false;
// Maximum age of the cache, in milliseconds
L.TileLayer.prototype.options.cacheMaxAge = 24 * 3600 * 1000;
L.TileLayer.include({
// Overwrites L.TileLayer.prototype.createTile
createTile(coords, done) {
const url = this.getTileUrl(coords);
const tile = document.createElement('img');
if (this.options.crossOrigin) {
tile.crossOrigin = '';
}
tile.onerror = () => {
logger.error(
bom.leaf load failed: ${tile.src}
)}
if (this.options.cache) {
this.pouch.get(url, {attachments: true, binary: true, revs_info: true}, this.onCacheLookup(tile, url, done));
} else {
// Fall back to standard behaviour
tile.onload = L.bind(this._tileOnLoad, this, done, tile);
tile.src = url;
}
return tile;
},
// Returns a callback (closure over tile/key/originalSrc) to be run when the DB backend is finished with a fetch operation.
onCacheLookup(tile, tileUrl, done) {
return function(err, data) {
if (data) {
this.fire('tilecachehit', {tile, url: tileUrl});
if ((Date.now() > (data.timestamp + this.options.cacheMaxAge))) {
// old tile, refresh it
tile.qwest = null
this.readAndSaveTile(tile, tileUrl, data._revs_info[0].rev, done)
} else {
// tile from cache
tile.onload = L.bind(this._tileOnLoad, this, done, tile);
tile.src = URL.createObjectURL(data._attachments.img.data);
}
} else {
this.fire('tilecachemiss', {tile, url: tileUrl});
this.readAndSaveTile(tile, tileUrl, null, done)
}
}.bind(this);
},
readAndSaveTile(tile, tileUrl, existingRevision, done) {
if (tile.qwest) {
return
}
let headers = {}
if (tileUrl.indexOf('cors-anywhere') >= 0) {
headers = {
'X-Requested-With': 'XMLHttpRequest'
}
}
tile.qwest = qwest.get(tileUrl, null, {headers, cache: true, responseType: 'blob'}).then(res => {
this.saveTile(res.response, tileUrl, existingRevision, done)
tile.src = URL.createObjectURL(res.response);
}).catch(error => {
logger.error('qwest error', error.message);
})
},
// Overwrite L.TileLayer.prototype._abortLoading
_abortLoading() {
let i
let tile
for (i in this._tiles) {
if (this._tiles[i].coords.z !== this._tileZoom) {
tile = this._tiles[i].el;
tile.onload = L.Util.falseFn;
tile.onerror = L.Util.falseFn;
if (!tile.complete) {
tile.src = L.Util.emptyImageUrl;
L.DomUtil.remove(tile);
}
if (tile.qwest) {
tile.qwest.abort()
}
}
}
},
// Returns an event handler (closure over DB key), which runs when the tile (which is an ) is ready.
// The handler will delete the document from pouchDB if an existing revision is passed.
// This will keep just the latest valid copy of the image in the cache.
saveTile(tileBlob, tileUrl, existingRevision, done) {
const doc = {
_id: tileUrl,
_attachments: {
img: {
content_type: 'image/jpeg',
data: tileBlob
}
},
timestamp: Date.now()
}
if (existingRevision) {
this.pouch.remove(tileUrl, existingRevision, () => {
this.pouchPut(doc)
})
} else {
this.pouchPut(doc)
}
if (done) {
done()
}
},
pouchPut(doc) {
this.pouch.put(doc).then(res => {
logger.debug('tile cached', res)
}).catch(err => {
if (err.status === 409) {
// document update conflicts may be caused by XHR flooding,
// but we can safely ignore them since we keep only one version anyway and we need no db sync
logger.debug(err)
} else {
logger.error(err)
}
this.fire('tilecacheerror', {tile: doc._id, error: err})
})
}
});
The text was updated successfully, but these errors were encountered: