mirror of
https://github.com/Esri/offline-editor-js.git
synced 2025-12-15 15:20:05 +00:00
380 lines
14 KiB
HTML
380 lines
14 KiB
HTML
<!DOCTYPE html>
|
|
<html manifest="appcache-tiles.appcache">
|
|
<head>
|
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
|
<meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no"/>
|
|
|
|
<!--
|
|
|
|
This sample demonstrates using an application manifest to store tiles locally.
|
|
|
|
The use cases for using this sample are to ensure you can reload and restart you application
|
|
one it is offline.
|
|
|
|
It is strongly recommended that you use your own optimized build of the ArcGIS API for JavaScript
|
|
using the Web Optimizer: http://jso.arcgis.com/. You can reference the CDN or host it on your
|
|
own web server.
|
|
|
|
Use the included Grunt task to help generate the manifest file. There is manual
|
|
work involved in determining which files need to go into the manifest. The included manifest
|
|
file should work with this sample to give you an idea of what goes into the manifest.
|
|
|
|
A few things to know about manifest files:
|
|
- You cannot load an online url that has a redirect.
|
|
- If there is an error encountered, the manifest file will stop loading
|
|
- The /utils/appCacheManager.js library will auto detect if the manifest changed and
|
|
ask if you want to reload the application.
|
|
|
|
-->
|
|
|
|
<title>Cache Tiles</title>
|
|
<link rel="stylesheet" href="http://js.arcgis.com/3.9/js/esri/css/esri.css">
|
|
<style>
|
|
html, body, #map {
|
|
height: 100%;
|
|
width: 100%;
|
|
margin: 0;
|
|
padding: 0;
|
|
}
|
|
body {
|
|
background-color: #FFF;
|
|
overflow: hidden;
|
|
font-family: "Trebuchet MS";
|
|
}
|
|
#button-div1{
|
|
position: relative;
|
|
background: #000000;
|
|
color: #ffffff;
|
|
width: 100%;
|
|
height: 50px;
|
|
}
|
|
.basic-btn{
|
|
background-color: #000000;
|
|
border-color: #ffffff 1px;
|
|
color: #ffffff;
|
|
padding: 8px;
|
|
position: relative; float: left;
|
|
}
|
|
#img-offline-indicator{
|
|
padding: 8px;
|
|
position: relative; float: right;
|
|
}
|
|
#tile-info{
|
|
background-color: #000000;
|
|
color: white;
|
|
padding: 8px;
|
|
position: relative; float: right;
|
|
}
|
|
</style>
|
|
<script>
|
|
var locationPath = location.pathname.replace(/\/[^/]+$/, "");
|
|
var dojoConfig = {
|
|
paths: {
|
|
tiles: locationPath + "/../lib/tiles",
|
|
vendor: locationPath + "/../vendor",
|
|
utils: locationPath + "/../utils"
|
|
}
|
|
}
|
|
</script>
|
|
<!-- This is a custom build of the ArcGIS API for JavaScript using the new Web Optimizer Tool -->
|
|
<script src="http://js.arcgis.com/o/agup_hack4co/appcache2/dojo/dojo.js" data-dojo-config="async: true"></script>
|
|
<!-- Use this tag below if you are hosting your ArcGIS API for JavaScript files locally -->
|
|
<!--<script src="libs/dojo/dojo/dojo.js" data-dojo-config="async: true"></script>-->
|
|
<script src="../vendor/IndexedDBShim/dist/IndexedDBShim.min.js"></script>
|
|
<script src="../vendor/offline/offline.min.js"></script>
|
|
<script>
|
|
Offline.options = {
|
|
checks: {
|
|
image: {
|
|
url: function() {
|
|
return 'http://esri.github.io/offline-editor-js/tiny-image.png?_=' + (Math.floor(Math.random() * 1000000000));
|
|
}
|
|
},
|
|
active: 'image'
|
|
}
|
|
}
|
|
</script>
|
|
</head>
|
|
|
|
<body>
|
|
<div id="button-div1">
|
|
<img id="img-offline-indicator" src="../samples/images/blue-pin.png"/>
|
|
<textarea contenteditable="false" id="tile-info"></textarea>
|
|
<button class="basic-btn" id="btn-get-tiles">1. Download Tiles</button>
|
|
<button class="basic-btn" id="btn-online-offline">2. Go Offline</button>
|
|
<button class="basic-btn" id="btn-zoom-out" onclick="panLeft()">3. Pan left</button>
|
|
</div>
|
|
<div id="map"></div>
|
|
|
|
<script>
|
|
var map,offlineTileEnabler,baseMapLayer,zoom = 18;
|
|
var globalState = {};
|
|
var _wantToCancel;
|
|
var _isOnline = true;
|
|
var minZoomAdjust = -1, maxZoomAdjust = 1, mMinZoom, mMaxZoom;
|
|
var imgOfflineIndicator,btnGetTiles,btnOnlineOffline,btnZoom;
|
|
var tiles,appCacheManager,tileInfo;
|
|
var redPinPath = "../samples/images/red-pin.png";
|
|
var bluePinPath = "../samples/images/blue-pin.png"
|
|
var EXTENT_BUFFER = 0; //buffers the map extent in meters
|
|
|
|
require(["esri/map","utils/appCacheManager","tiles/offlineTilesEnabler","dojo/on","dojo/domReady!"],
|
|
function(Map,AppCacheManager,OfflineTileEnabler,on) {
|
|
|
|
imgOfflineIndicator = document.getElementById("img-offline-indicator");
|
|
imgOfflineIndicator.offlineColor = "blue";
|
|
|
|
Offline.check();
|
|
Offline.on('up down', updateState );
|
|
|
|
/**
|
|
* There have been a few bugs in the offline detection library (offline.min.js)
|
|
* This is a utility check to 100% validate if the application is online or
|
|
* offline prior to launching any map functionality.
|
|
*/
|
|
verifyOnline(function(result){ console.log("VERIFY ONLINE " + result)
|
|
result == true ? _isOnline = true : _isOnline = false;
|
|
startMap();
|
|
|
|
})
|
|
|
|
function startMap(){
|
|
//Make sure map shows up after a browser refresh
|
|
Offline.state === 'up' ? zoom = 18 : zoom = 17;
|
|
|
|
map = new Map("map", {
|
|
basemap: "topo",
|
|
center: [-122.45,37.75], // long, lat
|
|
zoom: zoom,
|
|
sliderStyle: "small"
|
|
});
|
|
|
|
map.on("load",function(evt){
|
|
init();
|
|
initOfflineTileEnabler();
|
|
console.log("level: " + map.getLevel() + ", maxZoom: " + map.getMaxZoom());
|
|
})
|
|
}
|
|
|
|
function init(){
|
|
map.on("extent-change",function(evt){
|
|
updateOfflineUsage();
|
|
console.log("Zoom level = " + map.getLevel())
|
|
});
|
|
|
|
appCacheManager = new AppCacheManager(true,true);
|
|
appCacheManager.on(appCacheManager.CACHE_EVENT,cacheEventHandler);
|
|
appCacheManager.on(appCacheManager.CACHE_ERROR,cacheErrorHandler);
|
|
appCacheManager.on(appCacheManager.CACHE_LOADED,cacheLoaderHandler);
|
|
|
|
btnGetTiles = document.getElementById("btn-get-tiles");
|
|
btnOnlineOffline = document.getElementById("btn-online-offline");
|
|
|
|
btnZoom = document.getElementById("btn-zoom-out");
|
|
|
|
tileInfo = document.getElementById("tile-info")
|
|
tileInfo.innerHTML = "Tile count: 0\r\nBytes: 0";
|
|
|
|
map.reposition();
|
|
map.resize();
|
|
}
|
|
|
|
function initOfflineTileEnabler(){
|
|
|
|
mMaxZoom = map.getMaxZoom();
|
|
mMinZoom = map.getMinZoom();
|
|
|
|
offlineTileEnabler = new OfflineTileEnabler();
|
|
baseMapLayer = offlineTileEnabler.getBasemapLayer(map); console.log("Offline State: " + Offline.state)
|
|
|
|
offlineTileEnabler.extend(baseMapLayer,function(success)
|
|
{
|
|
if( success )
|
|
{
|
|
console.log("Offline tile lib is enabled. Application state is: " + Offline.state);
|
|
Offline.check();
|
|
|
|
//using null sets this for CORS
|
|
baseMapLayer.offline.proxyPath = null;
|
|
|
|
on(btnOnlineOffline,"click",goOnlineOffline);
|
|
on(btnGetTiles,"click",downloadTiles);
|
|
|
|
updateOfflineUsage();
|
|
}
|
|
else
|
|
{
|
|
alert("error initializing storage - browser doesn't support indexeddb or websql")
|
|
}
|
|
}.bind(this),_isOnline);
|
|
}
|
|
|
|
function updateState(){
|
|
if(Offline.state === 'up'){
|
|
updateOfflineUsage();
|
|
imgOfflineIndicator.src = bluePinPath;
|
|
if(typeof baseMapLayer != "undefined") baseMapLayer.goOnline();
|
|
}
|
|
else{
|
|
imgOfflineIndicator.src = redPinPath;
|
|
if(typeof baseMapLayer != "undefined") baseMapLayer.goOffline();
|
|
}
|
|
}
|
|
|
|
function updateOfflineUsage()
|
|
{
|
|
baseMapLayer.offline.store.usedSpace(function(result,err){
|
|
if(result != null){
|
|
tileInfo.innerHTML = "DB Tile count: " + result.tileCount + "\r\nDB Bytes: " + result.sizeBytes;
|
|
}
|
|
else{
|
|
tileInfo.innerHTML = "DB Tile count: " + count + "\r\nDB Bytes: Error";
|
|
}
|
|
})
|
|
}
|
|
|
|
/**
|
|
* Utility function to validate min and max zoom settings of the map
|
|
*/
|
|
function getMinMaxZoom(){
|
|
|
|
var zoom = {};
|
|
var min = map.getLevel() + minZoomAdjust;
|
|
var max = map.getLevel() + maxZoomAdjust;
|
|
zoom.max = Math.min(mMaxZoom, max); //prevent errors by setting the tile layer floor
|
|
zoom.min = Math.max(mMinZoom, min); //prevent errors by setting the tile layer ceiling
|
|
|
|
return zoom;
|
|
}
|
|
|
|
/**
|
|
* Reports the process while downloading tiles.
|
|
*/
|
|
function reportProgress(progress)
|
|
{
|
|
console.log("downloading tiles...");
|
|
if(progress.hasOwnProperty("countNow")){
|
|
var percent = Math.floor(progress.countNow / progress.countMax * 100);
|
|
btnGetTiles.innerHTML = 'Saving to phone ' + percent + "% - Tap to Cancel";
|
|
}
|
|
|
|
if( progress.finishedDownloading )
|
|
{
|
|
btnGetTiles.innerHTML = "Saving to phone 100% - Tap to Cancel";
|
|
updateOfflineUsage();
|
|
|
|
if( progress.cancelRequested )
|
|
{
|
|
globalState.downloadState = 'cancelled';
|
|
alert("Tile download was cancelled");
|
|
}
|
|
else
|
|
{
|
|
globalState.downloadState = 'downloaded';
|
|
alert("Tile download complete");
|
|
}
|
|
|
|
btnGetTiles.innerHTML = '1. Download Tiles';
|
|
}
|
|
return _wantToCancel; //determines if a cancel request has been issued
|
|
}
|
|
|
|
/**
|
|
* Forces offlineTileEnabler to go online or offline.
|
|
* If it is offline it will try to find a tile in the local database.
|
|
*/
|
|
function goOnlineOffline(){
|
|
if(imgOfflineIndicator.offlineColor == "blue"){
|
|
btnOnlineOffline.innerHTML = "2. Go Online";
|
|
imgOfflineIndicator.src = redPinPath;
|
|
imgOfflineIndicator.offlineColor = "red";
|
|
baseMapLayer.goOffline();
|
|
}
|
|
else{
|
|
btnOnlineOffline.innerHTML = "2. Go Offline";
|
|
imgOfflineIndicator.src = bluePinPath;
|
|
imgOfflineIndicator.offlineColor = "blue";
|
|
baseMapLayer.goOnline();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Manually starts the process to download and store tiles
|
|
* in the local database
|
|
*/
|
|
function downloadTiles(){
|
|
baseMapLayer.deleteAllTiles(function(success,err){
|
|
if(success == false){
|
|
alert("There was a problem deleting the tile cache");
|
|
}
|
|
else{
|
|
console.log("success deleting tile cache");
|
|
var self = this.data;
|
|
|
|
if( globalState.downloadState == 'downloading')
|
|
{
|
|
console.log("cancel!");
|
|
_wantToCancel = true;
|
|
btnGetTiles.innerHTML = "cancelling..";
|
|
}
|
|
else
|
|
{
|
|
var zoom = getMinMaxZoom();
|
|
|
|
var extent = baseMapLayer.getExtentBuffer(EXTENT_BUFFER,map.extent);
|
|
_wantToCancel = false;
|
|
baseMapLayer.prepareForOffline(zoom.min, zoom.max, extent, reportProgress.bind(this));
|
|
globalState.downloadState = 'downloading';
|
|
}
|
|
}
|
|
}.bind(this))
|
|
}
|
|
|
|
/**
|
|
* Attempts an http request to verify if app is online or offline.
|
|
* Use this in conjunction with the offline checker library: offline.min.js
|
|
* @param callback
|
|
*/
|
|
function verifyOnline(callback){
|
|
var req = new XMLHttpRequest();
|
|
req.open("GET", "images/blue-pin.png?" + (Math.floor(Math.random() * 1000000000)), true);
|
|
req.onload = function()
|
|
{
|
|
if( req.status === 200 && req.responseText !== "")
|
|
{
|
|
callback(true);
|
|
}
|
|
else
|
|
{
|
|
console.log("verifyOffline failed");
|
|
callback(false);
|
|
}
|
|
};
|
|
req.onerror = function(e)
|
|
{
|
|
console.log("verifyOffline failed: " + e);
|
|
callback(false);
|
|
};
|
|
req.send(null);
|
|
}
|
|
|
|
function cacheLoaderHandler(evt){
|
|
if(evt == appCacheManager.CACHE_LOADED) console.log("Application cache successfully loaded!")
|
|
}
|
|
|
|
function cacheEventHandler(evt){
|
|
console.log("CACHE EVENT: " + JSON.stringify(evt));
|
|
}
|
|
|
|
function cacheErrorHandler(evt){
|
|
console.log("CACHE ERROR: " + JSON.stringify(evt));
|
|
}
|
|
}
|
|
);
|
|
|
|
function panLeft(){
|
|
map.panLeft();
|
|
}
|
|
</script>
|
|
|
|
</body> |