Skip to content

Commit

Permalink
Add cache support (#41)
Browse files Browse the repository at this point in the history
* Add cache support (closes #15)

* Fix webpack build

* Store query for cached items, update existing cache item when found

Co-authored-by: Pierre Rudloff <contact@rudloff.pro>
  • Loading branch information
fodor0205 and Rudloff authored Feb 1, 2022
1 parent 8368092 commit c57c58f
Show file tree
Hide file tree
Showing 4 changed files with 113 additions and 10 deletions.
5 changes: 5 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
]
},
"dependencies": {
"idb": "^4.0.5",
"js-clipper": "^1.0.1",
"leaflet": "^1.2.0"
},
Expand All @@ -48,6 +49,7 @@
"babel-core": "^6.26.0",
"babel-eslint": "^8.0.1",
"babel-loader": "^7.1.2",
"babel-polyfill": "^6.26.0",
"babel-preset-env": "^1.6.0",
"babel-preset-stage-0": "^6.24.1",
"css-loader": "^0.28.7",
Expand All @@ -60,6 +62,7 @@
"lint-staged": "^4.2.3",
"postcss-loader": "^2.0.7",
"prettier": "^1.7.4",
"uglifyjs-webpack-plugin": "1.3.0",
"webpack": "^3.6.0"
}
}
94 changes: 93 additions & 1 deletion src/OverPassLayer.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import L from 'leaflet';
import ClipperLib from 'js-clipper';
import { openDB } from 'idb';
import './OverPassLayer.css';
import './MinZoomIndicator';

Expand All @@ -14,6 +15,8 @@ const OverPassLayer = L.FeatureGroup.extend({
timeout: 30 * 1000, // Milliseconds
retryOnTimeout: false,
noInitialRequest: false,
cacheEnabled: false,
cacheTTL: 1800, // Seconds

beforeRequest() {},

Expand Down Expand Up @@ -73,6 +76,23 @@ const OverPassLayer = L.FeatureGroup.extend({
this._ids = {};
this._loadedBounds = options.loadedBounds || [];
this._requestInProgress = false;

if (this.options.cacheEnabled) {
this._initCacheDb();
}
},

async _initCacheDb() {
this._cacheDb = await openDB('leaflet-overpass-layer', 1, {
upgrade(db) {
db.createObjectStore('cache', { autoIncrement: true });
}
});

const layerAddedToMap = !!this._map;
if (layerAddedToMap) {
this._loadCachedItems();
}
},

_getPoiPopupHTML(tags, id) {
Expand Down Expand Up @@ -328,7 +348,39 @@ const OverPassLayer = L.FeatureGroup.extend({

_onRequestLoad(xhr, bounds) {
if (xhr.status >= 200 && xhr.status < 400) {
this.options.onSuccess.call(this, JSON.parse(xhr.response));
let result = JSON.parse(xhr.response);
this.options.onSuccess.call(this, result);

const cacheDbInitialized = typeof this._cacheDb !== 'undefined';
if (this.options.cacheEnabled && cacheDbInitialized) {
let expireDate = new Date();
expireDate.setSeconds(expireDate.getSeconds() + this.options.cacheTTL);

this._getCachedItems().then(cachedItems => {
let existingCacheKey = undefined;

cachedItems.forEach((cachedItem, key) => {
const queryEquals = cachedItem.query === this.options.query;
const northEast = L.latLng(cachedItem.bounds._northEast);
const southWest = L.latLng(cachedItem.bounds._southWest);
const cachedItemBounds = L.latLngBounds(northEast, southWest);
if (queryEquals && bounds.equals(cachedItemBounds)) {
existingCacheKey = key;
}
});

this._cacheDb.put(
'cache',
{
query: this.options.query,
result: result,
bounds: bounds,
expires: expireDate
},
existingCacheKey
);
});
}

this._onRequestLoadCallback(bounds);
} else {
Expand Down Expand Up @@ -379,6 +431,39 @@ const OverPassLayer = L.FeatureGroup.extend({
}
},

async _getCachedItems() {
const cacheDbInitialized = typeof this._cacheDb !== 'undefined';
if (!cacheDbInitialized) return;

const keys = await this._cacheDb.getAllKeys('cache');
const items = await this._cacheDb.getAll('cache');

const itemsMap = new Map();
items.forEach((item, i) => {
const key = keys[i];
itemsMap.set(key, item);
});

return itemsMap;
},

async _loadCachedItems() {
const cacheDbInitialized = typeof this._cacheDb !== 'undefined';
if (!cacheDbInitialized || !this._map) return;

const cachedItems = await this._getCachedItems();
cachedItems.forEach((cachedItem, key) => {
if (new Date() > cachedItem.expires) {
this._cacheDb.delete('cache', key);
} else {
if (cachedItem.query === this.options.query) {
this.options.onSuccess.call(this, cachedItem.result);
this._onRequestLoadCallback(cachedItem.bounds);
}
}
});
},

onAdd(map) {
this._map = map;

Expand All @@ -404,6 +489,13 @@ const OverPassLayer = L.FeatureGroup.extend({

this._markers = L.featureGroup().addTo(this._map);

if (this.options.cacheEnabled) {
const cacheDbInitialized = typeof this._cacheDb !== 'undefined';
if (cacheDbInitialized) {
this._loadCachedItems();
}
}

if (!this.options.noInitialRequest) {
this._prepareRequest();
}
Expand Down
21 changes: 12 additions & 9 deletions webpack.config.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,22 @@
const webpack = require('webpack');
const path = require('path');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
const extractCSS = new ExtractTextPlugin('OverPassLayer.css');

const plugins = [extractCSS];

plugins.push(
new webpack.optimize.UglifyJsPlugin({
minimize: true,
mangle: true,
output: {
comments: false
},
compress: {
warnings: false
new UglifyJsPlugin({
uglifyOptions: {
minimize: true,
mangle: true,
output: {
comments: false
},
compress: {
warnings: false
}
}
})
);
Expand All @@ -23,7 +26,7 @@ module.exports = {
plugins: plugins,
context: path.join(__dirname, 'src'),
entry: {
OverPassLayer: './OverPassLayer'
OverPassLayer: ['babel-polyfill', './OverPassLayer']
},
output: {
path: path.join(__dirname, 'dist'),
Expand Down

0 comments on commit c57c58f

Please sign in to comment.