Adding CacheRead and CacheWrite controls.

These controls read from and write to the browser's offline storage. Example with a seeding tool included.
This commit is contained in:
ahocevar
2012-03-08 14:18:44 +01:00
parent 0566b0a5bb
commit f18ac9911b
8 changed files with 761 additions and 0 deletions
+43
View File
@@ -0,0 +1,43 @@
<!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 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>
+183
View File
@@ -0,0 +1,183 @@
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: {
loadend: updateLayerInfo,
tileloaded: updateTileInfo,
tileerror: updateTileInfo
}
}),
new OpenLayers.Layer.WMS("OSGeo (same origin - proxied)", "http://vmap0.tiles.osgeo.org/wms/vmap0", {
layers: "basic"
}, {
eventListeners: {
tileloadstart: function(evt) {
// send requests through proxy
evt.tile.url = "proxy.cgi?url=" + encodeURIComponent(evt.tile.url);
},
loadend: updateLayerInfo,
tileloaded: updateTileInfo
}
})
],
center: [0,0],
zoom: 1
});
cacheWrite = new OpenLayers.Control.CacheWrite({
imageFormat: "image/jpeg",
eventListeners: {
cachefull: function() {
status.innerHTML = "Cache full.";
cacheFull = true;
}
}
});
// 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();
}
}
});
var layerSwitcher = new OpenLayers.Control.LayerSwitcher();
map.addControls([cacheWrite, cacheRead1, cacheRead2, layerSwitcher]);
layerSwitcher.maximizeControl();
// add UI and behavior
var status = document.getElementById("status"),
hits = document.getElementById("hits"),
previousCount = -1,
cacheHits = 0,
cacheFull = false;
updateLayerInfo();
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 = seedCache;
// update the number of cached tiles and detect local storage support
function updateLayerInfo(evt) {
if (window.localStorage) {
if (previousCount !== localStorage.length) {
status.innerHTML = localStorage.length + " entries in cache.";
}
previousCount = localStorage.length;
} else {
status.innerHTML = "Local storage not supported. Try a different browser.";
}
}
// update the number of cache hits and detect missing CORS support
function updateTileInfo(evt) {
if (cacheWrite.active) {
try {
var canvasContext = evt.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) {
status.innerHTML = "CORS image requests not supported. Try a different layer.";
}
}
if (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();
cacheFull = false;
updateLayerInfo();
}
// activate the cacheRead control that matches the desired fetch strategy
function setType() {
if (tileloadstart.checked) {
cacheRead1.activate();
} else {
cacheRead2.activate();
}
}
// seed the cache
function seedCache() {
var zoom = map.getZoom();
var extent = map.getExtent();
var center = map.getCenter();
var active = cacheWrite.active;
var tileWidth = map.baseLayer.tileSize.w;
var layer = map.baseLayer;
var buffer = layer.buffer;
// 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", this, function next() {
var nextZoom = map.getZoom() + 1;
var extentWidth = 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 (cacheFull || nextZoom === layer.numZoomLevels-1) {
// we're done - restore previous settings
layer.events.unregister("loadend", this, next);
layer.buffer = buffer;
map.setCenter(center, zoom);
if (!active) {
cacheWrite.deactivate();
}
if (read.checked) {
setType();
}
}
});
// start seeding
map.setCenter(center, zoom);
}
}