Merge pull request #301 from ahocevar/offline
Adding CacheRead and CacheWrite controls. r=@elemoine,@fredj
This commit is contained in:
36
examples/cache-read.html
Normal file
36
examples/cache-read.html
Normal file
@@ -0,0 +1,36 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<title>OpenLayers Cache Read Example</title>
|
||||
<link rel="stylesheet" href="../theme/default/style.css" type="text/css">
|
||||
<link rel="stylesheet" href="style.css" type="text/css">
|
||||
<script src="../lib/OpenLayers.js"></script>
|
||||
<script src="cache-read.js"></script>
|
||||
</head>
|
||||
<body onload="init()">
|
||||
<h1 id="title">Cache Read Example</h1>
|
||||
|
||||
<div id="tags">
|
||||
local storage, persistence, cache, html5
|
||||
</div>
|
||||
|
||||
<div id="shortdesc">Caching viewed tiles</div>
|
||||
|
||||
<div id="map" class="smallmap"></div>
|
||||
<div id="status"></div>
|
||||
<br>
|
||||
<div id="docs">
|
||||
<p>This example shows how to use the CacheRead control to fetch cached
|
||||
tiles from the browser's Local Storage. As you pan and zoom the map,
|
||||
you can see how the number of cache hits incrases as you browse regions
|
||||
that are available in the cache.</p>
|
||||
<p>To fill the cache with tiles, switch to the
|
||||
<a href="cache-write.html">cache-write.html</a> example.</p>
|
||||
<p>See <a href="cache-read.js">cache-read.js</a> for the source
|
||||
code.</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
36
examples/cache-read.js
Normal file
36
examples/cache-read.js
Normal file
@@ -0,0 +1,36 @@
|
||||
var map, cacheRead;
|
||||
function init() {
|
||||
map = new OpenLayers.Map({
|
||||
div: "map",
|
||||
projection: "EPSG:900913",
|
||||
layers: [
|
||||
new OpenLayers.Layer.WMS("OSGeo", "http://vmap0.tiles.osgeo.org/wms/vmap0", {
|
||||
layers: "basic"
|
||||
}, {
|
||||
eventListeners: {
|
||||
tileloaded: updateHits
|
||||
}
|
||||
})
|
||||
],
|
||||
center: [0, 0],
|
||||
zoom: 1
|
||||
});
|
||||
cacheRead = new OpenLayers.Control.CacheRead();
|
||||
map.addControl(cacheRead);
|
||||
|
||||
|
||||
|
||||
// User interface
|
||||
var status = document.getElementById("status"),
|
||||
hits = 0;
|
||||
|
||||
// update the number of cached tiles and detect local storage support
|
||||
function updateHits(evt) {
|
||||
hits += evt.tile.url.substr(0, 5) === "data:";
|
||||
if (window.localStorage) {
|
||||
status.innerHTML = hits + " cache hits.";
|
||||
} else {
|
||||
status.innerHTML = "Local storage not supported. Try a different browser.";
|
||||
}
|
||||
}
|
||||
}
|
||||
37
examples/cache-write.html
Normal file
37
examples/cache-write.html
Normal file
@@ -0,0 +1,37 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<title>OpenLayers Cache Write Example</title>
|
||||
<link rel="stylesheet" href="../theme/default/style.css" type="text/css">
|
||||
<link rel="stylesheet" href="style.css" type="text/css">
|
||||
<script src="../lib/OpenLayers.js"></script>
|
||||
<script>OpenLayers.Console = window.console;</script>
|
||||
<script src="cache-write.js"></script>
|
||||
</head>
|
||||
<body onload="init()">
|
||||
<h1 id="title">Cache Write Example</h1>
|
||||
|
||||
<div id="tags">
|
||||
local storage, persistence, cache, html5
|
||||
</div>
|
||||
|
||||
<div id="shortdesc">Caching viewed tiles</div>
|
||||
|
||||
<div id="map" class="smallmap"></div>
|
||||
<div>Cache status: <span id="status"></span></div>
|
||||
<div><button id="clear">Clear cache</button></div>
|
||||
<br>
|
||||
<div id="docs">
|
||||
<p>This example shows how to use the CacheWrite control to cache the
|
||||
tiles. Caching is turned on, and as you pan and zoom the map, every
|
||||
tile that is loaded is also copied to the browsers Local Storage.</p>
|
||||
<p>To use the cached tiles, switch to the
|
||||
<a href="cache-read.html">cache-read.html</a> example.</p>
|
||||
<p>See <a href="cache-write.js">cache-write.js</a> for the source
|
||||
code.</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
48
examples/cache-write.js
Normal file
48
examples/cache-write.js
Normal file
@@ -0,0 +1,48 @@
|
||||
// Use proxy to get same origin URLs for tiles that don't support CORS.
|
||||
OpenLayers.ProxyHost = "proxy.cgi?url=";
|
||||
|
||||
var map, cacheWrite;
|
||||
|
||||
function init() {
|
||||
map = new OpenLayers.Map({
|
||||
div: "map",
|
||||
projection: "EPSG:900913",
|
||||
layers: [
|
||||
new OpenLayers.Layer.WMS("OSGeo", "http://vmap0.tiles.osgeo.org/wms/vmap0", {
|
||||
layers: "basic"
|
||||
}, {
|
||||
eventListeners: {
|
||||
tileloaded: updateStatus
|
||||
}
|
||||
})
|
||||
],
|
||||
center: [0, 0],
|
||||
zoom: 1
|
||||
});
|
||||
cacheWrite = new OpenLayers.Control.CacheWrite({
|
||||
autoActivate: true,
|
||||
imageFormat: "image/jpeg",
|
||||
eventListeners: {
|
||||
cachefull: function() { status.innerHTML = "Cache full."; }
|
||||
}
|
||||
});
|
||||
map.addControl(cacheWrite);
|
||||
|
||||
|
||||
|
||||
// User interface
|
||||
var status = document.getElementById("status");
|
||||
document.getElementById("clear").onclick = function() {
|
||||
OpenLayers.Control.CacheWrite.clearCache();
|
||||
updateStatus();
|
||||
};
|
||||
|
||||
// update the number of cached tiles and detect local storage support
|
||||
function updateStatus() {
|
||||
if (window.localStorage) {
|
||||
status.innerHTML = localStorage.length + " entries in cache.";
|
||||
} else {
|
||||
status.innerHTML = "Local storage not supported. Try a different browser.";
|
||||
}
|
||||
}
|
||||
}
|
||||
44
examples/offline-storage.html
Normal file
44
examples/offline-storage.html
Normal file
@@ -0,0 +1,44 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<title>OpenLayers Offline Storage Example</title>
|
||||
<link rel="stylesheet" href="../theme/default/style.css" type="text/css">
|
||||
<link rel="stylesheet" href="style.css" type="text/css">
|
||||
<style type="text/css">
|
||||
.olControlAttribution {
|
||||
bottom: 0;
|
||||
}
|
||||
</style>
|
||||
<script src="../lib/OpenLayers.js"></script>
|
||||
<script>OpenLayers.Console = window.console;</script>
|
||||
<script src="offline-storage.js"></script>
|
||||
</head>
|
||||
<body onload="init()">
|
||||
<h1 id="title">Offline Storage Example</h1>
|
||||
|
||||
<div id="tags">
|
||||
local storage, persistence, cache, html5
|
||||
</div>
|
||||
|
||||
<div id="shortdesc">Caching viewed tiles</div>
|
||||
|
||||
<div id="map" class="smallmap"></div>
|
||||
<div>Cache status: <span id="hits"></span> <span id="status"></span></div>
|
||||
<div><input id="read" type="checkbox">Read from cache [<input id="tileloadstart" name="type" type="radio">try cache first] [<input id="tileerror" name="type" type="radio">try online first<sup>1</sup>]</div>
|
||||
<div><input id="write" type="checkbox">Write to cache</div>
|
||||
<div><button id="clear">Clear cached tiles</button><button id="seed">Seed current extent</button>
|
||||
<br>
|
||||
<p><sup>1</sup> <small>Disconnect your device from the network to test - only works for same origin layers.</small></p>
|
||||
<br>
|
||||
<div id="docs">
|
||||
<p>This example shows how to use the CacheWrite control to cache tiles
|
||||
that are being viewed in the browser's local storage, and how to use
|
||||
the CacheRead control to use cached tiles when offline or on a slow
|
||||
connection. See <a href="offline-storage.js">offline-storage.js</a>
|
||||
for the source code.</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
199
examples/offline-storage.js
Normal file
199
examples/offline-storage.js
Normal file
@@ -0,0 +1,199 @@
|
||||
// Use proxy to get same origin URLs for tiles that don't support CORS.
|
||||
OpenLayers.ProxyHost = "proxy.cgi?url=";
|
||||
|
||||
var map, cacheWrite, cacheRead1, cacheRead2;
|
||||
|
||||
function init() {
|
||||
map = new OpenLayers.Map({
|
||||
div: "map",
|
||||
projection: "EPSG:900913",
|
||||
layers: [
|
||||
new OpenLayers.Layer.OSM("OpenStreetMap (CORS)", null, {
|
||||
eventListeners: {
|
||||
tileloaded: updateStatus,
|
||||
loadend: detect
|
||||
}
|
||||
}),
|
||||
new OpenLayers.Layer.WMS("OSGeo (same origin - proxied)", "http://vmap0.tiles.osgeo.org/wms/vmap0", {
|
||||
layers: "basic"
|
||||
}, {
|
||||
eventListeners: {
|
||||
tileloaded: updateStatus
|
||||
}
|
||||
})
|
||||
],
|
||||
center: [0, 0],
|
||||
zoom: 1
|
||||
});
|
||||
// try cache before loading from remote resource
|
||||
cacheRead1 = new OpenLayers.Control.CacheRead({
|
||||
eventListeners: {
|
||||
activate: function() {
|
||||
cacheRead2.deactivate();
|
||||
}
|
||||
}
|
||||
});
|
||||
// try loading from remote resource and fall back to cache
|
||||
cacheRead2 = new OpenLayers.Control.CacheRead({
|
||||
autoActivate: false,
|
||||
fetchEvent: "tileerror",
|
||||
eventListeners: {
|
||||
activate: function() {
|
||||
cacheRead1.deactivate();
|
||||
}
|
||||
}
|
||||
});
|
||||
cacheWrite = new OpenLayers.Control.CacheWrite({
|
||||
imageFormat: "image/jpeg",
|
||||
eventListeners: {
|
||||
cachefull: function() {
|
||||
if (seeding) {
|
||||
stopSeeding();
|
||||
}
|
||||
status.innerHTML = "Cache full.";
|
||||
}
|
||||
}
|
||||
});
|
||||
var layerSwitcher = new OpenLayers.Control.LayerSwitcher();
|
||||
map.addControls([cacheRead1, cacheRead2, cacheWrite, layerSwitcher]);
|
||||
layerSwitcher.maximizeControl();
|
||||
|
||||
|
||||
|
||||
// add UI and behavior
|
||||
var status = document.getElementById("status"),
|
||||
hits = document.getElementById("hits"),
|
||||
cacheHits = 0,
|
||||
seeding = false;
|
||||
var read = document.getElementById("read");
|
||||
read.checked = true;
|
||||
read.onclick = toggleRead;
|
||||
var write = document.getElementById("write");
|
||||
write.checked = false;
|
||||
write.onclick = toggleWrite;
|
||||
document.getElementById("clear").onclick = clearCache;
|
||||
var tileloadstart = document.getElementById("tileloadstart");
|
||||
tileloadstart.checked = "checked";
|
||||
tileloadstart.onclick = setType;
|
||||
document.getElementById("tileerror").onclick = setType;
|
||||
document.getElementById("seed").onclick = startSeeding;
|
||||
|
||||
// detect what the browser supports
|
||||
function detect(evt) {
|
||||
// detection is only done once, so we remove the listener.
|
||||
evt.object.events.unregister("loadend", null, detect);
|
||||
var tile = map.baseLayer.grid[0][0];
|
||||
try {
|
||||
var canvasContext = tile.getCanvasContext();
|
||||
if (canvasContext) {
|
||||
// will throw an exception if CORS image requests are not supported
|
||||
canvasContext.canvas.toDataURL();
|
||||
} else {
|
||||
status.innerHTML = "Canvas not supported. Try a different browser.";
|
||||
}
|
||||
} catch(e) {
|
||||
// we remove the OSM layer if CORS image requests are not supported.
|
||||
map.setBaseLayer(map.layers[1]);
|
||||
evt.object.destroy();
|
||||
layerSwitcher.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
// update the number of cache hits and detect missing CORS support
|
||||
function updateStatus(evt) {
|
||||
if (window.localStorage) {
|
||||
status.innerHTML = localStorage.length + " entries in cache.";
|
||||
} else {
|
||||
status.innerHTML = "Local storage not supported. Try a different browser.";
|
||||
}
|
||||
if (evt && evt.tile.url.substr(0, 5) === "data:") {
|
||||
cacheHits++;
|
||||
}
|
||||
hits.innerHTML = cacheHits + " cache hits.";
|
||||
}
|
||||
|
||||
// turn the cacheRead controls on and off
|
||||
function toggleRead() {
|
||||
if (!this.checked) {
|
||||
cacheRead1.deactivate();
|
||||
cacheRead2.deactivate();
|
||||
} else {
|
||||
setType();
|
||||
}
|
||||
}
|
||||
|
||||
// turn the cacheWrite control on and off
|
||||
function toggleWrite() {
|
||||
cacheWrite[cacheWrite.active ? "deactivate" : "activate"]();
|
||||
}
|
||||
|
||||
// clear all tiles from the cache
|
||||
function clearCache() {
|
||||
OpenLayers.Control.CacheWrite.clearCache();
|
||||
updateStatus();
|
||||
}
|
||||
|
||||
// activate the cacheRead control that matches the desired fetch strategy
|
||||
function setType() {
|
||||
if (tileloadstart.checked) {
|
||||
cacheRead1.activate();
|
||||
} else {
|
||||
cacheRead2.activate();
|
||||
}
|
||||
}
|
||||
|
||||
// start seeding the cache
|
||||
function startSeeding() {
|
||||
var layer = map.baseLayer,
|
||||
zoom = map.getZoom();
|
||||
seeding = {
|
||||
zoom: zoom,
|
||||
extent: map.getExtent(),
|
||||
center: map.getCenter(),
|
||||
cacheWriteActive: cacheWrite.active,
|
||||
buffer: layer.buffer,
|
||||
layer: layer
|
||||
};
|
||||
// make sure the next setCenter triggers a load
|
||||
map.zoomTo(zoom === layer.numZoomLevels-1 ? zoom - 1 : zoom + 1);
|
||||
// turn on cache writing
|
||||
cacheWrite.activate();
|
||||
// turn off cache reading
|
||||
cacheRead1.deactivate();
|
||||
cacheRead2.deactivate();
|
||||
|
||||
layer.events.register("loadend", null, seed);
|
||||
|
||||
// start seeding
|
||||
map.setCenter(seeding.center, zoom);
|
||||
}
|
||||
|
||||
// seed a zoom level based on the extent at the time startSeeding was called
|
||||
function seed() {
|
||||
var layer = seeding.layer;
|
||||
var tileWidth = layer.tileSize.w;
|
||||
var nextZoom = map.getZoom() + 1;
|
||||
var extentWidth = seeding.extent.getWidth() / map.getResolutionForZoom(nextZoom);
|
||||
// adjust the layer's buffer size so we don't have to pan
|
||||
layer.buffer = Math.ceil((extentWidth / tileWidth - map.getSize().w / tileWidth) / 2);
|
||||
map.zoomIn();
|
||||
if (nextZoom === layer.numZoomLevels-1) {
|
||||
stopSeeding();
|
||||
}
|
||||
}
|
||||
|
||||
// stop seeding (when done or when cache is full)
|
||||
function stopSeeding() {
|
||||
// we're done - restore previous settings
|
||||
seeding.layer.events.unregister("loadend", null, seed);
|
||||
seeding.layer.buffer = seeding.buffer;
|
||||
map.setCenter(seeding.center, seeding.zoom);
|
||||
if (!seeding.cacheWriteActive) {
|
||||
cacheWrite.deactivate();
|
||||
}
|
||||
if (read.checked) {
|
||||
setType();
|
||||
}
|
||||
seeding = false;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user