From 63064667e3e27cca7c9a19a2411b8e35457cfd66 Mon Sep 17 00:00:00 2001 From: Wil Black Date: Thu, 13 Nov 2014 15:17:48 -0800 Subject: [PATCH 1/3] Got offline maps working. Needs some touching up but it's caching. --- README.md | 9 +- demo/offlinemap.js | 3298 +++++++++++++++++++++++++++++++++++++++ demo/regions-demo.html | 191 +++ dist/offlinemap.js | 101 +- dist/offlinemap.min.js | 4 +- gulpfile.coffee | 4 +- src/ImageStore.coffee | 1 + src/OfflineLayer.coffee | 131 +- 8 files changed, 3722 insertions(+), 17 deletions(-) create mode 100644 demo/offlinemap.js create mode 100644 demo/regions-demo.html mode change 100755 => 100644 dist/offlinemap.min.js diff --git a/README.md b/README.md index a93521f..7b05c62 100644 --- a/README.md +++ b/README.md @@ -76,4 +76,11 @@ This could happen if these functions are called before the onReady callback or i ##Example -Look at **src/demo.coffee** for a complete example of how to use OfflineLayer and a basic progression control example. \ No newline at end of file +Look at **src/demo.coffee** for a complete example of how to use OfflineLayer and a basic progression control example. + + +To run the examples + +``` +npm install +``` \ No newline at end of file diff --git a/demo/offlinemap.js b/demo/offlinemap.js new file mode 100644 index 0000000..4d75387 --- /dev/null +++ b/demo/offlinemap.js @@ -0,0 +1,3298 @@ +(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o= arr.length) { + callback(); + } + } + } + }; + async.forEach = async.each; + + async.eachSeries = function (arr, iterator, callback) { + callback = callback || function () {}; + if (!arr.length) { + return callback(); + } + var completed = 0; + var iterate = function () { + iterator(arr[completed], function (err) { + if (err) { + callback(err); + callback = function () {}; + } + else { + completed += 1; + if (completed >= arr.length) { + callback(); + } + else { + iterate(); + } + } + }); + }; + iterate(); + }; + async.forEachSeries = async.eachSeries; + + async.eachLimit = function (arr, limit, iterator, callback) { + var fn = _eachLimit(limit); + fn.apply(null, [arr, iterator, callback]); + }; + async.forEachLimit = async.eachLimit; + + var _eachLimit = function (limit) { + + return function (arr, iterator, callback) { + callback = callback || function () {}; + if (!arr.length || limit <= 0) { + return callback(); + } + var completed = 0; + var started = 0; + var running = 0; + + (function replenish () { + if (completed >= arr.length) { + return callback(); + } + + while (running < limit && started < arr.length) { + started += 1; + running += 1; + iterator(arr[started - 1], function (err) { + if (err) { + callback(err); + callback = function () {}; + } + else { + completed += 1; + running -= 1; + if (completed >= arr.length) { + callback(); + } + else { + replenish(); + } + } + }); + } + })(); + }; + }; + + + var doParallel = function (fn) { + return function () { + var args = Array.prototype.slice.call(arguments); + return fn.apply(null, [async.each].concat(args)); + }; + }; + var doParallelLimit = function(limit, fn) { + return function () { + var args = Array.prototype.slice.call(arguments); + return fn.apply(null, [_eachLimit(limit)].concat(args)); + }; + }; + var doSeries = function (fn) { + return function () { + var args = Array.prototype.slice.call(arguments); + return fn.apply(null, [async.eachSeries].concat(args)); + }; + }; + + + var _asyncMap = function (eachfn, arr, iterator, callback) { + arr = _map(arr, function (x, i) { + return {index: i, value: x}; + }); + if (!callback) { + eachfn(arr, function (x, callback) { + iterator(x.value, function (err) { + callback(err); + }); + }); + } else { + var results = []; + eachfn(arr, function (x, callback) { + iterator(x.value, function (err, v) { + results[x.index] = v; + callback(err); + }); + }, function (err) { + callback(err, results); + }); + } + }; + async.map = doParallel(_asyncMap); + async.mapSeries = doSeries(_asyncMap); + async.mapLimit = function (arr, limit, iterator, callback) { + return _mapLimit(limit)(arr, iterator, callback); + }; + + var _mapLimit = function(limit) { + return doParallelLimit(limit, _asyncMap); + }; + + // reduce only has a series version, as doing reduce in parallel won't + // work in many situations. + async.reduce = function (arr, memo, iterator, callback) { + async.eachSeries(arr, function (x, callback) { + iterator(memo, x, function (err, v) { + memo = v; + callback(err); + }); + }, function (err) { + callback(err, memo); + }); + }; + // inject alias + async.inject = async.reduce; + // foldl alias + async.foldl = async.reduce; + + async.reduceRight = function (arr, memo, iterator, callback) { + var reversed = _map(arr, function (x) { + return x; + }).reverse(); + async.reduce(reversed, memo, iterator, callback); + }; + // foldr alias + async.foldr = async.reduceRight; + + var _filter = function (eachfn, arr, iterator, callback) { + var results = []; + arr = _map(arr, function (x, i) { + return {index: i, value: x}; + }); + eachfn(arr, function (x, callback) { + iterator(x.value, function (v) { + if (v) { + results.push(x); + } + callback(); + }); + }, function (err) { + callback(_map(results.sort(function (a, b) { + return a.index - b.index; + }), function (x) { + return x.value; + })); + }); + }; + async.filter = doParallel(_filter); + async.filterSeries = doSeries(_filter); + // select alias + async.select = async.filter; + async.selectSeries = async.filterSeries; + + var _reject = function (eachfn, arr, iterator, callback) { + var results = []; + arr = _map(arr, function (x, i) { + return {index: i, value: x}; + }); + eachfn(arr, function (x, callback) { + iterator(x.value, function (v) { + if (!v) { + results.push(x); + } + callback(); + }); + }, function (err) { + callback(_map(results.sort(function (a, b) { + return a.index - b.index; + }), function (x) { + return x.value; + })); + }); + }; + async.reject = doParallel(_reject); + async.rejectSeries = doSeries(_reject); + + var _detect = function (eachfn, arr, iterator, main_callback) { + eachfn(arr, function (x, callback) { + iterator(x, function (result) { + if (result) { + main_callback(x); + main_callback = function () {}; + } + else { + callback(); + } + }); + }, function (err) { + main_callback(); + }); + }; + async.detect = doParallel(_detect); + async.detectSeries = doSeries(_detect); + + async.some = function (arr, iterator, main_callback) { + async.each(arr, function (x, callback) { + iterator(x, function (v) { + if (v) { + main_callback(true); + main_callback = function () {}; + } + callback(); + }); + }, function (err) { + main_callback(false); + }); + }; + // any alias + async.any = async.some; + + async.every = function (arr, iterator, main_callback) { + async.each(arr, function (x, callback) { + iterator(x, function (v) { + if (!v) { + main_callback(false); + main_callback = function () {}; + } + callback(); + }); + }, function (err) { + main_callback(true); + }); + }; + // all alias + async.all = async.every; + + async.sortBy = function (arr, iterator, callback) { + async.map(arr, function (x, callback) { + iterator(x, function (err, criteria) { + if (err) { + callback(err); + } + else { + callback(null, {value: x, criteria: criteria}); + } + }); + }, function (err, results) { + if (err) { + return callback(err); + } + else { + var fn = function (left, right) { + var a = left.criteria, b = right.criteria; + return a < b ? -1 : a > b ? 1 : 0; + }; + callback(null, _map(results.sort(fn), function (x) { + return x.value; + })); + } + }); + }; + + async.auto = function (tasks, callback) { + callback = callback || function () {}; + var keys = _keys(tasks); + var remainingTasks = keys.length + if (!remainingTasks) { + return callback(); + } + + var results = {}; + + var listeners = []; + var addListener = function (fn) { + listeners.unshift(fn); + }; + var removeListener = function (fn) { + for (var i = 0; i < listeners.length; i += 1) { + if (listeners[i] === fn) { + listeners.splice(i, 1); + return; + } + } + }; + var taskComplete = function () { + remainingTasks-- + _each(listeners.slice(0), function (fn) { + fn(); + }); + }; + + addListener(function () { + if (!remainingTasks) { + var theCallback = callback; + // prevent final callback from calling itself if it errors + callback = function () {}; + + theCallback(null, results); + } + }); + + _each(keys, function (k) { + var task = _isArray(tasks[k]) ? tasks[k]: [tasks[k]]; + var taskCallback = function (err) { + var args = Array.prototype.slice.call(arguments, 1); + if (args.length <= 1) { + args = args[0]; + } + if (err) { + var safeResults = {}; + _each(_keys(results), function(rkey) { + safeResults[rkey] = results[rkey]; + }); + safeResults[k] = args; + callback(err, safeResults); + // stop subsequent errors hitting callback multiple times + callback = function () {}; + } + else { + results[k] = args; + async.setImmediate(taskComplete); + } + }; + var requires = task.slice(0, Math.abs(task.length - 1)) || []; + var ready = function () { + return _reduce(requires, function (a, x) { + return (a && results.hasOwnProperty(x)); + }, true) && !results.hasOwnProperty(k); + }; + if (ready()) { + task[task.length - 1](taskCallback, results); + } + else { + var listener = function () { + if (ready()) { + removeListener(listener); + task[task.length - 1](taskCallback, results); + } + }; + addListener(listener); + } + }); + }; + + async.retry = function(times, task, callback) { + var DEFAULT_TIMES = 5; + var attempts = []; + // Use defaults if times not passed + if (typeof times === 'function') { + callback = task; + task = times; + times = DEFAULT_TIMES; + } + // Make sure times is a number + times = parseInt(times, 10) || DEFAULT_TIMES; + var wrappedTask = function(wrappedCallback, wrappedResults) { + var retryAttempt = function(task, finalAttempt) { + return function(seriesCallback) { + task(function(err, result){ + seriesCallback(!err || finalAttempt, {err: err, result: result}); + }, wrappedResults); + }; + }; + while (times) { + attempts.push(retryAttempt(task, !(times-=1))); + } + async.series(attempts, function(done, data){ + data = data[data.length - 1]; + (wrappedCallback || callback)(data.err, data.result); + }); + } + // If a callback is passed, run this as a controll flow + return callback ? wrappedTask() : wrappedTask + }; + + async.waterfall = function (tasks, callback) { + callback = callback || function () {}; + if (!_isArray(tasks)) { + var err = new Error('First argument to waterfall must be an array of functions'); + return callback(err); + } + if (!tasks.length) { + return callback(); + } + var wrapIterator = function (iterator) { + return function (err) { + if (err) { + callback.apply(null, arguments); + callback = function () {}; + } + else { + var args = Array.prototype.slice.call(arguments, 1); + var next = iterator.next(); + if (next) { + args.push(wrapIterator(next)); + } + else { + args.push(callback); + } + async.setImmediate(function () { + iterator.apply(null, args); + }); + } + }; + }; + wrapIterator(async.iterator(tasks))(); + }; + + var _parallel = function(eachfn, tasks, callback) { + callback = callback || function () {}; + if (_isArray(tasks)) { + eachfn.map(tasks, function (fn, callback) { + if (fn) { + fn(function (err) { + var args = Array.prototype.slice.call(arguments, 1); + if (args.length <= 1) { + args = args[0]; + } + callback.call(null, err, args); + }); + } + }, callback); + } + else { + var results = {}; + eachfn.each(_keys(tasks), function (k, callback) { + tasks[k](function (err) { + var args = Array.prototype.slice.call(arguments, 1); + if (args.length <= 1) { + args = args[0]; + } + results[k] = args; + callback(err); + }); + }, function (err) { + callback(err, results); + }); + } + }; + + async.parallel = function (tasks, callback) { + _parallel({ map: async.map, each: async.each }, tasks, callback); + }; + + async.parallelLimit = function(tasks, limit, callback) { + _parallel({ map: _mapLimit(limit), each: _eachLimit(limit) }, tasks, callback); + }; + + async.series = function (tasks, callback) { + callback = callback || function () {}; + if (_isArray(tasks)) { + async.mapSeries(tasks, function (fn, callback) { + if (fn) { + fn(function (err) { + var args = Array.prototype.slice.call(arguments, 1); + if (args.length <= 1) { + args = args[0]; + } + callback.call(null, err, args); + }); + } + }, callback); + } + else { + var results = {}; + async.eachSeries(_keys(tasks), function (k, callback) { + tasks[k](function (err) { + var args = Array.prototype.slice.call(arguments, 1); + if (args.length <= 1) { + args = args[0]; + } + results[k] = args; + callback(err); + }); + }, function (err) { + callback(err, results); + }); + } + }; + + async.iterator = function (tasks) { + var makeCallback = function (index) { + var fn = function () { + if (tasks.length) { + tasks[index].apply(null, arguments); + } + return fn.next(); + }; + fn.next = function () { + return (index < tasks.length - 1) ? makeCallback(index + 1): null; + }; + return fn; + }; + return makeCallback(0); + }; + + async.apply = function (fn) { + var args = Array.prototype.slice.call(arguments, 1); + return function () { + return fn.apply( + null, args.concat(Array.prototype.slice.call(arguments)) + ); + }; + }; + + var _concat = function (eachfn, arr, fn, callback) { + var r = []; + eachfn(arr, function (x, cb) { + fn(x, function (err, y) { + r = r.concat(y || []); + cb(err); + }); + }, function (err) { + callback(err, r); + }); + }; + async.concat = doParallel(_concat); + async.concatSeries = doSeries(_concat); + + async.whilst = function (test, iterator, callback) { + if (test()) { + iterator(function (err) { + if (err) { + return callback(err); + } + async.whilst(test, iterator, callback); + }); + } + else { + callback(); + } + }; + + async.doWhilst = function (iterator, test, callback) { + iterator(function (err) { + if (err) { + return callback(err); + } + var args = Array.prototype.slice.call(arguments, 1); + if (test.apply(null, args)) { + async.doWhilst(iterator, test, callback); + } + else { + callback(); + } + }); + }; + + async.until = function (test, iterator, callback) { + if (!test()) { + iterator(function (err) { + if (err) { + return callback(err); + } + async.until(test, iterator, callback); + }); + } + else { + callback(); + } + }; + + async.doUntil = function (iterator, test, callback) { + iterator(function (err) { + if (err) { + return callback(err); + } + var args = Array.prototype.slice.call(arguments, 1); + if (!test.apply(null, args)) { + async.doUntil(iterator, test, callback); + } + else { + callback(); + } + }); + }; + + async.queue = function (worker, concurrency) { + if (concurrency === undefined) { + concurrency = 1; + } + function _insert(q, data, pos, callback) { + if (!q.started){ + q.started = true; + } + if (!_isArray(data)) { + data = [data]; + } + if(data.length == 0) { + // call drain immediately if there are no tasks + return async.setImmediate(function() { + if (q.drain) { + q.drain(); + } + }); + } + _each(data, function(task) { + var item = { + data: task, + callback: typeof callback === 'function' ? callback : null + }; + + if (pos) { + q.tasks.unshift(item); + } else { + q.tasks.push(item); + } + + if (q.saturated && q.tasks.length === q.concurrency) { + q.saturated(); + } + async.setImmediate(q.process); + }); + } + + var workers = 0; + var q = { + tasks: [], + concurrency: concurrency, + saturated: null, + empty: null, + drain: null, + started: false, + paused: false, + push: function (data, callback) { + _insert(q, data, false, callback); + }, + kill: function () { + q.drain = null; + q.tasks = []; + }, + unshift: function (data, callback) { + _insert(q, data, true, callback); + }, + process: function () { + if (!q.paused && workers < q.concurrency && q.tasks.length) { + var task = q.tasks.shift(); + if (q.empty && q.tasks.length === 0) { + q.empty(); + } + workers += 1; + var next = function () { + workers -= 1; + if (task.callback) { + task.callback.apply(task, arguments); + } + if (q.drain && q.tasks.length + workers === 0) { + q.drain(); + } + q.process(); + }; + var cb = only_once(next); + worker(task.data, cb); + } + }, + length: function () { + return q.tasks.length; + }, + running: function () { + return workers; + }, + idle: function() { + return q.tasks.length + workers === 0; + }, + pause: function () { + if (q.paused === true) { return; } + q.paused = true; + q.process(); + }, + resume: function () { + if (q.paused === false) { return; } + q.paused = false; + q.process(); + } + }; + return q; + }; + + async.priorityQueue = function (worker, concurrency) { + + function _compareTasks(a, b){ + return a.priority - b.priority; + }; + + function _binarySearch(sequence, item, compare) { + var beg = -1, + end = sequence.length - 1; + while (beg < end) { + var mid = beg + ((end - beg + 1) >>> 1); + if (compare(item, sequence[mid]) >= 0) { + beg = mid; + } else { + end = mid - 1; + } + } + return beg; + } + + function _insert(q, data, priority, callback) { + if (!q.started){ + q.started = true; + } + if (!_isArray(data)) { + data = [data]; + } + if(data.length == 0) { + // call drain immediately if there are no tasks + return async.setImmediate(function() { + if (q.drain) { + q.drain(); + } + }); + } + _each(data, function(task) { + var item = { + data: task, + priority: priority, + callback: typeof callback === 'function' ? callback : null + }; + + q.tasks.splice(_binarySearch(q.tasks, item, _compareTasks) + 1, 0, item); + + if (q.saturated && q.tasks.length === q.concurrency) { + q.saturated(); + } + async.setImmediate(q.process); + }); + } + + // Start with a normal queue + var q = async.queue(worker, concurrency); + + // Override push to accept second parameter representing priority + q.push = function (data, priority, callback) { + _insert(q, data, priority, callback); + }; + + // Remove unshift function + delete q.unshift; + + return q; + }; + + async.cargo = function (worker, payload) { + var working = false, + tasks = []; + + var cargo = { + tasks: tasks, + payload: payload, + saturated: null, + empty: null, + drain: null, + drained: true, + push: function (data, callback) { + if (!_isArray(data)) { + data = [data]; + } + _each(data, function(task) { + tasks.push({ + data: task, + callback: typeof callback === 'function' ? callback : null + }); + cargo.drained = false; + if (cargo.saturated && tasks.length === payload) { + cargo.saturated(); + } + }); + async.setImmediate(cargo.process); + }, + process: function process() { + if (working) return; + if (tasks.length === 0) { + if(cargo.drain && !cargo.drained) cargo.drain(); + cargo.drained = true; + return; + } + + var ts = typeof payload === 'number' + ? tasks.splice(0, payload) + : tasks.splice(0, tasks.length); + + var ds = _map(ts, function (task) { + return task.data; + }); + + if(cargo.empty) cargo.empty(); + working = true; + worker(ds, function () { + working = false; + + var args = arguments; + _each(ts, function (data) { + if (data.callback) { + data.callback.apply(null, args); + } + }); + + process(); + }); + }, + length: function () { + return tasks.length; + }, + running: function () { + return working; + } + }; + return cargo; + }; + + var _console_fn = function (name) { + return function (fn) { + var args = Array.prototype.slice.call(arguments, 1); + fn.apply(null, args.concat([function (err) { + var args = Array.prototype.slice.call(arguments, 1); + if (typeof console !== 'undefined') { + if (err) { + if (console.error) { + console.error(err); + } + } + else if (console[name]) { + _each(args, function (x) { + console[name](x); + }); + } + } + }])); + }; + }; + async.log = _console_fn('log'); + async.dir = _console_fn('dir'); + /*async.info = _console_fn('info'); + async.warn = _console_fn('warn'); + async.error = _console_fn('error');*/ + + async.memoize = function (fn, hasher) { + var memo = {}; + var queues = {}; + hasher = hasher || function (x) { + return x; + }; + var memoized = function () { + var args = Array.prototype.slice.call(arguments); + var callback = args.pop(); + var key = hasher.apply(null, args); + if (key in memo) { + async.nextTick(function () { + callback.apply(null, memo[key]); + }); + } + else if (key in queues) { + queues[key].push(callback); + } + else { + queues[key] = [callback]; + fn.apply(null, args.concat([function () { + memo[key] = arguments; + var q = queues[key]; + delete queues[key]; + for (var i = 0, l = q.length; i < l; i++) { + q[i].apply(null, arguments); + } + }])); + } + }; + memoized.memo = memo; + memoized.unmemoized = fn; + return memoized; + }; + + async.unmemoize = function (fn) { + return function () { + return (fn.unmemoized || fn).apply(null, arguments); + }; + }; + + async.times = function (count, iterator, callback) { + var counter = []; + for (var i = 0; i < count; i++) { + counter.push(i); + } + return async.map(counter, iterator, callback); + }; + + async.timesSeries = function (count, iterator, callback) { + var counter = []; + for (var i = 0; i < count; i++) { + counter.push(i); + } + return async.mapSeries(counter, iterator, callback); + }; + + async.seq = function (/* functions... */) { + var fns = arguments; + return function () { + var that = this; + var args = Array.prototype.slice.call(arguments); + var callback = args.pop(); + async.reduce(fns, args, function (newargs, fn, cb) { + fn.apply(that, newargs.concat([function () { + var err = arguments[0]; + var nextargs = Array.prototype.slice.call(arguments, 1); + cb(err, nextargs); + }])) + }, + function (err, results) { + callback.apply(that, [err].concat(results)); + }); + }; + }; + + async.compose = function (/* functions... */) { + return async.seq.apply(null, Array.prototype.reverse.call(arguments)); + }; + + var _applyEach = function (eachfn, fns /*args...*/) { + var go = function () { + var that = this; + var args = Array.prototype.slice.call(arguments); + var callback = args.pop(); + return eachfn(fns, function (fn, cb) { + fn.apply(that, args.concat([cb])); + }, + callback); + }; + if (arguments.length > 2) { + var args = Array.prototype.slice.call(arguments, 2); + return go.apply(this, args); + } + else { + return go; + } + }; + async.applyEach = doParallel(_applyEach); + async.applyEachSeries = doSeries(_applyEach); + + async.forever = function (fn, callback) { + function next(err) { + if (err) { + if (callback) { + return callback(err); + } + throw err; + } + fn(next); + } + next(); + }; + + // Node.js + if (typeof module !== 'undefined' && module.exports) { + module.exports = async; + } + // AMD / RequireJS + else if (typeof define !== 'undefined' && define.amd) { + define([], function () { + return async; + }); + } + // included directly via + + + + +
+ + + + + + +
+ +
+
+
+ + + + + + \ No newline at end of file diff --git a/dist/offlinemap.js b/dist/offlinemap.js index f214db7..4d75387 100644 --- a/dist/offlinemap.js +++ b/dist/offlinemap.js @@ -1124,8 +1124,8 @@ }()); -}).call(this,require("/home/clayton/dev/mWater/offline-leaflet-map/node_modules/browserify/node_modules/insert-module-globals/node_modules/process/browser.js")) -},{"/home/clayton/dev/mWater/offline-leaflet-map/node_modules/browserify/node_modules/insert-module-globals/node_modules/process/browser.js":2}],2:[function(require,module,exports){ +}).call(this,require("+xKvab")) +},{"+xKvab":2}],2:[function(require,module,exports){ // shim for using process in browser var process = module.exports = {}; @@ -1173,8 +1173,11 @@ process.argv = []; function noop() {} process.on = noop; +process.addListener = noop; process.once = noop; process.off = noop; +process.removeListener = noop; +process.removeAllListeners = noop; process.emit = noop; process.binding = function (name) { @@ -2757,9 +2760,11 @@ module.exports = OfflineLayer = (function(_super) { OfflineLayer.prototype.initialize = function(url, options) { var dbOption, err, imageRetriever, storeName, useWebSQL; L.TileLayer.prototype.initialize.call(this, url, options); + this._map = options['map']; this._onReady = options["onReady"]; this._onError = options["onError"]; dbOption = options["dbOption"]; + this._dbOnly = options["dbOnly"]; storeName = options["storeName"] || 'OfflineLeafletTileImages'; this._tileImagesStore = null; this._minZoomLevel = 12; @@ -2825,6 +2830,9 @@ module.exports = OfflineLayer = (function(_super) { OfflineLayer.prototype._loadTile = function(tile, tilePoint) { var key, onError, onSuccess; + if (!this._dbOnly === true) { + this._dbOnly = false; + } if (!this._tileImagesStore) { return L.TileLayer.prototype._loadTile.call(this, tile, tilePoint); } @@ -2837,13 +2845,17 @@ module.exports = OfflineLayer = (function(_super) { if (dbEntry) { return _this._setUpTile(tile, key, dbEntry.image); } else { - return _this._setUpTile(tile, key, _this.getTileUrl(tilePoint)); + if (!_this._dbOnly) { + return _this._setUpTile(tile, key, _this.getTileUrl(tilePoint)); + } } }; })(this); onError = (function(_this) { return function() { - _this._setUpTile(tile, key, _this.getTileUrl(tilePoint)); + if (!_this._dbOnly) { + _this._setUpTile(tile, key, _this.getTileUrl(tilePoint)); + } return _this._reportError("DB_GET", key); }; })(this); @@ -2881,14 +2893,18 @@ module.exports = OfflineLayer = (function(_super) { })(this)); }; - OfflineLayer.prototype.calculateNbTiles = function(zoomLevelLimit) { + OfflineLayer.prototype.calculateNbTiles = function(zoomLevelLimit, regions) { var count, key, tileImagesToQuery; if (this._map.getZoom() < this._minZoomLevel) { this._reportError("ZOOM_LEVEL_TOO_LOW"); return -1; } count = 0; - tileImagesToQuery = this._getTileImages(zoomLevelLimit); + if (regions) { + tileImagesToQuery = this._getTilesByRegion(zoomLevelLimit, regions); + } else { + tileImagesToQuery = this._getTileImages(zoomLevelLimit); + } for (key in tileImagesToQuery) { count++; } @@ -2959,6 +2975,79 @@ module.exports = OfflineLayer = (function(_super) { })(this)); }; + OfflineLayer.prototype._getTilesByRegion = function(zoomLevelLimit, regions) { + var arrayLength, bounds, boundsORG, i, j, maxX, maxY, minX, minY, ne, pne, point, psw, region, roundedTileBounds, startingZoom, sw, tileBounds, tileImagesToQuery, tileSize, tilesInScreen, x, y, _i, _j, _k, _l, _len, _ref, _ref1, _ref2, _ref3; + console.log('[_getTilesByRegion()]'); + zoomLevelLimit = zoomLevelLimit || this._map.getMaxZoom(); + startingZoom = 12; + tileImagesToQuery = {}; + tileSize = this._getTileSize(); + boundsORG = this._map.getPixel; + for (_i = 0, _len = regions.length; _i < _len; _i++) { + region = regions[_i]; + console.log('[_getTilesByRegion()] Processing ' + region.name); + sw = L.latLng(region.sLat, region.wLng); + ne = L.latLng(region.nLat, region.eLng); + psw = L.point(this._map.project(sw, startingZoom).x, this._map.project(sw, startingZoom).y); + pne = L.point(this._map.project(ne, startingZoom).x, this._map.project(ne, startingZoom).y); + bounds = L.bounds(psw, pne); + roundedTileBounds = L.bounds(bounds.min.divideBy(tileSize)._floor(), bounds.max.divideBy(tileSize)._floor()); + console.log('[_getTilesByRegion()] roundedTileBounds'); + console.log(roundedTileBounds.min); + console.log(roundedTileBounds.max); + tilesInScreen = []; + for (j = _j = _ref = roundedTileBounds.min.y, _ref1 = roundedTileBounds.max.y; _ref <= _ref1 ? _j <= _ref1 : _j >= _ref1; j = _ref <= _ref1 ? ++_j : --_j) { + for (i = _k = _ref2 = roundedTileBounds.min.x, _ref3 = roundedTileBounds.max.x; _ref2 <= _ref3 ? _k <= _ref3 : _k >= _ref3; i = _ref2 <= _ref3 ? ++_k : --_k) { + tilesInScreen.push(new L.Point(i, j)); + } + } + tileBounds = L.bounds(bounds.min.divideBy(tileSize), bounds.max.divideBy(tileSize)); + minY = tileBounds.min.y; + maxY = tileBounds.max.y; + minX = tileBounds.min.x; + maxX = tileBounds.max.x; + arrayLength = tilesInScreen.length; + console.log('[_getTilesByRegion()] arrayLength = ' + arrayLength); + for (i = _l = 0; 0 <= arrayLength ? _l < arrayLength : _l > arrayLength; i = 0 <= arrayLength ? ++_l : --_l) { + point = tilesInScreen[i]; + x = point.x; + y = point.y; + this._getZoomedInTiles(x, y, startingZoom, zoomLevelLimit, tileImagesToQuery, minY, maxY, minX, maxX); + this._getZoomedOutTiles(x, y, startingZoom, 0, tileImagesToQuery, minY, maxY, minX, maxX); + } + } + return tileImagesToQuery; + }; + + OfflineLayer.prototype.saveRegions = function(regions, zoomLevelLimit, onStarted, onSuccess, onError) { + var tileImagesToQuery; + console.log('[saveRegions()]'); + if (!this._tileImagesStore) { + this._reportError("NO_DB", "No DB available"); + onError("No DB available"); + return; + } + if (this.isBusy()) { + this._reportError("SYSTEM_BUSY", "system is busy."); + onError("system is busy."); + return; + } + if (this._map.getZoom() < this._minZoomLevel) { + this._reportError("ZOOM_LEVEL_TOO_LOW"); + onError("ZOOM_LEVEL_TOO_LOW"); + return; + } + tileImagesToQuery = this._getTilesByRegion(zoomLevelLimit, regions); + console.log('[saveRegions] tileImagesToQuery'); + console.log(tileImagesToQuery); + return this._tileImagesStore.saveImages(tileImagesToQuery, onStarted, onSuccess, (function(_this) { + return function(error) { + _this._reportError("SAVING_TILES", error); + return onError(error); + }; + })(this)); + }; + OfflineLayer.prototype._getZoomedInTiles = function(x, y, currentZ, maxZ, tileImagesToQuery, minY, maxY, minX, maxX) { this._getTileImage(x, y, currentZ, tileImagesToQuery, minY, maxY, minX, maxX, true); if (currentZ < maxZ) { diff --git a/dist/offlinemap.min.js b/dist/offlinemap.min.js old mode 100755 new mode 100644 index 659e7a2..fdc77c4 --- a/dist/offlinemap.min.js +++ b/dist/offlinemap.min.js @@ -1,2 +1,2 @@ -!function e(t,n,r){function o(u,a){if(!n[u]){if(!t[u]){var s="function"==typeof require&&require;if(!a&&s)return s(u,!0);if(i)return i(u,!0);throw new Error("Cannot find module '"+u+"'")}var c=n[u]={exports:{}};t[u][0].call(c.exports,function(e){var n=t[u][1][e];return o(n?n:e)},c,c.exports,e,t,n,r)}return n[u].exports}for(var i="function"==typeof require&&require,u=0;u=e.length&&r())}if(r=r||function(){},!e.length)return r();var i=0;s(e,function(e){t(e,n(o))})},i.forEach=i.each,i.eachSeries=function(e,t,n){if(n=n||function(){},!e.length)return n();var r=0,o=function(){t(e[r],function(t){t?(n(t),n=function(){}):(r+=1,r>=e.length?n():o())})};o()},i.forEachSeries=i.eachSeries,i.eachLimit=function(e,t,n,r){var o=h(t);o.apply(null,[e,n,r])},i.forEachLimit=i.eachLimit;var h=function(e){return function(t,n,r){if(r=r||function(){},!t.length||0>=e)return r();var o=0,i=0,u=0;!function a(){if(o>=t.length)return r();for(;e>u&&i=t.length?r():a())})}()}},p=function(e){return function(){var t=Array.prototype.slice.call(arguments);return e.apply(null,[i.each].concat(t))}},d=function(e,t){return function(){var n=Array.prototype.slice.call(arguments);return t.apply(null,[h(e)].concat(n))}},m=function(e){return function(){var t=Array.prototype.slice.call(arguments);return e.apply(null,[i.eachSeries].concat(t))}},y=function(e,t,n,r){if(t=c(t,function(e,t){return{index:t,value:e}}),r){var o=[];e(t,function(e,t){n(e.value,function(n,r){o[e.index]=r,t(n)})},function(e){r(e,o)})}else e(t,function(e,t){n(e.value,function(e){t(e)})})};i.map=p(y),i.mapSeries=m(y),i.mapLimit=function(e,t,n,r){return v(t)(e,n,r)};var v=function(e){return d(e,y)};i.reduce=function(e,t,n,r){i.eachSeries(e,function(e,r){n(t,e,function(e,n){t=n,r(e)})},function(e){r(e,t)})},i.inject=i.reduce,i.foldl=i.reduce,i.reduceRight=function(e,t,n,r){var o=c(e,function(e){return e}).reverse();i.reduce(o,t,n,r)},i.foldr=i.reduceRight;var g=function(e,t,n,r){var o=[];t=c(t,function(e,t){return{index:t,value:e}}),e(t,function(e,t){n(e.value,function(n){n&&o.push(e),t()})},function(){r(c(o.sort(function(e,t){return e.index-t.index}),function(e){return e.value}))})};i.filter=p(g),i.filterSeries=m(g),i.select=i.filter,i.selectSeries=i.filterSeries;var _=function(e,t,n,r){var o=[];t=c(t,function(e,t){return{index:t,value:e}}),e(t,function(e,t){n(e.value,function(n){n||o.push(e),t()})},function(){r(c(o.sort(function(e,t){return e.index-t.index}),function(e){return e.value}))})};i.reject=p(_),i.rejectSeries=m(_);var b=function(e,t,n,r){e(t,function(e,t){n(e,function(n){n?(r(e),r=function(){}):t()})},function(){r()})};i.detect=p(b),i.detectSeries=m(b),i.some=function(e,t,n){i.each(e,function(e,r){t(e,function(e){e&&(n(!0),n=function(){}),r()})},function(){n(!1)})},i.any=i.some,i.every=function(e,t,n){i.each(e,function(e,r){t(e,function(e){e||(n(!1),n=function(){}),r()})},function(){n(!0)})},i.all=i.every,i.sortBy=function(e,t,n){i.map(e,function(e,n){t(e,function(t,r){t?n(t):n(null,{value:e,criteria:r})})},function(e,t){if(e)return n(e);var r=function(e,t){var n=e.criteria,r=t.criteria;return r>n?-1:n>r?1:0};n(null,c(t.sort(r),function(e){return e.value}))})},i.auto=function(e,t){t=t||function(){};var n=f(e),r=n.length;if(!r)return t();var o={},u=[],c=function(e){u.unshift(e)},h=function(e){for(var t=0;tr;){var i=r+(o-r+1>>>1);n(t,e[i])>=0?r=i:o=i-1}return r}function o(e,t,o,u){return e.started||(e.started=!0),a(t)||(t=[t]),0==t.length?i.setImmediate(function(){e.drain&&e.drain()}):void s(t,function(t){var a={data:t,priority:o,callback:"function"==typeof u?u:null};e.tasks.splice(r(e.tasks,a,n)+1,0,a),e.saturated&&e.tasks.length===e.concurrency&&e.saturated(),i.setImmediate(e.process)})}var u=i.queue(e,t);return u.push=function(e,t,n){o(u,e,t,n)},delete u.unshift,u},i.cargo=function(e,t){var n=!1,r=[],o={tasks:r,payload:t,saturated:null,empty:null,drain:null,drained:!0,push:function(e,n){a(e)||(e=[e]),s(e,function(e){r.push({data:e,callback:"function"==typeof n?n:null}),o.drained=!1,o.saturated&&r.length===t&&o.saturated()}),i.setImmediate(o.process)},process:function u(){if(!n){if(0===r.length)return o.drain&&!o.drained&&o.drain(),void(o.drained=!0);var i="number"==typeof t?r.splice(0,t):r.splice(0,r.length),a=c(i,function(e){return e.data});o.empty&&o.empty(),n=!0,e(a,function(){n=!1;var e=arguments;s(i,function(t){t.callback&&t.callback.apply(null,e)}),u()})}},length:function(){return r.length},running:function(){return n}};return o};var S=function(e){return function(t){var n=Array.prototype.slice.call(arguments,1);t.apply(null,n.concat([function(t){var n=Array.prototype.slice.call(arguments,1);"undefined"!=typeof console&&(t?console.error&&console.error(t):console[e]&&s(n,function(t){console[e](t)}))}]))}};i.log=S("log"),i.dir=S("dir"),i.memoize=function(e,t){var n={},r={};t=t||function(e){return e};var o=function(){var o=Array.prototype.slice.call(arguments),u=o.pop(),a=t.apply(null,o);a in n?i.nextTick(function(){u.apply(null,n[a])}):a in r?r[a].push(u):(r[a]=[u],e.apply(null,o.concat([function(){n[a]=arguments;var e=r[a];delete r[a];for(var t=0,o=e.length;o>t;t++)e[t].apply(null,arguments)}])))};return o.memo=n,o.unmemoized=e,o},i.unmemoize=function(e){return function(){return(e.unmemoized||e).apply(null,arguments)}},i.times=function(e,t,n){for(var r=[],o=0;e>o;o++)r.push(o);return i.map(r,t,n)},i.timesSeries=function(e,t,n){for(var r=[],o=0;e>o;o++)r.push(o);return i.mapSeries(r,t,n)},i.seq=function(){var e=arguments;return function(){var t=this,n=Array.prototype.slice.call(arguments),r=n.pop();i.reduce(e,n,function(e,n,r){n.apply(t,e.concat([function(){var e=arguments[0],t=Array.prototype.slice.call(arguments,1);r(e,t)}]))},function(e,n){r.apply(t,[e].concat(n))})}},i.compose=function(){return i.seq.apply(null,Array.prototype.reverse.call(arguments))};var I=function(e,t){var n=function(){var n=this,r=Array.prototype.slice.call(arguments),o=r.pop();return e(t,function(e,t){e.apply(n,r.concat([t]))},o)};if(arguments.length>2){var r=Array.prototype.slice.call(arguments,2);return n.apply(this,r)}return n};i.applyEach=p(I),i.applyEachSeries=m(I),i.forever=function(e,t){function n(r){if(r){if(t)return t(r);throw r}e(n)}n()},"undefined"!=typeof t&&t.exports?t.exports=i:"undefined"!=typeof define&&define.amd?define([],function(){return i}):r.async=i}()}).call(this,e("/home/clayton/dev/mWater/offline-leaflet-map/node_modules/browserify/node_modules/insert-module-globals/node_modules/process/browser.js"))},{"/home/clayton/dev/mWater/offline-leaflet-map/node_modules/browserify/node_modules/insert-module-globals/node_modules/process/browser.js":2}],2:[function(e,t){function n(){}var r=t.exports={};r.nextTick=function(){var e="undefined"!=typeof window&&window.setImmediate,t="undefined"!=typeof window&&window.postMessage&&window.addEventListener;if(e)return function(e){return window.setImmediate(e)};if(t){var n=[];return window.addEventListener("message",function(e){var t=e.source;if((t===window||null===t)&&"process-tick"===e.data&&(e.stopPropagation(),n.length>0)){var r=n.shift();r()}},!0),function(e){n.push(e),window.postMessage("process-tick","*")}}return function(e){setTimeout(e,0)}}(),r.title="browser",r.browser=!0,r.env={},r.argv=[],r.on=n,r.once=n,r.off=n,r.emit=n,r.binding=function(){throw new Error("process.binding is not supported")},r.cwd=function(){return"/"},r.chdir=function(){throw new Error("process.chdir is not supported")}},{}],3:[function(e,t){!function(e,n,r){"function"==typeof define?define(n):"undefined"!=typeof t&&t.exports?t.exports=n():r[e]=n()}("IDBStore",function(){"use strict";var e=function(e){throw e},t={storeName:"Store",storePrefix:"IDBWrapper-",dbVersion:1,keyPath:"id",autoIncrement:!0,onStoreReady:function(){},onError:e,indexes:[]},n=function(e,n){"undefined"==typeof n&&"function"==typeof e&&(n=e),"[object Object]"!=Object.prototype.toString.call(e)&&(e={});for(var r in t)this[r]="undefined"!=typeof e[r]?e[r]:t[r];this.dbName=this.storePrefix+this.storeName,this.dbVersion=parseInt(this.dbVersion,10)||1,n&&(this.onStoreReady=n);var o="object"==typeof window?window:self;this.idb=o.indexedDB||o.webkitIndexedDB||o.mozIndexedDB,this.keyRange=o.IDBKeyRange||o.webkitIDBKeyRange||o.mozIDBKeyRange,this.features={hasAutoIncrement:!o.mozIndexedDB},this.consts={READ_ONLY:"readonly",READ_WRITE:"readwrite",VERSION_CHANGE:"versionchange",NEXT:"next",NEXT_NO_DUPLICATE:"nextunique",PREV:"prev",PREV_NO_DUPLICATE:"prevunique"},this.openDB()};n.prototype={constructor:n,version:"1.4.1",db:null,dbName:null,dbVersion:null,store:null,storeName:null,keyPath:null,autoIncrement:null,indexes:null,features:null,onStoreReady:null,onError:null,_insertIdCount:0,openDB:function(){var e=this.idb.open(this.dbName,this.dbVersion),t=!1;e.onerror=function(e){var t=!1;"error"in e.target?t="VersionError"==e.target.error.name:"errorCode"in e.target&&(t=12==e.target.errorCode),this.onError(t?new Error("The version number provided is lower than the existing one."):e)}.bind(this),e.onsuccess=function(e){if(!t){if(this.db)return void this.onStoreReady();if(this.db=e.target.result,"string"==typeof this.db.version)return void this.onError(new Error("The IndexedDB implementation in this browser is outdated. Please upgrade your browser."));if(!this.db.objectStoreNames.contains(this.storeName))return void this.onError(new Error("Something is wrong with the IndexedDB implementation in this browser. Please upgrade your browser."));var n=this.db.transaction([this.storeName],this.consts.READ_ONLY);this.store=n.objectStore(this.storeName);var r=Array.prototype.slice.call(this.getIndexList());this.indexes.forEach(function(e){var n=e.name;if(!n)return t=!0,void this.onError(new Error("Cannot create index: No index name given."));if(this.normalizeIndexData(e),this.hasIndex(n)){var o=this.store.index(n),i=this.indexComplies(o,e);i||(t=!0,this.onError(new Error('Cannot modify index "'+n+'" for current version. Please bump version number to '+(this.dbVersion+1)+"."))),r.splice(r.indexOf(n),1)}else t=!0,this.onError(new Error('Cannot create new index "'+n+'" for current version. Please bump version number to '+(this.dbVersion+1)+"."))},this),r.length&&(t=!0,this.onError(new Error('Cannot delete index(es) "'+r.toString()+'" for current version. Please bump version number to '+(this.dbVersion+1)+"."))),t||this.onStoreReady()}}.bind(this),e.onupgradeneeded=function(e){if(this.db=e.target.result,this.db.objectStoreNames.contains(this.storeName))this.store=e.target.transaction.objectStore(this.storeName);else{var n={autoIncrement:this.autoIncrement};null!==this.keyPath&&(n.keyPath=this.keyPath),this.store=this.db.createObjectStore(this.storeName,n)}var r=Array.prototype.slice.call(this.getIndexList());this.indexes.forEach(function(e){var n=e.name;if(n||(t=!0,this.onError(new Error("Cannot create index: No index name given."))),this.normalizeIndexData(e),this.hasIndex(n)){var o=this.store.index(n),i=this.indexComplies(o,e);i||(this.store.deleteIndex(n),this.store.createIndex(n,e.keyPath,{unique:e.unique,multiEntry:e.multiEntry})),r.splice(r.indexOf(n),1)}else this.store.createIndex(n,e.keyPath,{unique:e.unique,multiEntry:e.multiEntry})},this),r.length&&r.forEach(function(e){this.store.deleteIndex(e)},this)}.bind(this)},deleteDatabase:function(){this.idb.deleteDatabase&&this.idb.deleteDatabase(this.dbName)},put:function(t,n,o,i){null!==this.keyPath&&(i=o,o=n,n=t),i||(i=e),o||(o=r);var u,a=!1,s=null,c=this.db.transaction([this.storeName],this.consts.READ_WRITE);return c.oncomplete=function(){var e=a?o:i;e(s)},c.onabort=i,c.onerror=i,null!==this.keyPath?(this._addIdPropertyIfNeeded(n),u=c.objectStore(this.storeName).put(n)):u=c.objectStore(this.storeName).put(n,t),u.onsuccess=function(e){a=!0,s=e.target.result},u.onerror=i,c},get:function(t,n,o){o||(o=e),n||(n=r);var i=!1,u=null,a=this.db.transaction([this.storeName],this.consts.READ_ONLY);a.oncomplete=function(){var e=i?n:o;e(u)},a.onabort=o,a.onerror=o;var s=a.objectStore(this.storeName).get(t);return s.onsuccess=function(e){i=!0,u=e.target.result},s.onerror=o,a},remove:function(t,n,o){o||(o=e),n||(n=r);var i=!1,u=null,a=this.db.transaction([this.storeName],this.consts.READ_WRITE);a.oncomplete=function(){var e=i?n:o;e(u)},a.onabort=o,a.onerror=o;var s=a.objectStore(this.storeName)["delete"](t);return s.onsuccess=function(e){i=!0,u=e.target.result},s.onerror=o,a},batch:function(t,n,o){o||(o=e),n||(n=r),"[object Array]"!=Object.prototype.toString.call(t)&&o(new Error("dataArray argument must be of type Array."));var i=this.db.transaction([this.storeName],this.consts.READ_WRITE);i.oncomplete=function(){var e=s?n:o;e(s)},i.onabort=o,i.onerror=o;var u=t.length,a=!1,s=!1,c=function(){u--,0!==u||a||(a=!0,s=!0)};return t.forEach(function(e){var t=e.type,n=e.key,r=e.value,u=function(e){i.abort(),a||(a=!0,o(e,t,n))};if("remove"==t){var s=i.objectStore(this.storeName)["delete"](n);s.onsuccess=c,s.onerror=u}else if("put"==t){var l;null!==this.keyPath?(this._addIdPropertyIfNeeded(r),l=i.objectStore(this.storeName).put(r)):l=i.objectStore(this.storeName).put(r,n),l.onsuccess=c,l.onerror=u}},this),i},putBatch:function(e,t,n){var r=e.map(function(e){return{type:"put",value:e}});return this.batch(r,t,n)},removeBatch:function(e,t,n){var r=e.map(function(e){return{type:"remove",key:e}});return this.batch(r,t,n)},getBatch:function(t,n,o,i){o||(o=e),n||(n=r),i||(i="sparse"),"[object Array]"!=Object.prototype.toString.call(t)&&o(new Error("keyArray argument must be of type Array."));var u=this.db.transaction([this.storeName],this.consts.READ_ONLY);u.oncomplete=function(){var e=l?n:o;e(f)},u.onabort=o,u.onerror=o;var a=[],s=t.length,c=!1,l=!1,f=null,h=function(e){e.target.result||"dense"==i?a.push(e.target.result):"sparse"==i&&a.length++,s--,0===s&&(c=!0,l=!0,f=a)};return t.forEach(function(e){var t=function(e){c=!0,f=e,o(e),u.abort()},n=u.objectStore(this.storeName).get(e);n.onsuccess=h,n.onerror=t},this),u},getAll:function(t,n){n||(n=e),t||(t=r);var o=this.db.transaction([this.storeName],this.consts.READ_ONLY),i=o.objectStore(this.storeName);return i.getAll?this._getAllNative(o,i,t,n):this._getAllCursor(o,i,t,n),o},_getAllNative:function(e,t,n,r){var o=!1,i=null;e.oncomplete=function(){var e=o?n:r;e(i)},e.onabort=r,e.onerror=r;var u=t.getAll();u.onsuccess=function(e){o=!0,i=e.target.result},u.onerror=r},_getAllCursor:function(e,t,n,r){var o=[],i=!1,u=null;e.oncomplete=function(){var e=i?n:r;e(u)},e.onabort=r,e.onerror=r;var a=t.openCursor();a.onsuccess=function(e){var t=e.target.result;t?(o.push(t.value),t["continue"]()):(i=!0,u=o)},a.onError=r},clear:function(t,n){n||(n=e),t||(t=r);var o=!1,i=null,u=this.db.transaction([this.storeName],this.consts.READ_WRITE);u.oncomplete=function(){var e=o?t:n;e(i)},u.onabort=n,u.onerror=n;var a=u.objectStore(this.storeName).clear();return a.onsuccess=function(e){o=!0,i=e.target.result},a.onerror=n,u},_addIdPropertyIfNeeded:function(e){this.features.hasAutoIncrement||"undefined"!=typeof e[this.keyPath]||(e[this.keyPath]=this._insertIdCount++ +Date.now())},getIndexList:function(){return this.store.indexNames},hasIndex:function(e){return this.store.indexNames.contains(e)},normalizeIndexData:function(e){e.keyPath=e.keyPath||e.name,e.unique=!!e.unique,e.multiEntry=!!e.multiEntry},indexComplies:function(e,t){var n=["keyPath","unique","multiEntry"].every(function(n){if("multiEntry"==n&&void 0===e[n]&&t[n]===!1)return!0;if("keyPath"==n&&"[object Array]"==Object.prototype.toString.call(t[n])){var r=t.keyPath,o=e.keyPath;if("string"==typeof o)return r.toString()==o;if("function"!=typeof o.contains&&"function"!=typeof o.indexOf)return!1;if(o.length!==r.length)return!1;for(var i=0,u=r.length;u>i;i++)if(!(o.contains&&o.contains(r[i])||o.indexOf(-1!==r[i])))return!1;return!0}return t[n]==e[n]});return n},iterate:function(t,n){n=i({index:null,order:"ASC",autoContinue:!0,filterDuplicates:!1,keyRange:null,writeAccess:!1,onEnd:null,onError:e},n||{});var r="desc"==n.order.toLowerCase()?"PREV":"NEXT";n.filterDuplicates&&(r+="_NO_DUPLICATE");var o=!1,u=this.db.transaction([this.storeName],this.consts[n.writeAccess?"READ_WRITE":"READ_ONLY"]),a=u.objectStore(this.storeName);n.index&&(a=a.index(n.index)),u.oncomplete=function(){return o?void(n.onEnd?n.onEnd():t(null)):void n.onError(null)},u.onabort=n.onError,u.onerror=n.onError;var s=a.openCursor(n.keyRange,this.consts[r]);return s.onerror=n.onError,s.onsuccess=function(e){var r=e.target.result;r?(t(r.value,r,u),n.autoContinue&&r["continue"]()):o=!0},u},query:function(e,t){var n=[];return t=t||{},t.onEnd=function(){e(n)},this.iterate(function(e){n.push(e)},t)},count:function(t,n){n=i({index:null,keyRange:null},n||{});var r=n.onError||e,o=!1,u=null,a=this.db.transaction([this.storeName],this.consts.READ_ONLY);a.oncomplete=function(){var e=o?t:r;e(u)},a.onabort=r,a.onerror=r;var s=a.objectStore(this.storeName);n.index&&(s=s.index(n.index));var c=s.count(n.keyRange);return c.onsuccess=function(e){o=!0,u=e.target.result},c.onError=r,a},makeKeyRange:function(e){var t,n="undefined"!=typeof e.lower,r="undefined"!=typeof e.upper,o="undefined"!=typeof e.only;switch(!0){case o:t=this.keyRange.only(e.only);break;case n&&r:t=this.keyRange.bound(e.lower,e.upper,e.excludeLower,e.excludeUpper);break;case n:t=this.keyRange.lowerBound(e.lower,e.excludeLower);break;case r:t=this.keyRange.upperBound(e.upper,e.excludeUpper);break;default:throw new Error('Cannot create KeyRange. Provide one or both of "lower" or "upper" value, or an "only" value.')}return t}};var r=function(){},o={},i=function(e,t){var n,r;for(n in t)r=t[n],r!==o[n]&&r!==e[n]&&(e[n]=r);return e};return n.version=n.prototype.version,n},this)},{}],4:[function(e,t){var n,r,o;t.exports=n=function(){function e(e){this.offlineLayer=e}return e.prototype.retrieveImage=function(e,t,n){var i;return i=this.offlineLayer._createURL(e.x,e.y,e.z),r(i,function(e){return t(o(e))},n)},e}(),r=function(e,t,n){var r;return r=new XMLHttpRequest,r.open("GET",e,!0),r.responseType="arraybuffer",r.onload=function(e){return 200===this.status?t(this.response):n("GET_STATUS_ERROR",e)},r.onerror=function(e){return n("NETWORK_ERROR",e)},r.send()},o=function(e){var t,n,r,o,i;for(t="",n=new Uint8Array(e),r=o=0,i=n.byteLength;i>=0?i>o:o>i;r=i>=0?++o:--o)t+=String.fromCharCode(n[r]);return"data:image/png;base64,"+btoa(t)}},{}],5:[function(e,t){var n,r,o,i;i=e("async"),r=e("./IndexedDBDataStorage"),o=e("./WebSQLDataStorage"),t.exports=n=function(){function e(e,t){if(null==t)throw new Error("the image store needs an imageRetriever");if(null==e)throw new Error("the image store needs an eventEmitter");this._eventEmitter=e,this._nbTilesLeftToSave=0,this._nbImagesCurrentlyBeingRetrieved=0,this._imageRetriever=t,this._myQueue=null,this._beingCanceled=!1,this._running=!1}return e.prototype.createDB=function(e,t,n,i){var u;if(u=i,null==t)throw new Error("This async function needs a callback");return this.storage=u?new o(e,t,n):new r(e,t,n)},e.prototype.cancel=function(){return this._running?this._beingCanceled?!0:(this._beingCanceled=!0,null!=this._myQueue?(this._myQueue.kill(),0===this._nbImagesCurrentlyBeingRetrieved&&this._finish(),!0):!1):!1},e.prototype.isBusy=function(){return this._running},e.prototype.get=function(e,t,n){if(null==t||null==n)throw new Error("This async function needs callbacks");return this.storage.get(e,t,n)},e.prototype.clear=function(e,t){if(null==e||null==t)throw new Error("This async function needs callbacks");return this.storage.clear(e,t)},e.prototype._finish=function(e,t){return this._running=!1,this._beingCanceled=!1,this._eventEmitter.fire("tilecachingprogressdone",null),this._myQueue=null,this._nbImagesCurrentlyBeingRetrieved=0,null!=e?t(e):this._onSaveImagesSuccess()},e.prototype.saveImages=function(e,t,n,r){if(this._running=!0,null!=this._myQueue)throw new Error("Not allowed to save images while saving is already in progress");if(null==t||null==n||null==r)throw new Error("This async function needs callbacks");return this._onSaveImagesSuccess=n,this._getImagesNotInDB(e,function(e){return function(n){var o,u,a,s;if(!e._beingCanceled&&null!=n&&n.length>0){for(o=8,e._myQueue=i.queue(function(t,n){return e._saveTile(t,n)},o),e._myQueue.drain=function(t){return e._finish(t,r)},a=0,s=n.length;s>a;a++)u=n[a],e._myQueue.push(u);return t()}return t(),e._finish()}}(this),function(e){return r(e)})},e.prototype._getImagesNotInDB=function(e,t,n){var r,o;o=[];for(r in e)o.push(r);return this.storage.getDenseBatch(o,function(n){return function(r){var i,u,a,s,c,l;for(i=0,s=[],n._eventEmitter.fire("tilecachingstart",null),n._nbTilesLeftToSave=0,u=function(t){var r,u;return t||(r=o[i],u=e[r],n._nbTilesLeftToSave++,s.push({key:r,tileInfo:u})),i++},c=0,l=r.length;l>c;c++)a=r[c],u(a);return n._updateTotalNbImagesLeftToSave(n._nbTilesLeftToSave),t(s)}}(this),function(e){return n(e)})},e.prototype._saveTile=function(e,t){var n,r;return r=function(n){return function(r){return n.storage.put(e.key,{image:r},function(){return n._decrementNbTilesLeftToSave(),t()},function(e){return n._decrementNbTilesLeftToSave(),t(e)})}}(this),n=function(n){return function(r,o){return n._decrementNbTilesLeftToSave(),n._eventEmitter._reportError(r,{data:o,tileInfo:e.tileInfo}),t(r)}}(this),this._nbImagesCurrentlyBeingRetrieved++,this._imageRetriever.retrieveImage(e.tileInfo,r,n)},e.prototype._updateTotalNbImagesLeftToSave=function(e){return this._nbTilesLeftToSave=e,this._eventEmitter.fire("tilecachingprogressstart",{nbTiles:this._nbTilesLeftToSave})},e.prototype._decrementNbTilesLeftToSave=function(){return this._nbTilesLeftToSave--,this._beingCanceled||this._eventEmitter.fire("tilecachingprogress",{nbTiles:this._nbTilesLeftToSave}),this._nbImagesCurrentlyBeingRetrieved--,this._beingCanceled&&0===this._nbImagesCurrentlyBeingRetrieved?this._finish():void 0},e}()},{"./IndexedDBDataStorage":6,"./WebSQLDataStorage":9,async:1}],6:[function(e,t){var n,r;n=e("idb-wrapper"),t.exports=r=function(){function e(e,t,r){this._idbStore=new n({dbVersion:1,storeName:e,keyPath:null,autoIncrement:!1},t,r)}return e.prototype.get=function(e,t,n){return this._idbStore.get(e,t,n)},e.prototype.clear=function(e,t){return this._idbStore.clear(e,t)},e.prototype.put=function(e,t,n,r){return this._idbStore.put(e,t,n,r)},e.prototype.getDenseBatch=function(e,t,n){return this._idbStore.getBatch(e,t,n,"dense")},e}()},{"idb-wrapper":3}],7:[function(e,t){var n,r,o,i={}.hasOwnProperty,u=function(e,t){function n(){this.constructor=e}for(var r in t)i.call(t,r)&&(e[r]=t[r]);return n.prototype=t.prototype,e.prototype=new n,e.__super__=t.prototype,e};r=e("./ImageStore"),n=e("./ImageRetriever"),t.exports=o=function(e){function t(){return t.__super__.constructor.apply(this,arguments)}return u(t,e),t.prototype.initialize=function(e,t){var o,i,u,a,s;if(L.TileLayer.prototype.initialize.call(this,e,t),this._onReady=t.onReady,this._onError=t.onError,o=t.dbOption,a=t.storeName||"OfflineLeafletTileImages",this._tileImagesStore=null,this._minZoomLevel=12,null!=t.minZoomLevel&&(this._minZoomLevel=parseInt(t.minZoomLevel)),null==o||"None"===o)return setTimeout(function(e){return function(){return e._onReady()}}(this),0);try{return"WebSQL"===o?s=!0:"IndexedDB"===o?s=!1:this._onError("COULD_NOT_CREATE_DB","Invalid dbOption parameter: "+o),u=new n(this),this._tileImagesStore=new r(this,u),this._tileImagesStore.createDB(a,function(e){return function(){return e._onReady()}}(this),function(e){return function(t){return e._tileImagesStore=null,e._reportError("COULD_NOT_CREATE_DB",t),setTimeout(function(){return e._onReady()},0)}}(this),s)}catch(c){return i=c,this._tileImagesStore=null,this._reportError("COULD_NOT_CREATE_DB",i),setTimeout(function(e){return function(){return e._onReady()}}(this),0)}},t.prototype._setUpTile=function(e,t,n){return e.src=n,this.fire("tileloadstart",{tile:e,url:e.src})},t.prototype._reportError=function(e,t){return this._onError?this._onError(e,t):void 0},t.prototype._loadTile=function(e,t){var n,r,o;return this._tileImagesStore?(e._layer=this,e.onerror=this._tileOnError,this._adjustTilePoint(t),e.onload=this._tileOnLoad,o=function(r){return function(o){return o?r._setUpTile(e,n,o.image):r._setUpTile(e,n,r.getTileUrl(t))}}(this),r=function(r){return function(){return r._setUpTile(e,n,r.getTileUrl(t)),r._reportError("DB_GET",n)}}(this),n=this._createTileKey(t.x,t.y,t.z),this._tileImagesStore.get(n,o,r)):L.TileLayer.prototype._loadTile.call(this,e,t)},t.prototype.useDB=function(){return null!==this._tileImagesStore},t.prototype.cancel=function(){return null!=this._tileImagesStore?this._tileImagesStore.cancel():!1},t.prototype.clearTiles=function(e,t){return this.useDB()?this.isBusy()?(this._reportError("SYSTEM_BUSY","System is busy."),void t("System is busy.")):this._tileImagesStore.clear(e,function(e){return function(n){return e._reportError("COULD_NOT_CLEAR_DB",n),t(n)}}(this)):(this._reportError("NO_DB","No DB available"),void t("No DB available"))},t.prototype.calculateNbTiles=function(e){var t,n,r;if(this._map.getZoom()=T?S>=_:_>=S;o=S>=T?++_:--_)for(r=b=I=f.min.x,w=f.max.x;w>=I?w>=b:b>=w;r=w>=I?++b:--b)y.push(new L.Point(r,o));for(p=L.bounds(n.min.divideBy(m),n.max.divideBy(m)),c=p.min.y,a=p.max.y,s=p.min.x,u=p.max.x,t=y.length,r=E=0;t>=0?t>E:E>t;r=t>=0?++E:--E)l=y[r],v=l.x,g=l.y,this._getZoomedInTiles(v,g,h,e,d,c,a,s,u),this._getZoomedOutTiles(v,g,h,0,d,c,a,s,u);return d},t.prototype.saveTiles=function(e,t,n,r){var o;return this._tileImagesStore?this.isBusy()?(this._reportError("SYSTEM_BUSY","system is busy."),void r("system is busy.")):this._map.getZoom()n?(i*=2,u*=2,a*=2,s*=2,this._getZoomedInTiles(2*e,2*t,n+1,r,o,i,u,a,s),this._getZoomedInTiles(2*e+1,2*t,n+1,r,o,i,u,a,s),this._getZoomedInTiles(2*e,2*t+1,n+1,r,o,i,u,a,s),this._getZoomedInTiles(2*e+1,2*t+1,n+1,r,o,i,u,a,s)):void 0 -},t.prototype._getZoomedOutTiles=function(e,t,n,r,o,i,u,a,s){return this._getTileImage(e,t,n,o,i,u,a,s,!1),n>r?(i/=2,u/=2,a/=2,s/=2,this._getZoomedOutTiles(Math.floor(e/2),Math.floor(t/2),n-1,r,o,i,u,a,s)):void 0},t.prototype._getTileImage=function(e,t,n,r,o,i,u,a){var s;if(!(eMath.floor(a)||tMath.floor(i)))return s=this._createTileKey(e,t,n),r[s]?void 0:r[s]={key:s,x:e,y:t,z:n}},t.prototype._createNormalizedTilePoint=function(e,t,n){var r;for(r=Math.pow(2,n);e>r;)e-=r;for(;0>e;)e+=r;for(;t>r;)t-=r;for(;0>t;)t+=r;return{x:e,y:t,z:n}},t.prototype._createURL=function(e,t,n){var r;return r=this._createNormalizedTilePoint(e,t,n),this.getTileUrl(r)},t.prototype._createTileKey=function(e,t,n){var r;return r=this._createNormalizedTilePoint(e,t,n),r.x+", "+r.y+", "+r.z},t}(L.TileLayer)},{"./ImageRetriever":4,"./ImageStore":5}],8:[function(e,t){var n,r={}.hasOwnProperty,o=function(e,t){function n(){this.constructor=e}for(var o in t)r.call(t,o)&&(e[o]=t[o]);return n.prototype=t.prototype,e.prototype=new n,e.__super__=t.prototype,e};t.exports=n=function(e){function t(){return t.__super__.constructor.apply(this,arguments)}return o(t,e),t.prototype.onAdd=function(){var e;return e=L.DomUtil.create("div","offlinemap-controls",this._container),e.setAttribute("id","offlinemap-controls"),this._counter=L.DomUtil.create("div","offlinemap-controls-counter",e),this._counter.setAttribute("id","offlinemap-controls-counter"),this._counter.innerHTML="Ready",this._cancelButton=L.DomUtil.create("input","offlinemap-controls-cancel-button",e),this._cancelButton.setAttribute("type","button"),this._cancelButton.setAttribute("id","cancelBtn"),this._cancelButton.setAttribute("value","Cancel"),this._cancelButton.setAttribute("disabled",!0),L.DomEvent.addListener(this._cancelButton,"click",this.onCancelClick,this),L.DomEvent.disableClickPropagation(this._cancelButton),e},t.prototype.onProgressStart=function(){return this._evaluating=!0,this._counter.innerHTML="...",this._cancelButton.removeAttribute("disabled")},t.prototype.onProgressDone=function(){return this._counter.innerHTML="Ready",this._cancelButton.removeAttribute("disabled")},t.prototype.updateTotalNbTilesLeftToSave=function(e){return this._evaluating=!1,this._nbTilesToSave=e.nbTiles,this.updateNbTilesLeftToSave(e)},t.prototype.updateNbTilesLeftToSave=function(e){return this._evaluating?void 0:this._counter.innerHTML=0===this._nbTilesToSave?"100%":Math.floor((this._nbTilesToSave-e.nbTiles)/this._nbTilesToSave*100)+"%"},t.prototype.onCancelClick=function(){return this._offlineLayer.cancel()?(this._counter.innerHTML="Canceling...",this._cancelButton.setAttribute("disabled",!0)):void 0},t.prototype.setOfflineLayer=function(e){return this._offlineLayer=e,this._offlineLayer.on("tilecachingstart",this.onProgressStart,this),this._offlineLayer.on("tilecachingprogressstart",this.updateTotalNbTilesLeftToSave,this),this._offlineLayer.on("tilecachingprogress",this.updateNbTilesLeftToSave,this),this._offlineLayer.on("tilecachingprogressdone",this.onProgressDone,this)},t}(L.Control)},{}],9:[function(e,t){var n;t.exports=n=function(){function e(e,t,n){this._storeName=e,this._webSQLDB=openDatabase("OfflineTileImages","1.0","Store tile images for OfflineLeaftMap",52428800),this._webSQLDB.transaction(function(e){return function(t){return t.executeSql("CREATE TABLE IF NOT EXISTS "+e._storeName+" (key unique, image)")}}(this),n,t)}return e.prototype.get=function(e,t,n){return this._webSQLDB.transaction(function(r){return function(o){var i;return i=function(e,r){var o;return o=r.rows.length,0===o?t(void 0):1===o?t(r.rows.item(0)):n("There should be no more than one entry")},o.executeSql("SELECT * FROM "+r._storeName+" WHERE key='"+e+"'",[],i,n)}}(this))},e.prototype.clear=function(e,t){return this._webSQLDB.transaction(function(n){return function(r){return r.executeSql("DELETE FROM "+n._storeName,[],e,t)}}(this))},e.prototype.put=function(e,t,n,r){return this._webSQLDB.transaction(function(o){return function(i){return i.executeSql("INSERT OR REPLACE INTO "+o._storeName+" VALUES (?, ?)",[e,t.image],n,r)}}(this))},e.prototype.getDenseBatch=function(e,t,n){return 0===e.length&&t([]),this._webSQLDB.transaction(function(r){return function(o){var i,u,a,s,c,l,f;for(s=[],c=[],i=l=0,f=e.length;f>=0?f>l:l>f;i=f>=0?++l:--l)c.push("'"+e[i]+"'"),s.push(void 0);return u=c.join(","),a=function(n,r){var o,u,a,c;for(i=a=0,c=r.rows.length;c>=0?c>a:a>c;i=c>=0?++a:--a)u=r.rows.item(i),o=e.indexOf(u.key),o>=0&&(s[o]=u);return t(s)},o.executeSql("SELECT * FROM "+r._storeName+" WHERE key IN ("+u+")",[],a,n)}}(this))},e}()},{}],10:[function(e){window.OfflineLayer=e("./OfflineLayer"),window.OfflineProgressControl=e("./OfflineProgressControl")},{"./OfflineLayer":7,"./OfflineProgressControl":8}]},{},[10]); \ No newline at end of file +!function e(t,n,r){function o(s,a){if(!n[s]){if(!t[s]){var u="function"==typeof require&&require;if(!a&&u)return u(s,!0);if(i)return i(s,!0);throw new Error("Cannot find module '"+s+"'")}var c=n[s]={exports:{}};t[s][0].call(c.exports,function(e){var n=t[s][1][e];return o(n?n:e)},c,c.exports,e,t,n,r)}return n[s].exports}for(var i="function"==typeof require&&require,s=0;s=e.length&&r())}if(r=r||function(){},!e.length)return r();var i=0;u(e,function(e){t(e,n(o))})},i.forEach=i.each,i.eachSeries=function(e,t,n){if(n=n||function(){},!e.length)return n();var r=0,o=function(){t(e[r],function(t){t?(n(t),n=function(){}):(r+=1,r>=e.length?n():o())})};o()},i.forEachSeries=i.eachSeries,i.eachLimit=function(e,t,n,r){var o=h(t);o.apply(null,[e,n,r])},i.forEachLimit=i.eachLimit;var h=function(e){return function(t,n,r){if(r=r||function(){},!t.length||0>=e)return r();var o=0,i=0,s=0;!function a(){if(o>=t.length)return r();for(;e>s&&i=t.length?r():a())})}()}},p=function(e){return function(){var t=Array.prototype.slice.call(arguments);return e.apply(null,[i.each].concat(t))}},d=function(e,t){return function(){var n=Array.prototype.slice.call(arguments);return t.apply(null,[h(e)].concat(n))}},m=function(e){return function(){var t=Array.prototype.slice.call(arguments);return e.apply(null,[i.eachSeries].concat(t))}},y=function(e,t,n,r){if(t=c(t,function(e,t){return{index:t,value:e}}),r){var o=[];e(t,function(e,t){n(e.value,function(n,r){o[e.index]=r,t(n)})},function(e){r(e,o)})}else e(t,function(e,t){n(e.value,function(e){t(e)})})};i.map=p(y),i.mapSeries=m(y),i.mapLimit=function(e,t,n,r){return g(t)(e,n,r)};var g=function(e){return d(e,y)};i.reduce=function(e,t,n,r){i.eachSeries(e,function(e,r){n(t,e,function(e,n){t=n,r(e)})},function(e){r(e,t)})},i.inject=i.reduce,i.foldl=i.reduce,i.reduceRight=function(e,t,n,r){var o=c(e,function(e){return e}).reverse();i.reduce(o,t,n,r)},i.foldr=i.reduceRight;var v=function(e,t,n,r){var o=[];t=c(t,function(e,t){return{index:t,value:e}}),e(t,function(e,t){n(e.value,function(n){n&&o.push(e),t()})},function(){r(c(o.sort(function(e,t){return e.index-t.index}),function(e){return e.value}))})};i.filter=p(v),i.filterSeries=m(v),i.select=i.filter,i.selectSeries=i.filterSeries;var _=function(e,t,n,r){var o=[];t=c(t,function(e,t){return{index:t,value:e}}),e(t,function(e,t){n(e.value,function(n){n||o.push(e),t()})},function(){r(c(o.sort(function(e,t){return e.index-t.index}),function(e){return e.value}))})};i.reject=p(_),i.rejectSeries=m(_);var b=function(e,t,n,r){e(t,function(e,t){n(e,function(n){n?(r(e),r=function(){}):t()})},function(){r()})};i.detect=p(b),i.detectSeries=m(b),i.some=function(e,t,n){i.each(e,function(e,r){t(e,function(e){e&&(n(!0),n=function(){}),r()})},function(){n(!1)})},i.any=i.some,i.every=function(e,t,n){i.each(e,function(e,r){t(e,function(e){e||(n(!1),n=function(){}),r()})},function(){n(!0)})},i.all=i.every,i.sortBy=function(e,t,n){i.map(e,function(e,n){t(e,function(t,r){t?n(t):n(null,{value:e,criteria:r})})},function(e,t){if(e)return n(e);var r=function(e,t){var n=e.criteria,r=t.criteria;return r>n?-1:n>r?1:0};n(null,c(t.sort(r),function(e){return e.value}))})},i.auto=function(e,t){t=t||function(){};var n=f(e),r=n.length;if(!r)return t();var o={},s=[],c=function(e){s.unshift(e)},h=function(e){for(var t=0;tr;){var i=r+(o-r+1>>>1);n(t,e[i])>=0?r=i:o=i-1}return r}function o(e,t,o,s){return e.started||(e.started=!0),a(t)||(t=[t]),0==t.length?i.setImmediate(function(){e.drain&&e.drain()}):(u(t,function(t){var a={data:t,priority:o,callback:"function"==typeof s?s:null};e.tasks.splice(r(e.tasks,a,n)+1,0,a),e.saturated&&e.tasks.length===e.concurrency&&e.saturated(),i.setImmediate(e.process)}),void 0)}var s=i.queue(e,t);return s.push=function(e,t,n){o(s,e,t,n)},delete s.unshift,s},i.cargo=function(e,t){var n=!1,r=[],o={tasks:r,payload:t,saturated:null,empty:null,drain:null,drained:!0,push:function(e,n){a(e)||(e=[e]),u(e,function(e){r.push({data:e,callback:"function"==typeof n?n:null}),o.drained=!1,o.saturated&&r.length===t&&o.saturated()}),i.setImmediate(o.process)},process:function s(){if(!n){if(0===r.length)return o.drain&&!o.drained&&o.drain(),o.drained=!0,void 0;var i="number"==typeof t?r.splice(0,t):r.splice(0,r.length),a=c(i,function(e){return e.data});o.empty&&o.empty(),n=!0,e(a,function(){n=!1;var e=arguments;u(i,function(t){t.callback&&t.callback.apply(null,e)}),s()})}},length:function(){return r.length},running:function(){return n}};return o};var S=function(e){return function(t){var n=Array.prototype.slice.call(arguments,1);t.apply(null,n.concat([function(t){var n=Array.prototype.slice.call(arguments,1);"undefined"!=typeof console&&(t?console.error&&console.error(t):console[e]&&u(n,function(t){console[e](t)}))}]))}};i.log=S("log"),i.dir=S("dir"),i.memoize=function(e,t){var n={},r={};t=t||function(e){return e};var o=function(){var o=Array.prototype.slice.call(arguments),s=o.pop(),a=t.apply(null,o);a in n?i.nextTick(function(){s.apply(null,n[a])}):a in r?r[a].push(s):(r[a]=[s],e.apply(null,o.concat([function(){n[a]=arguments;var e=r[a];delete r[a];for(var t=0,o=e.length;o>t;t++)e[t].apply(null,arguments)}])))};return o.memo=n,o.unmemoized=e,o},i.unmemoize=function(e){return function(){return(e.unmemoized||e).apply(null,arguments)}},i.times=function(e,t,n){for(var r=[],o=0;e>o;o++)r.push(o);return i.map(r,t,n)},i.timesSeries=function(e,t,n){for(var r=[],o=0;e>o;o++)r.push(o);return i.mapSeries(r,t,n)},i.seq=function(){var e=arguments;return function(){var t=this,n=Array.prototype.slice.call(arguments),r=n.pop();i.reduce(e,n,function(e,n,r){n.apply(t,e.concat([function(){var e=arguments[0],t=Array.prototype.slice.call(arguments,1);r(e,t)}]))},function(e,n){r.apply(t,[e].concat(n))})}},i.compose=function(){return i.seq.apply(null,Array.prototype.reverse.call(arguments))};var L=function(e,t){var n=function(){var n=this,r=Array.prototype.slice.call(arguments),o=r.pop();return e(t,function(e,t){e.apply(n,r.concat([t]))},o)};if(arguments.length>2){var r=Array.prototype.slice.call(arguments,2);return n.apply(this,r)}return n};i.applyEach=p(L),i.applyEachSeries=m(L),i.forever=function(e,t){function n(r){if(r){if(t)return t(r);throw r}e(n)}n()},"undefined"!=typeof t&&t.exports?t.exports=i:"undefined"!=typeof define&&define.amd?define([],function(){return i}):r.async=i}()}).call(this,e("+xKvab"))},{"+xKvab":2}],2:[function(e,t){function n(){}var r=t.exports={};r.nextTick=function(){var e="undefined"!=typeof window&&window.setImmediate,t="undefined"!=typeof window&&window.postMessage&&window.addEventListener;if(e)return function(e){return window.setImmediate(e)};if(t){var n=[];return window.addEventListener("message",function(e){var t=e.source;if((t===window||null===t)&&"process-tick"===e.data&&(e.stopPropagation(),n.length>0)){var r=n.shift();r()}},!0),function(e){n.push(e),window.postMessage("process-tick","*")}}return function(e){setTimeout(e,0)}}(),r.title="browser",r.browser=!0,r.env={},r.argv=[],r.on=n,r.addListener=n,r.once=n,r.off=n,r.removeListener=n,r.removeAllListeners=n,r.emit=n,r.binding=function(){throw new Error("process.binding is not supported")},r.cwd=function(){return"/"},r.chdir=function(){throw new Error("process.chdir is not supported")}},{}],3:[function(e,t){!function(e,n,r){"function"==typeof define?define(n):"undefined"!=typeof t&&t.exports?t.exports=n():r[e]=n()}("IDBStore",function(){"use strict";var e=function(e){throw e},t={storeName:"Store",storePrefix:"IDBWrapper-",dbVersion:1,keyPath:"id",autoIncrement:!0,onStoreReady:function(){},onError:e,indexes:[]},n=function(e,n){"undefined"==typeof n&&"function"==typeof e&&(n=e),"[object Object]"!=Object.prototype.toString.call(e)&&(e={});for(var r in t)this[r]="undefined"!=typeof e[r]?e[r]:t[r];this.dbName=this.storePrefix+this.storeName,this.dbVersion=parseInt(this.dbVersion,10)||1,n&&(this.onStoreReady=n);var o="object"==typeof window?window:self;this.idb=o.indexedDB||o.webkitIndexedDB||o.mozIndexedDB,this.keyRange=o.IDBKeyRange||o.webkitIDBKeyRange||o.mozIDBKeyRange,this.features={hasAutoIncrement:!o.mozIndexedDB},this.consts={READ_ONLY:"readonly",READ_WRITE:"readwrite",VERSION_CHANGE:"versionchange",NEXT:"next",NEXT_NO_DUPLICATE:"nextunique",PREV:"prev",PREV_NO_DUPLICATE:"prevunique"},this.openDB()};n.prototype={constructor:n,version:"1.4.1",db:null,dbName:null,dbVersion:null,store:null,storeName:null,keyPath:null,autoIncrement:null,indexes:null,features:null,onStoreReady:null,onError:null,_insertIdCount:0,openDB:function(){var e=this.idb.open(this.dbName,this.dbVersion),t=!1;e.onerror=function(e){var t=!1;"error"in e.target?t="VersionError"==e.target.error.name:"errorCode"in e.target&&(t=12==e.target.errorCode),t?this.onError(new Error("The version number provided is lower than the existing one.")):this.onError(e)}.bind(this),e.onsuccess=function(e){if(!t){if(this.db)return this.onStoreReady(),void 0;if(this.db=e.target.result,"string"==typeof this.db.version)return this.onError(new Error("The IndexedDB implementation in this browser is outdated. Please upgrade your browser.")),void 0;if(!this.db.objectStoreNames.contains(this.storeName))return this.onError(new Error("Something is wrong with the IndexedDB implementation in this browser. Please upgrade your browser.")),void 0;var n=this.db.transaction([this.storeName],this.consts.READ_ONLY);this.store=n.objectStore(this.storeName);var r=Array.prototype.slice.call(this.getIndexList());this.indexes.forEach(function(e){var n=e.name;if(!n)return t=!0,this.onError(new Error("Cannot create index: No index name given.")),void 0;if(this.normalizeIndexData(e),this.hasIndex(n)){var o=this.store.index(n),i=this.indexComplies(o,e);i||(t=!0,this.onError(new Error('Cannot modify index "'+n+'" for current version. Please bump version number to '+(this.dbVersion+1)+"."))),r.splice(r.indexOf(n),1)}else t=!0,this.onError(new Error('Cannot create new index "'+n+'" for current version. Please bump version number to '+(this.dbVersion+1)+"."))},this),r.length&&(t=!0,this.onError(new Error('Cannot delete index(es) "'+r.toString()+'" for current version. Please bump version number to '+(this.dbVersion+1)+"."))),t||this.onStoreReady()}}.bind(this),e.onupgradeneeded=function(e){if(this.db=e.target.result,this.db.objectStoreNames.contains(this.storeName))this.store=e.target.transaction.objectStore(this.storeName);else{var n={autoIncrement:this.autoIncrement};null!==this.keyPath&&(n.keyPath=this.keyPath),this.store=this.db.createObjectStore(this.storeName,n)}var r=Array.prototype.slice.call(this.getIndexList());this.indexes.forEach(function(e){var n=e.name;if(n||(t=!0,this.onError(new Error("Cannot create index: No index name given."))),this.normalizeIndexData(e),this.hasIndex(n)){var o=this.store.index(n),i=this.indexComplies(o,e);i||(this.store.deleteIndex(n),this.store.createIndex(n,e.keyPath,{unique:e.unique,multiEntry:e.multiEntry})),r.splice(r.indexOf(n),1)}else this.store.createIndex(n,e.keyPath,{unique:e.unique,multiEntry:e.multiEntry})},this),r.length&&r.forEach(function(e){this.store.deleteIndex(e)},this)}.bind(this)},deleteDatabase:function(){this.idb.deleteDatabase&&this.idb.deleteDatabase(this.dbName)},put:function(t,n,o,i){null!==this.keyPath&&(i=o,o=n,n=t),i||(i=e),o||(o=r);var s,a=!1,u=null,c=this.db.transaction([this.storeName],this.consts.READ_WRITE);return c.oncomplete=function(){var e=a?o:i;e(u)},c.onabort=i,c.onerror=i,null!==this.keyPath?(this._addIdPropertyIfNeeded(n),s=c.objectStore(this.storeName).put(n)):s=c.objectStore(this.storeName).put(n,t),s.onsuccess=function(e){a=!0,u=e.target.result},s.onerror=i,c},get:function(t,n,o){o||(o=e),n||(n=r);var i=!1,s=null,a=this.db.transaction([this.storeName],this.consts.READ_ONLY);a.oncomplete=function(){var e=i?n:o;e(s)},a.onabort=o,a.onerror=o;var u=a.objectStore(this.storeName).get(t);return u.onsuccess=function(e){i=!0,s=e.target.result},u.onerror=o,a},remove:function(t,n,o){o||(o=e),n||(n=r);var i=!1,s=null,a=this.db.transaction([this.storeName],this.consts.READ_WRITE);a.oncomplete=function(){var e=i?n:o;e(s)},a.onabort=o,a.onerror=o;var u=a.objectStore(this.storeName)["delete"](t);return u.onsuccess=function(e){i=!0,s=e.target.result},u.onerror=o,a},batch:function(t,n,o){o||(o=e),n||(n=r),"[object Array]"!=Object.prototype.toString.call(t)&&o(new Error("dataArray argument must be of type Array."));var i=this.db.transaction([this.storeName],this.consts.READ_WRITE);i.oncomplete=function(){var e=u?n:o;e(u)},i.onabort=o,i.onerror=o;var s=t.length,a=!1,u=!1,c=function(){s--,0!==s||a||(a=!0,u=!0)};return t.forEach(function(e){var t=e.type,n=e.key,r=e.value,s=function(e){i.abort(),a||(a=!0,o(e,t,n))};if("remove"==t){var u=i.objectStore(this.storeName)["delete"](n);u.onsuccess=c,u.onerror=s}else if("put"==t){var l;null!==this.keyPath?(this._addIdPropertyIfNeeded(r),l=i.objectStore(this.storeName).put(r)):l=i.objectStore(this.storeName).put(r,n),l.onsuccess=c,l.onerror=s}},this),i},putBatch:function(e,t,n){var r=e.map(function(e){return{type:"put",value:e}});return this.batch(r,t,n)},removeBatch:function(e,t,n){var r=e.map(function(e){return{type:"remove",key:e}});return this.batch(r,t,n)},getBatch:function(t,n,o,i){o||(o=e),n||(n=r),i||(i="sparse"),"[object Array]"!=Object.prototype.toString.call(t)&&o(new Error("keyArray argument must be of type Array."));var s=this.db.transaction([this.storeName],this.consts.READ_ONLY);s.oncomplete=function(){var e=l?n:o;e(f)},s.onabort=o,s.onerror=o;var a=[],u=t.length,c=!1,l=!1,f=null,h=function(e){e.target.result||"dense"==i?a.push(e.target.result):"sparse"==i&&a.length++,u--,0===u&&(c=!0,l=!0,f=a)};return t.forEach(function(e){var t=function(e){c=!0,f=e,o(e),s.abort()},n=s.objectStore(this.storeName).get(e);n.onsuccess=h,n.onerror=t},this),s},getAll:function(t,n){n||(n=e),t||(t=r);var o=this.db.transaction([this.storeName],this.consts.READ_ONLY),i=o.objectStore(this.storeName);return i.getAll?this._getAllNative(o,i,t,n):this._getAllCursor(o,i,t,n),o},_getAllNative:function(e,t,n,r){var o=!1,i=null;e.oncomplete=function(){var e=o?n:r;e(i)},e.onabort=r,e.onerror=r;var s=t.getAll();s.onsuccess=function(e){o=!0,i=e.target.result},s.onerror=r},_getAllCursor:function(e,t,n,r){var o=[],i=!1,s=null;e.oncomplete=function(){var e=i?n:r;e(s)},e.onabort=r,e.onerror=r;var a=t.openCursor();a.onsuccess=function(e){var t=e.target.result;t?(o.push(t.value),t["continue"]()):(i=!0,s=o)},a.onError=r},clear:function(t,n){n||(n=e),t||(t=r);var o=!1,i=null,s=this.db.transaction([this.storeName],this.consts.READ_WRITE);s.oncomplete=function(){var e=o?t:n;e(i)},s.onabort=n,s.onerror=n;var a=s.objectStore(this.storeName).clear();return a.onsuccess=function(e){o=!0,i=e.target.result},a.onerror=n,s},_addIdPropertyIfNeeded:function(e){this.features.hasAutoIncrement||"undefined"!=typeof e[this.keyPath]||(e[this.keyPath]=this._insertIdCount++ +Date.now())},getIndexList:function(){return this.store.indexNames},hasIndex:function(e){return this.store.indexNames.contains(e)},normalizeIndexData:function(e){e.keyPath=e.keyPath||e.name,e.unique=!!e.unique,e.multiEntry=!!e.multiEntry},indexComplies:function(e,t){var n=["keyPath","unique","multiEntry"].every(function(n){if("multiEntry"==n&&void 0===e[n]&&t[n]===!1)return!0;if("keyPath"==n&&"[object Array]"==Object.prototype.toString.call(t[n])){var r=t.keyPath,o=e.keyPath;if("string"==typeof o)return r.toString()==o;if("function"!=typeof o.contains&&"function"!=typeof o.indexOf)return!1;if(o.length!==r.length)return!1;for(var i=0,s=r.length;s>i;i++)if(!(o.contains&&o.contains(r[i])||o.indexOf(-1!==r[i])))return!1;return!0}return t[n]==e[n]});return n},iterate:function(t,n){n=i({index:null,order:"ASC",autoContinue:!0,filterDuplicates:!1,keyRange:null,writeAccess:!1,onEnd:null,onError:e},n||{});var r="desc"==n.order.toLowerCase()?"PREV":"NEXT";n.filterDuplicates&&(r+="_NO_DUPLICATE");var o=!1,s=this.db.transaction([this.storeName],this.consts[n.writeAccess?"READ_WRITE":"READ_ONLY"]),a=s.objectStore(this.storeName);n.index&&(a=a.index(n.index)),s.oncomplete=function(){return o?(n.onEnd?n.onEnd():t(null),void 0):(n.onError(null),void 0)},s.onabort=n.onError,s.onerror=n.onError;var u=a.openCursor(n.keyRange,this.consts[r]);return u.onerror=n.onError,u.onsuccess=function(e){var r=e.target.result;r?(t(r.value,r,s),n.autoContinue&&r["continue"]()):o=!0},s},query:function(e,t){var n=[];return t=t||{},t.onEnd=function(){e(n)},this.iterate(function(e){n.push(e)},t)},count:function(t,n){n=i({index:null,keyRange:null},n||{});var r=n.onError||e,o=!1,s=null,a=this.db.transaction([this.storeName],this.consts.READ_ONLY);a.oncomplete=function(){var e=o?t:r;e(s)},a.onabort=r,a.onerror=r;var u=a.objectStore(this.storeName);n.index&&(u=u.index(n.index));var c=u.count(n.keyRange);return c.onsuccess=function(e){o=!0,s=e.target.result},c.onError=r,a},makeKeyRange:function(e){var t,n="undefined"!=typeof e.lower,r="undefined"!=typeof e.upper,o="undefined"!=typeof e.only;switch(!0){case o:t=this.keyRange.only(e.only);break;case n&&r:t=this.keyRange.bound(e.lower,e.upper,e.excludeLower,e.excludeUpper);break;case n:t=this.keyRange.lowerBound(e.lower,e.excludeLower);break;case r:t=this.keyRange.upperBound(e.upper,e.excludeUpper);break;default:throw new Error('Cannot create KeyRange. Provide one or both of "lower" or "upper" value, or an "only" value.')}return t}};var r=function(){},o={},i=function(e,t){var n,r;for(n in t)r=t[n],r!==o[n]&&r!==e[n]&&(e[n]=r);return e};return n.version=n.prototype.version,n},this)},{}],4:[function(e,t){var n,r,o;t.exports=n=function(){function e(e){this.offlineLayer=e}return e.prototype.retrieveImage=function(e,t,n){var i;return i=this.offlineLayer._createURL(e.x,e.y,e.z),r(i,function(e){return t(o(e))},n)},e}(),r=function(e,t,n){var r;return r=new XMLHttpRequest,r.open("GET",e,!0),r.responseType="arraybuffer",r.onload=function(e){return 200===this.status?t(this.response):n("GET_STATUS_ERROR",e)},r.onerror=function(e){return n("NETWORK_ERROR",e)},r.send()},o=function(e){var t,n,r,o,i;for(t="",n=new Uint8Array(e),r=o=0,i=n.byteLength;i>=0?i>o:o>i;r=i>=0?++o:--o)t+=String.fromCharCode(n[r]);return"data:image/png;base64,"+btoa(t)}},{}],5:[function(e,t){var n,r,o,i;i=e("async"),r=e("./IndexedDBDataStorage"),o=e("./WebSQLDataStorage"),t.exports=n=function(){function e(e,t){if(null==t)throw new Error("the image store needs an imageRetriever");if(null==e)throw new Error("the image store needs an eventEmitter");this._eventEmitter=e,this._nbTilesLeftToSave=0,this._nbImagesCurrentlyBeingRetrieved=0,this._imageRetriever=t,this._myQueue=null,this._beingCanceled=!1,this._running=!1}return e.prototype.createDB=function(e,t,n,i){var s;if(s=i,null==t)throw new Error("This async function needs a callback");return this.storage=s?new o(e,t,n):new r(e,t,n)},e.prototype.cancel=function(){return this._running?this._beingCanceled?!0:(this._beingCanceled=!0,null!=this._myQueue?(this._myQueue.kill(),0===this._nbImagesCurrentlyBeingRetrieved&&this._finish(),!0):!1):!1},e.prototype.isBusy=function(){return this._running},e.prototype.get=function(e,t,n){if(null==t||null==n)throw new Error("This async function needs callbacks");return this.storage.get(e,t,n)},e.prototype.clear=function(e,t){if(null==e||null==t)throw new Error("This async function needs callbacks");return this.storage.clear(e,t)},e.prototype._finish=function(e,t){return this._running=!1,this._beingCanceled=!1,this._eventEmitter.fire("tilecachingprogressdone",null),this._myQueue=null,this._nbImagesCurrentlyBeingRetrieved=0,null!=e?t(e):this._onSaveImagesSuccess()},e.prototype.saveImages=function(e,t,n,r){if(this._running=!0,null!=this._myQueue)throw new Error("Not allowed to save images while saving is already in progress");if(null==t||null==n||null==r)throw new Error("This async function needs callbacks");return this._onSaveImagesSuccess=n,this._getImagesNotInDB(e,function(e){return function(n){var o,s,a,u;if(!e._beingCanceled&&null!=n&&n.length>0){for(o=8,e._myQueue=i.queue(function(t,n){return e._saveTile(t,n)},o),e._myQueue.drain=function(t){return e._finish(t,r)},a=0,u=n.length;u>a;a++)s=n[a],e._myQueue.push(s);return t()}return t(),e._finish()}}(this),function(e){return r(e)})},e.prototype._getImagesNotInDB=function(e,t,n){var r,o;o=[];for(r in e)o.push(r);return this.storage.getDenseBatch(o,function(n){return function(r){var i,s,a,u,c,l;for(i=0,u=[],n._eventEmitter.fire("tilecachingstart",null),n._nbTilesLeftToSave=0,s=function(t){var r,s;return t||(r=o[i],s=e[r],n._nbTilesLeftToSave++,u.push({key:r,tileInfo:s})),i++},c=0,l=r.length;l>c;c++)a=r[c],s(a);return n._updateTotalNbImagesLeftToSave(n._nbTilesLeftToSave),t(u)}}(this),function(e){return n(e)})},e.prototype._saveTile=function(e,t){var n,r;return r=function(n){return function(r){return n.storage.put(e.key,{image:r},function(){return n._decrementNbTilesLeftToSave(),t()},function(e){return n._decrementNbTilesLeftToSave(),t(e)})}}(this),n=function(n){return function(r,o){return n._decrementNbTilesLeftToSave(),n._eventEmitter._reportError(r,{data:o,tileInfo:e.tileInfo}),t(r)}}(this),this._nbImagesCurrentlyBeingRetrieved++,this._imageRetriever.retrieveImage(e.tileInfo,r,n)},e.prototype._updateTotalNbImagesLeftToSave=function(e){return this._nbTilesLeftToSave=e,this._eventEmitter.fire("tilecachingprogressstart",{nbTiles:this._nbTilesLeftToSave})},e.prototype._decrementNbTilesLeftToSave=function(){return this._nbTilesLeftToSave--,this._beingCanceled||this._eventEmitter.fire("tilecachingprogress",{nbTiles:this._nbTilesLeftToSave}),this._nbImagesCurrentlyBeingRetrieved--,this._beingCanceled&&0===this._nbImagesCurrentlyBeingRetrieved?this._finish():void 0},e}()},{"./IndexedDBDataStorage":6,"./WebSQLDataStorage":9,async:1}],6:[function(e,t){var n,r;n=e("idb-wrapper"),t.exports=r=function(){function e(e,t,r){this._idbStore=new n({dbVersion:1,storeName:e,keyPath:null,autoIncrement:!1},t,r)}return e.prototype.get=function(e,t,n){return this._idbStore.get(e,t,n)},e.prototype.clear=function(e,t){return this._idbStore.clear(e,t)},e.prototype.put=function(e,t,n,r){return this._idbStore.put(e,t,n,r)},e.prototype.getDenseBatch=function(e,t,n){return this._idbStore.getBatch(e,t,n,"dense")},e}()},{"idb-wrapper":3}],7:[function(e,t){var n,r,o,i={}.hasOwnProperty,s=function(e,t){function n(){this.constructor=e}for(var r in t)i.call(t,r)&&(e[r]=t[r]);return n.prototype=t.prototype,e.prototype=new n,e.__super__=t.prototype,e};r=e("./ImageStore"),n=e("./ImageRetriever"),t.exports=o=function(e){function t(){return t.__super__.constructor.apply(this,arguments)}return s(t,e),t.prototype.initialize=function(e,t){var o,i,s,a,u;if(L.TileLayer.prototype.initialize.call(this,e,t),this._map=t.map,this._onReady=t.onReady,this._onError=t.onError,o=t.dbOption,this._dbOnly=t.dbOnly,a=t.storeName||"OfflineLeafletTileImages",this._tileImagesStore=null,this._minZoomLevel=12,null!=t.minZoomLevel&&(this._minZoomLevel=parseInt(t.minZoomLevel)),null==o||"None"===o)return setTimeout(function(e){return function(){return e._onReady()}}(this),0);try{return"WebSQL"===o?u=!0:"IndexedDB"===o?u=!1:this._onError("COULD_NOT_CREATE_DB","Invalid dbOption parameter: "+o),s=new n(this),this._tileImagesStore=new r(this,s),this._tileImagesStore.createDB(a,function(e){return function(){return e._onReady()}}(this),function(e){return function(t){return e._tileImagesStore=null,e._reportError("COULD_NOT_CREATE_DB",t),setTimeout(function(){return e._onReady()},0)}}(this),u)}catch(c){return i=c,this._tileImagesStore=null,this._reportError("COULD_NOT_CREATE_DB",i),setTimeout(function(e){return function(){return e._onReady()}}(this),0)}},t.prototype._setUpTile=function(e,t,n){return e.src=n,this.fire("tileloadstart",{tile:e,url:e.src})},t.prototype._reportError=function(e,t){return this._onError?this._onError(e,t):void 0},t.prototype._loadTile=function(e,t){var n,r,o;return!this._dbOnly==!0&&(this._dbOnly=!1),this._tileImagesStore?(e._layer=this,e.onerror=this._tileOnError,this._adjustTilePoint(t),e.onload=this._tileOnLoad,o=function(r){return function(o){return o?r._setUpTile(e,n,o.image):r._dbOnly?void 0:r._setUpTile(e,n,r.getTileUrl(t))}}(this),r=function(r){return function(){return r._dbOnly||r._setUpTile(e,n,r.getTileUrl(t)),r._reportError("DB_GET",n)}}(this),n=this._createTileKey(t.x,t.y,t.z),this._tileImagesStore.get(n,o,r)):L.TileLayer.prototype._loadTile.call(this,e,t)},t.prototype.useDB=function(){return null!==this._tileImagesStore},t.prototype.cancel=function(){return null!=this._tileImagesStore?this._tileImagesStore.cancel():!1},t.prototype.clearTiles=function(e,t){return this.useDB()?this.isBusy()?(this._reportError("SYSTEM_BUSY","System is busy."),t("System is busy."),void 0):this._tileImagesStore.clear(e,function(e){return function(n){return e._reportError("COULD_NOT_CLEAR_DB",n),t(n)}}(this)):(this._reportError("NO_DB","No DB available"),t("No DB available"),void 0)},t.prototype.calculateNbTiles=function(e,t){var n,r,o;if(this._map.getZoom()=T?S>=_:_>=S;o=S>=T?++_:--_)for(r=b=I=f.min.x,x=f.max.x;x>=I?x>=b:b>=x;r=x>=I?++b:--b)y.push(new L.Point(r,o));for(p=L.bounds(n.min.divideBy(m),n.max.divideBy(m)),c=p.min.y,a=p.max.y,u=p.min.x,s=p.max.x,t=y.length,r=E=0;t>=0?t>E:E>t;r=t>=0?++E:--E)l=y[r],g=l.x,v=l.y,this._getZoomedInTiles(g,v,h,e,d,c,a,u,s),this._getZoomedOutTiles(g,v,h,0,d,c,a,u,s);return d},t.prototype.saveTiles=function(e,t,n,r){var o;return this._tileImagesStore?this.isBusy()?(this._reportError("SYSTEM_BUSY","system is busy."),r("system is busy."),void 0):this._map.getZoom()x;x++){for(m=t[x],console.log("[_getTilesByRegion()] Processing "+m.name),v=L.latLng(m.sLat,m.wLng),f=L.latLng(m.nLat,m.eLng),d=L.point(this._map.project(v,g).x,this._map.project(v,g).y),h=L.point(this._map.project(f,g).x,this._map.project(f,g).y),r=L.bounds(d,h),y=L.bounds(r.min.divideBy(E)._floor(),r.max.divideBy(E)._floor()),console.log("[_getTilesByRegion()] roundedTileBounds"),console.log(y.min),console.log(y.max),T=[],s=w=R=y.min.y,k=y.max.y;k>=R?k>=w:w>=k;s=k>=R?++w:--w)for(i=N=D=y.min.x,A=y.max.x;A>=D?A>=N:N>=A;i=A>=D?++N:--N)T.push(new L.Point(i,s)); +for(_=L.bounds(r.min.divideBy(E),r.max.divideBy(E)),l=_.min.y,u=_.max.y,c=_.min.x,a=_.max.x,n=T.length,console.log("[_getTilesByRegion()] arrayLength = "+n),i=O=0;n>=0?n>O:O>n;i=n>=0?++O:--O)p=T[i],S=p.x,I=p.y,this._getZoomedInTiles(S,I,g,e,b,l,u,c,a),this._getZoomedOutTiles(S,I,g,0,b,l,u,c,a)}return b},t.prototype.saveRegions=function(e,t,n,r,o){var i;return console.log("[saveRegions()]"),this._tileImagesStore?this.isBusy()?(this._reportError("SYSTEM_BUSY","system is busy."),o("system is busy."),void 0):this._map.getZoom()n?(i*=2,s*=2,a*=2,u*=2,this._getZoomedInTiles(2*e,2*t,n+1,r,o,i,s,a,u),this._getZoomedInTiles(2*e+1,2*t,n+1,r,o,i,s,a,u),this._getZoomedInTiles(2*e,2*t+1,n+1,r,o,i,s,a,u),this._getZoomedInTiles(2*e+1,2*t+1,n+1,r,o,i,s,a,u)):void 0},t.prototype._getZoomedOutTiles=function(e,t,n,r,o,i,s,a,u){return this._getTileImage(e,t,n,o,i,s,a,u,!1),n>r?(i/=2,s/=2,a/=2,u/=2,this._getZoomedOutTiles(Math.floor(e/2),Math.floor(t/2),n-1,r,o,i,s,a,u)):void 0},t.prototype._getTileImage=function(e,t,n,r,o,i,s,a){var u;if(!(eMath.floor(a)||tMath.floor(i)))return u=this._createTileKey(e,t,n),r[u]?void 0:r[u]={key:u,x:e,y:t,z:n}},t.prototype._createNormalizedTilePoint=function(e,t,n){var r;for(r=Math.pow(2,n);e>r;)e-=r;for(;0>e;)e+=r;for(;t>r;)t-=r;for(;0>t;)t+=r;return{x:e,y:t,z:n}},t.prototype._createURL=function(e,t,n){var r;return r=this._createNormalizedTilePoint(e,t,n),this.getTileUrl(r)},t.prototype._createTileKey=function(e,t,n){var r;return r=this._createNormalizedTilePoint(e,t,n),r.x+", "+r.y+", "+r.z},t}(L.TileLayer)},{"./ImageRetriever":4,"./ImageStore":5}],8:[function(e,t){var n,r={}.hasOwnProperty,o=function(e,t){function n(){this.constructor=e}for(var o in t)r.call(t,o)&&(e[o]=t[o]);return n.prototype=t.prototype,e.prototype=new n,e.__super__=t.prototype,e};t.exports=n=function(e){function t(){return t.__super__.constructor.apply(this,arguments)}return o(t,e),t.prototype.onAdd=function(){var e;return e=L.DomUtil.create("div","offlinemap-controls",this._container),e.setAttribute("id","offlinemap-controls"),this._counter=L.DomUtil.create("div","offlinemap-controls-counter",e),this._counter.setAttribute("id","offlinemap-controls-counter"),this._counter.innerHTML="Ready",this._cancelButton=L.DomUtil.create("input","offlinemap-controls-cancel-button",e),this._cancelButton.setAttribute("type","button"),this._cancelButton.setAttribute("id","cancelBtn"),this._cancelButton.setAttribute("value","Cancel"),this._cancelButton.setAttribute("disabled",!0),L.DomEvent.addListener(this._cancelButton,"click",this.onCancelClick,this),L.DomEvent.disableClickPropagation(this._cancelButton),e},t.prototype.onProgressStart=function(){return this._evaluating=!0,this._counter.innerHTML="...",this._cancelButton.removeAttribute("disabled")},t.prototype.onProgressDone=function(){return this._counter.innerHTML="Ready",this._cancelButton.removeAttribute("disabled")},t.prototype.updateTotalNbTilesLeftToSave=function(e){return this._evaluating=!1,this._nbTilesToSave=e.nbTiles,this.updateNbTilesLeftToSave(e)},t.prototype.updateNbTilesLeftToSave=function(e){return this._evaluating?void 0:this._counter.innerHTML=0===this._nbTilesToSave?"100%":Math.floor((this._nbTilesToSave-e.nbTiles)/this._nbTilesToSave*100)+"%"},t.prototype.onCancelClick=function(){return this._offlineLayer.cancel()?(this._counter.innerHTML="Canceling...",this._cancelButton.setAttribute("disabled",!0)):void 0},t.prototype.setOfflineLayer=function(e){return this._offlineLayer=e,this._offlineLayer.on("tilecachingstart",this.onProgressStart,this),this._offlineLayer.on("tilecachingprogressstart",this.updateTotalNbTilesLeftToSave,this),this._offlineLayer.on("tilecachingprogress",this.updateNbTilesLeftToSave,this),this._offlineLayer.on("tilecachingprogressdone",this.onProgressDone,this)},t}(L.Control)},{}],9:[function(e,t){var n;t.exports=n=function(){function e(e,t,n){this._storeName=e,this._webSQLDB=openDatabase("OfflineTileImages","1.0","Store tile images for OfflineLeaftMap",52428800),this._webSQLDB.transaction(function(e){return function(t){return t.executeSql("CREATE TABLE IF NOT EXISTS "+e._storeName+" (key unique, image)")}}(this),n,t)}return e.prototype.get=function(e,t,n){return this._webSQLDB.transaction(function(r){return function(o){var i;return i=function(e,r){var o;return o=r.rows.length,0===o?t(void 0):1===o?t(r.rows.item(0)):n("There should be no more than one entry")},o.executeSql("SELECT * FROM "+r._storeName+" WHERE key='"+e+"'",[],i,n)}}(this))},e.prototype.clear=function(e,t){return this._webSQLDB.transaction(function(n){return function(r){return r.executeSql("DELETE FROM "+n._storeName,[],e,t)}}(this))},e.prototype.put=function(e,t,n,r){return this._webSQLDB.transaction(function(o){return function(i){return i.executeSql("INSERT OR REPLACE INTO "+o._storeName+" VALUES (?, ?)",[e,t.image],n,r)}}(this))},e.prototype.getDenseBatch=function(e,t,n){return 0===e.length&&t([]),this._webSQLDB.transaction(function(r){return function(o){var i,s,a,u,c,l,f;for(u=[],c=[],i=l=0,f=e.length;f>=0?f>l:l>f;i=f>=0?++l:--l)c.push("'"+e[i]+"'"),u.push(void 0);return s=c.join(","),a=function(n,r){var o,s,a,c;for(i=a=0,c=r.rows.length;c>=0?c>a:a>c;i=c>=0?++a:--a)s=r.rows.item(i),o=e.indexOf(s.key),o>=0&&(u[o]=s);return t(u)},o.executeSql("SELECT * FROM "+r._storeName+" WHERE key IN ("+s+")",[],a,n)}}(this))},e}()},{}],10:[function(e){window.OfflineLayer=e("./OfflineLayer"),window.OfflineProgressControl=e("./OfflineProgressControl")},{"./OfflineLayer":7,"./OfflineProgressControl":8}]},{},[10]); \ No newline at end of file diff --git a/gulpfile.coffee b/gulpfile.coffee index 92a56f2..01a7621 100644 --- a/gulpfile.coffee +++ b/gulpfile.coffee @@ -1,4 +1,4 @@ -gulp = require 'gulp' +gulp = require ('gulp') coffee = require('gulp-coffee') gutil = require('gulp-util') uglify = require('gulp-uglify') @@ -28,6 +28,7 @@ gulp.task 'demo', () -> .pipe(streamConvert('bundle.js')) .pipe(gulp.dest("./demo/")) + gulp.task 'standalone', () -> bundler = browserify("./standalone.coffee", extensions: [".coffee"] @@ -35,6 +36,7 @@ gulp.task 'standalone', () -> bundler.bundle() .pipe(streamConvert('offlinemap.js')) .pipe(gulp.dest("./dist/")) + .pipe(gulp.dest("./demo/")) .pipe(buffer()) .pipe(rename("offlinemap.min.js")) .pipe(uglify()) diff --git a/src/ImageStore.coffee b/src/ImageStore.coffee index 3edbccf..20f8b08 100644 --- a/src/ImageStore.coffee +++ b/src/ImageStore.coffee @@ -80,6 +80,7 @@ module.exports = class ImageStore @_getImagesNotInDB(tileImagesToQuery, (tileInfoOfImagesNotInDB) => + if not @_beingCanceled and tileInfoOfImagesNotInDB? and tileInfoOfImagesNotInDB.length > 0 MAX_NB_IMAGES_RETRIEVED_SIMULTANEOUSLY = 8 @_myQueue = async.queue((data, callback) => diff --git a/src/OfflineLayer.coffee b/src/OfflineLayer.coffee index 0f3ad69..08580db 100644 --- a/src/OfflineLayer.coffee +++ b/src/OfflineLayer.coffee @@ -14,10 +14,11 @@ ImageRetriever = require './ImageRetriever' module.exports = class OfflineLayer extends L.TileLayer initialize: (url, options) -> L.TileLayer.prototype.initialize.call(this, url, options) - + @_map = options['map'] @_onReady = options["onReady"] @_onError = options["onError"] dbOption = options["dbOption"] + @_dbOnly = options["dbOnly"] # Boolean, if true only show tile that are cached in the DB. storeName = options["storeName"] || 'OfflineLeafletTileImages' @_tileImagesStore = null @_minZoomLevel = 12 @@ -78,6 +79,8 @@ module.exports = class OfflineLayer extends L.TileLayer # look at the code from L.TileLayer for more details _loadTile: (tile, tilePoint) -> + if not @_dbOnly == true + @_dbOnly = false; if not @_tileImagesStore return L.TileLayer.prototype._loadTile.call(this, tile, tilePoint) @@ -92,16 +95,17 @@ module.exports = class OfflineLayer extends L.TileLayer if dbEntry # if the tile has been cached, use the stored Base64 value @_setUpTile(tile, key, dbEntry.image) - else + else # query the map provider for the tile - @_setUpTile(tile, key, @getTileUrl(tilePoint)) + if not @_dbOnly + @_setUpTile(tile, key, @getTileUrl(tilePoint)) onError = () => # Error while getting the key from the DB # will get the tile from the map provider - @_setUpTile(tile, key, @getTileUrl(tilePoint)) + if not @_dbOnly + @_setUpTile(tile, key, @getTileUrl(tilePoint)) @_reportError("DB_GET", key) - key = @_createTileKey(tilePoint.x, tilePoint.y, tilePoint.z) # Look for the tile in the DB @_tileImagesStore.get(key, onSuccess, onError) @@ -131,13 +135,20 @@ module.exports = class OfflineLayer extends L.TileLayer ) # calculateNbTiles includes potentially already saved tiles. - calculateNbTiles: (zoomLevelLimit) -> + calculateNbTiles: (zoomLevelLimit, regions) -> + if @_map.getZoom() < @_minZoomLevel @_reportError("ZOOM_LEVEL_TOO_LOW") return -1 count = 0 - tileImagesToQuery = @_getTileImages(zoomLevelLimit) + if regions + tileImagesToQuery = @_getTilesByRegion(zoomLevelLimit, regions) + else + tileImagesToQuery = @_getTileImages(zoomLevelLimit) + + + for key of tileImagesToQuery count++ return count @@ -192,6 +203,10 @@ module.exports = class OfflineLayer extends L.TileLayer @_getZoomedOutTiles(x, y, startingZoom, 0, tileImagesToQuery, minY, maxY, minX, maxX) return tileImagesToQuery + + + + # saves the tiles currently on screen + lower and higher zoom levels. saveTiles: (zoomLevelLimit, onStarted, onSuccess, onError) -> @@ -217,8 +232,109 @@ module.exports = class OfflineLayer extends L.TileLayer onError(error) ) + +# Returns tiles that are gotten from the defined regions. + # Regions are boxes defined by lat and lng. + # Params: + # - zoomLevelLimit: [Integer] the maximum zoom level to use in caching images. + # - regions: [Array] An array of objects. Each object defines a regions as follows + # { + # name:'', + # nLat:, + # sLat:, + # wLng:, + # eLng: + # } + # } + _getTilesByRegion: (zoomLevelLimit, regions) -> + console.log('[_getTilesByRegion()]'); + zoomLevelLimit = zoomLevelLimit || @_map.getMaxZoom() + startingZoom = 12 + tileImagesToQuery = {} + tileSize = @_getTileSize() + boundsORG = @_map.getPixel + + for region in regions + console.log('[_getTilesByRegion()] Processing '+region.name) + # Get the bounds of the region + sw = L.latLng(region.sLat, region.wLng) + ne = L.latLng(region.nLat, region.eLng) + + # Compute the bounds (these are in tile coordinates, not lat/lng) + psw = L.point(@_map.project(sw, startingZoom).x, @_map.project(sw, startingZoom).y); + pne = L.point(@_map.project(ne, startingZoom).x, @_map.project(ne, startingZoom).y); + bounds = L.bounds(psw, pne); + + roundedTileBounds = L.bounds( + bounds.min.divideBy(tileSize)._floor(), + bounds.max.divideBy(tileSize)._floor() + ) + + console.log('[_getTilesByRegion()] roundedTileBounds'); + console.log(roundedTileBounds.min); + console.log(roundedTileBounds.max); + tilesInScreen = [] + + for j in [roundedTileBounds.min.y .. roundedTileBounds.max.y] + for i in [roundedTileBounds.min.x .. roundedTileBounds.max.x] + tilesInScreen.push(new L.Point(i, j)) + + # We will use the exact bound values to test if sub tiles are still inside these bounds. + # The idea is to avoid caching images outside the screen. + + tileBounds = L.bounds( + bounds.min.divideBy(tileSize), + bounds.max.divideBy(tileSize) + ) + minY = tileBounds.min.y + maxY = tileBounds.max.y + minX = tileBounds.min.x + maxX = tileBounds.max.x + + + arrayLength = tilesInScreen.length + console.log('[_getTilesByRegion()] arrayLength = ' + arrayLength) + for i in [0 ... arrayLength] + point = tilesInScreen[i] + x = point.x + y = point.y + @_getZoomedInTiles(x, y, startingZoom, zoomLevelLimit, tileImagesToQuery, minY, maxY, minX, maxX) + @_getZoomedOutTiles(x, y, startingZoom, 0, tileImagesToQuery, minY, maxY, minX, maxX) + + return tileImagesToQuery + + + # saves the tiles currently on screen + lower and higher zoom levels. + saveRegions: (regions, zoomLevelLimit, onStarted, onSuccess, onError) -> + console.log('[saveRegions()]'); + if(!@_tileImagesStore) + @_reportError("NO_DB", "No DB available") + onError("No DB available") + return + + if(@isBusy()) + @_reportError("SYSTEM_BUSY", "system is busy.") + onError("system is busy.") + return + + if @_map.getZoom() < @_minZoomLevel + @_reportError("ZOOM_LEVEL_TOO_LOW") + onError("ZOOM_LEVEL_TOO_LOW") + return + + #lock UI + tileImagesToQuery = @_getTilesByRegion(zoomLevelLimit, regions) + console.log('[saveRegions] tileImagesToQuery') + console.log(tileImagesToQuery) + @_tileImagesStore.saveImages(tileImagesToQuery, onStarted, onSuccess, (error) => + @_reportError("SAVING_TILES", error) + onError(error) + ) + + # returns all the tiles with higher zoom levels _getZoomedInTiles: (x, y, currentZ, maxZ, tileImagesToQuery, minY, maxY, minX, maxX) -> + @_getTileImage(x, y, currentZ, tileImagesToQuery, minY, maxY, minX, maxX, true) if currentZ < maxZ @@ -253,6 +369,7 @@ module.exports = class OfflineLayer extends L.TileLayer # At this point, we only add the image to a "dictionary" # This is being done to avoid multiple requests when zooming out, since zooming int should never overlap key = @_createTileKey(x, y, z) + if(!tileImagesToQuery[key]) tileImagesToQuery[key] = {key:key, x: x, y: y, z: z} From 757c3f90ad4072492ca9ae7b9c52fbe2a103a2c7 Mon Sep 17 00:00:00 2001 From: Wil Black Date: Thu, 13 Nov 2014 15:39:09 -0800 Subject: [PATCH 2/3] Better Region Def's --- demo/regions-demo.html | 101 ++++++++++++++++++++--------------------- 1 file changed, 49 insertions(+), 52 deletions(-) diff --git a/demo/regions-demo.html b/demo/regions-demo.html index 877c316..5db9685 100644 --- a/demo/regions-demo.html +++ b/demo/regions-demo.html @@ -35,36 +35,50 @@ var subDomains = ['otile1','otile2','otile3','otile4'] var mapquestAttrib = 'Data, imagery and map information provided by MapQuest, OpenStreetMap and contributors.' - - loadRegions = function(){ - // Create the map - $("#log").text('Loading Regions...') - var regions = [ + var regions = [ + { + name: "Region 1 - Coos Bay to OR/CA Border", + nLat: 43.5, + sLat: 42.0, + wLng: -124.7, + eLng: -124.2 + }, { - name: "Region 1", - nLat: 44.0, - sLat: 41.5, - wLng: -124.4, - eLng: -124.1 + name: "Region 2 - OR/CA Border to Shelter Cove", + nLat: 42.0, + sLat: 40.0, + wLng: -124.5, + eLng: -123.8 }, - // { - // name: "Region 2", - // nLat: 41.5, - // sLat: 39.0, - // wLng: -124.6, - // eLng: -124.3 - // }, - // { - // name: "Region 3", - // nLat: 39.0, - // sLat: 37.0, - // wLng: -124.4, - // eLng: -124.1 - // } + { + name: "Region 3 - Shelter Cove to ???", + nLat: 40.0, + sLat: 32.0, + wLng: -124.0, + eLng: -123.5 + } ]; + + onReady = function(){ + /* + This is fired when the offlineLayer has cached all of it's tiles. + */ + console.log("[offlineLayer onReady()] The OfflineLayer is ready to be used"); + } + + onError = function(errorType, errorData1, errorData2){ + /* + Fires when offlineLayer errors out during tile caching. + */ + console.log("[offlineLayer onError()] "); + console.log(errorType) + console.log(errorData1) + console.log(errorData2) + } + + init = function(){ if (!map) map = L.map('map').setView([-2.9, -79], 13); - var options = { map: map, maxZoom: 12, @@ -76,15 +90,21 @@ storeName:"myStoreName", dbOption:"WebSQL" } - offlineLayer = new OfflineLayer( mapquestUrl, options) + offlineLayer = new OfflineLayer( mapquestUrl, options); + } + init(); + + loadRegions = function(){ + // Create the map + $("#log").text('Loading Regions...') - nbTiles = offlineLayer.calculateNbTiles(options.maxZoom, regions); + nbTiles = offlineLayer.calculateNbTiles(offlineLayer.options.maxZoom, regions); if (nbTiles < 10000) { console.log("Will be saving: " + nbTiles + " tiles") - offlineLayer.saveRegions(regions, options.maxZoom, + offlineLayer.saveRegions(regions, offlineLayer.options.maxZoom, function(){ console.log('[saveRegions] onStarted'); @@ -106,31 +126,7 @@ } // End load regions - onReady = function(){ - /* - This is fired when the offlineLayer has cached all of it's tiles. - */ - - console.log("[offlineLayer onReady()] The OfflineLayer is ready to be used"); - - //offlineLayer.addTo(map); - // cacheBtn = new CacheBtnControl(); - // map.addControl(cacheBtn); - // progressControls = new OfflineProgressControl(); - // progressControls.setOfflineLayer(offlineLayer); - // map.addControl(progressControls); - } - - onError = function(errorType, errorData1, errorData2){ - /* - Fires when offlineLayer errors out during tile caching. - */ - console.log("[offlineLayer onError()] "); - console.log(errorType) - console.log(errorData1) - console.log(errorData2) - } clearTiles = function(){ $("#log").text('clearing tiles...'); @@ -151,6 +147,7 @@ map.addEventListener('mousemove', function(event){ $("#position").text(event.latlng.toString()); }) + map.setView([40.0, -124], 10); // var map = L.map('map').setView([40.0, -124], 10); From 50672c6c69ca7a475c213dbe69563ffceb3b5a8e Mon Sep 17 00:00:00 2001 From: Wil Black Date: Thu, 13 Nov 2014 17:36:02 -0800 Subject: [PATCH 3/3] Still not loading secondary map. --- README.md | 58 +++++++++++- demo/regions-demo.html | 192 ++++++++++++++++++++++++++-------------- src/OfflineLayer.coffee | 9 +- 3 files changed, 187 insertions(+), 72 deletions(-) diff --git a/README.md b/README.md index 7b05c62..bb767f4 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,8 @@ It is initialized the same way, using url and options but it has extra options: The idea is to make it possible to zoom in but also to locate your saved data from a lower zoom level when working offline. **zoomLevelLimit** will limit the zoom depth. +* **saveRegions(regions, zoomLevel, onStarted, onSuccess, onError):** +save all tiles with the regions defined on the `regions` parameter. `regions` is an Array objects. Each object defines a lat/lon box. This will cahce al tiles in this region with the same behavior as saveTiles. See the [regions-demo.html example](#regions-demo) * **calculateNbTiles(zoomLevelLimit):** An important function that will tell you how many tiles would be saved by a call to saveTiles. Make sure to call this function and limit any call to saveTiles() if you want to avoid saving millions of tiles. **zoomLevelLimit** will limit the zoom depth. @@ -62,10 +64,14 @@ This could happen if these functions are called before the onReady callback or i **saveTiles() errors:** + * **"SYSTEM\_BUSY":** System is busy. + * **"SAVING\_TILES":** An error occurred when calling saveTiles. + * **"DB\_GET":** An error occurred when calling get on ImageStore. errorData is the DB key of the tile. * **"GET\_STATUS\_ERROR":** The XMLHttpRequest Get status is not equal to 200. errorData contains the error from XMLHttpRequest and the URL of the image. + * **"NETWORK\_ERROR":** The XMLHttpRequest used to get an image threw an error. errorData contains the error from XMLHttpRequest and the URL of the image. **clearTiles() errors:** @@ -74,13 +80,57 @@ This could happen if these functions are called before the onReady callback or i -##Example +##Examples +To build the examples + +``` +npm install +gulp +``` + +To run an example start a webserver in the `/demo` +``` +cd demo +cd http-server +``` + +The navigate to `localhost:8081/` or `localhost:8081/regions-demo.html` for the regions example. + +### Example 1. Caching tiles in the current viewport Look at **src/demo.coffee** for a complete example of how to use OfflineLayer and a basic progression control example. +### Example 2. Caching tiles from pre-defined regions +The example is defined in `demo/regions-demo.html`. It loads tiles from from a list of regions defined in a regions array. These tiles are then available any time you want to create a map. This is useful for loading tiles into an app for a specific geographic area -To run the examples +Here is an example of a regions array: +``` +# This regions caches a strip of coastline on the US West Coast. +regions = [ + { + name: "Region 1", + nLat: 43.5, + sLat: 42.0, + wLng: -124.7, + eLng: -124.2 + }, + { + name: "Region 2", + nLat: 42.0, + sLat: 40.0, + wLng: -124.5, + eLng: -123.8 + }, + { + name: "Region 3", + nLat: 40.0, + sLat: 32.0, + wLng: -124.0, + eLng: -123.5 + } + ]; ``` -npm install -``` \ No newline at end of file + + +---- diff --git a/demo/regions-demo.html b/demo/regions-demo.html index 5db9685..b0cf67f 100644 --- a/demo/regions-demo.html +++ b/demo/regions-demo.html @@ -17,12 +17,12 @@ - +
-
+
@@ -31,6 +31,10 @@ $( document ).ready(function() { window.map = null; window.offlineLayer; + window.noaaLayer; + + var noaaUrl = 'http://tile.stamen.com/watercolor/{z}/{x}/{y}.jpg' + var mapquestUrl = 'http://{s}.mqcdn.com/tiles/1.0.0/osm/{z}/{x}/{y}.png' var subDomains = ['otile1','otile2','otile3','otile4'] var mapquestAttrib = 'Data, imagery and map information provided by MapQuest, OpenStreetMap and contributors.' @@ -52,7 +56,7 @@ eLng: -123.8 }, { - name: "Region 3 - Shelter Cove to ???", + name: "Region 3 - Shelter Cove to Point Arena", nLat: 40.0, sLat: 32.0, wLng: -124.0, @@ -60,7 +64,7 @@ } ]; - onReady = function(){ + onReady = function(){ /* This is fired when the offlineLayer has cached all of it's tiles. */ @@ -87,10 +91,24 @@ dbOnly: true, onReady: onReady, onError: onError, - storeName:"myStoreName", - dbOption:"WebSQL" + storeName:"OSMTiles", + dbOption:"IndexedDB" } offlineLayer = new OfflineLayer( mapquestUrl, options); + + var options = { + map: map, + maxZoom: 12, + attribution: mapquestAttrib, + //subdomains: subDomains, + dbOnly: true, + onReady: onReady, + onError: onError, + storeName:"NOAATiles", + dbOption:"IndexedDB" + } + noaaLayer = new OfflineLayer( noaaUrl, options); + } init(); @@ -100,34 +118,42 @@ nbTiles = offlineLayer.calculateNbTiles(offlineLayer.options.maxZoom, regions); if (nbTiles < 10000) { - console.log("Will be saving: " + nbTiles + " tiles") - - - - offlineLayer.saveRegions(regions, offlineLayer.options.maxZoom, - function(){ - console.log('[saveRegions] onStarted'); - - }, - function(){ - console.log('[saveRegions] onSuccess'); - $("#log").text('Done Loading Regions') - }, - function(error){ - console.log('onError'); - console.log(error); - }) + console.log("Will be saving: " + nbTiles + " tiles") + + offlineLayer.saveRegions(regions, offlineLayer.options.maxZoom, + function(){ + console.log('[saveRegions] onStarted'); + + }, + function(){ + console.log('[saveRegions] onSuccess'); + $("#log").text('Done Loading OSM Regions') + }, + function(error){ + console.log('onError'); + console.log(error); + }) + + noaaLayer.saveRegions(regions, noaaLayer.options.maxZoom, + function(){ + console.log('[saveRegions] onStarted'); + + }, + function(){ + console.log('[saveRegions] onSuccess'); + $("#log").text('Done Loading NOAA Regions') + }, + function(error){ + console.log('onError'); + console.log(error); + }) } else { - alert("You are trying to save " + nbTiles + " tiles. There is currently a limit of 10,000 tiles."); + alert("You are trying to save " + nbTiles + " tiles. There is currently a limit of 10,000 tiles."); } - - } // End load regions - - - + clearTiles = function(){ $("#log").text('clearing tiles...'); offlineLayer.clearTiles( @@ -139,48 +165,86 @@ } ); + + noaaLayer.clearTiles( + function(){ + console.log('[clearTiles] success') + $("#log").text('done clearing tiles'); + },function(error) { + console.log('[clearTiles] fail') + + } + ); + }; - showMap = function(){ - offlineLayer.addTo(map); + + showNewMap = function(){ + $("#map").hide(); + if (!newMap) { + var newMap = L.map('new-map', { + center: [40.0, -124], + zoom: 10, + //layers: [offlineLayer, noaaLayer] + }) + + } + + onReady = function(){ + console.log("[newMap offlineLayer onReady()] "); + } - map.addEventListener('mousemove', function(event){ + onError = function(errorType, errorData1, errorData2){ + /* + Fires when offlineLayer errors out during tile caching. + */ + console.log("[newMap offlineLayer onError()] "); + console.log(errorType) + console.log(errorData1) + console.log(errorData2) + } + + var options = { + map: newMap, + maxZoom: 13, + attribution: mapquestAttrib, + subdomains: subDomains, + dbOnly: true, + onReady: onReady, + onError: onError, + storeName:"OSMTiles", + dbOption:"WebSQL" + } + + newLayer = new OfflineLayer( mapquestUrl, options) + newLayer.addTo(newMap); + + var options = { + map: newMap, + maxZoom: 12, + attribution: mapquestAttrib, + //subdomains: subDomains, + dbOnly: true, + onReady: onReady, + onError: onError, + storeName:"NOAATiles", + dbOption:"IndexedDB" + } + noaaLayer = new OfflineLayer( noaaUrl, options); + noaaLayer.addTo(newMap); + + var baseMaps = { + "OSM": offlineLayer, + "NOAA": noaaLayer, + }; + L.control.layers(baseMaps).addTo(newMap); + newMap.addEventListener('mousemove', function(event){ $("#position").text(event.latlng.toString()); }) - map.setView([40.0, -124], 10); - // var map = L.map('map').setView([40.0, -124], 10); + } + - // onReady = function(){ - // console.log("[showMap offlineLayer onReady()] "); - // } - - // onError = function(errorType, errorData1, errorData2){ - // /* - // Fires when offlineLayer errors out during tile caching. - // */ - // console.log("[showMap offlineLayer onError()] "); - // console.log(errorType) - // console.log(errorData1) - // console.log(errorData2) - // } - - // var options = { - // map: map, - // maxZoom: 13, - // attribution: mapquestAttrib, - // subdomains: subDomains, - // dbOnly: true, - // onReady: onReady, - // onError: onError, - // storeName:"myStoreName", - // dbOption:"WebSQL" - // } - // //newLayer = new OfflineLayer( mapquestUrl, options) - // offlineLayer.addTo(map); - - } - }); diff --git a/src/OfflineLayer.coffee b/src/OfflineLayer.coffee index 08580db..f2ecfe6 100644 --- a/src/OfflineLayer.coffee +++ b/src/OfflineLayer.coffee @@ -79,7 +79,7 @@ module.exports = class OfflineLayer extends L.TileLayer # look at the code from L.TileLayer for more details _loadTile: (tile, tilePoint) -> - if not @_dbOnly == true + if not @_dbOnly == true @_dbOnly = false; if not @_tileImagesStore return L.TileLayer.prototype._loadTile.call(this, tile, tilePoint) @@ -233,7 +233,9 @@ module.exports = class OfflineLayer extends L.TileLayer ) -# Returns tiles that are gotten from the defined regions. + + _getTilesByRegion: (zoomLevelLimit, regions) -> + # Returns tiles that are gotten from the defined regions. # Regions are boxes defined by lat and lng. # Params: # - zoomLevelLimit: [Integer] the maximum zoom level to use in caching images. @@ -245,8 +247,7 @@ module.exports = class OfflineLayer extends L.TileLayer # wLng:, # eLng: # } - # } - _getTilesByRegion: (zoomLevelLimit, regions) -> + # } console.log('[_getTilesByRegion()]'); zoomLevelLimit = zoomLevelLimit || @_map.getMaxZoom() startingZoom = 12