more url reference changes in tiles/src. Added sample director. New sample that lets you save tiles to a download csv.

This commit is contained in:
andygup 2013-12-16 23:18:32 -07:00
parent 42c5a9b777
commit 1ed5ad3e34
6 changed files with 592 additions and 13 deletions

View File

@ -0,0 +1,180 @@
<!doctype html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="">
<meta name="author" content="">
<link rel="shortcut icon" href="../vendor/bootstrap-map-js/bootstrap_v3/docs-assets/ico/favicon.png">
<link rel="stylesheet" href="//js.arcgis.com/3.7/js/esri/css/esri.css">
<link rel="stylesheet" href="../vendor/bootstrap-map-js/bootstrap_v3/dist/css/bootstrap.css" >
<link rel="stylesheet" href="../vendor/bootstrap-map-js/src/css/bootstrapmap.css">
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.css" >
<link rel="stylesheet" href="../tiles/offlineProbe.css" >
<link rel="stylesheet" href="../tiles/style.css" >
<!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
<!--[if lt IE 9]>
<script src="../vendor/bootstrap-map-js/bootstrap_v3/docs-assets/js/html5shiv.js"></script>
<script src="../vendor/bootstrap-map-js/bootstrap_v3/docs-assets/js/respond.min.js"></script>
<![endif]-->
<title>Offline</title>
</head>
<body>
<div class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="http://github.com/Esri/offline-editor-js"><i class="fa fa-html5"></i> JS Offline Mapping</s>
<a class="navbar-brand" href="http://developers.arcgis.com"><i class="fa fa-globe"></i> esri</a>
</div>
<!--
<div class="collapse navbar-collapse">
<ul class="nav navbar-nav">
<li class="active"><a href="#">Home</a></li>
<li><a href="#about">About</a></li>
<li><a href="#contact">Contact</a></li>
</ul>
</div>
--><!--/.nav-collapse -->
</div>
</div>
<div class="container">
<div class="row">
<div class="col-sm-4">
</div>
<div class="col-sm-8">
<h3>Map:<span id="mapTitle">[none]</span></h3>
</div>
</div>
<div class="row">
<div class="col-sm-4">
<form role="form">
<div class="form-group">
<label class="control-label" for="minLevel">Min Zoom Level</label>
<input type="number" id="minLevel" name"minLevel" class="form-control" value=1 min=0 max=19>
</div>
<div class="form-group">
<label class="control-label" for="currentLevel">Current Zoom Level</label>
<input type="number" id="currentLevel" name"currentLevel" class="form-control" value=19 min=0 max=19>
</div>
<div class="form-group">
<label class="control-label" for="maxLevel">Max Zoom Level</label>
<input type="number" id="maxLevel" name"maxLevel" class="form-control" value=19 min=0 max=19>
</div>
</form>
<table id="tile-count-table" class="table table-striped table-condensed table-hover">
<thead>
<tr>
<th>Level</th>
<th>Tile Count</th>
<th>Size Mb (aprox.)</th>
</tr>
</thead>
<tbody id="tile-count-table-body">
</tbody>
</table>
</div>
<div class="col-sm-8">
<!-- Bootstrap-map-js -->
<div id="mapDiv"></div>
</div>
</div>
<div class="row">
<div id="ready-to-download-ui">
<div class="col-xs-12">
<button id="prepare-for-offline-btn" type="button" class="btn btn-primary"><i class="glyphicon glyphicon-cloud-download"></i> Prepare for Offline</button>
<button id="delete-all-tiles-btn" type="button" class="btn btn-danger"><i class="glyphicon glyphicon-floppy-remove"></i> Delete All Tiles</button>
<button id="go-offline-btn" type="button" class="btn btn-default"><i class="fa fa-chain-broken"></i> Go Offline</button>
<button id="go-online-btn" type="button" class="btn btn-default" disabled="disabled"><i class="fa fa-link"></i> Go Online</button>
<button id="update-offline-usage" type="button" class="btn btn-default"><i class="fa fa-refresh"></i> Usage: <span id="offline-usage">[click to update]</span></button>
<button id="show-stored-tiles" type="button" class="btn btn-default"><i class="fa fa-th"></i> <span id="show-stored-tiles-caption">Show Stored Tiles</span></button>
<button id="save-file" type="button" onclick="saveFile()" class="btn btn-default"><i class="glyphicon glyphicon-folder-open"></i> <span id="save-file-caption"> Save to File</span></button>
</div>
</div>
<div id="downloading-ui">
<div class="col-xs-1">
<button id="cancel-btn" type="button" class="btn btn-warning"><i class="glyphicon glyphicon-remove"></i> Cancel</button>
</div>
<div id="download-progress" class="col-xs-10">
<div class="progress progress-striped active">
<div class="progress-bar progress-bar-success" role="progressbar" style="width:0%;"></div>
</div>
</div>
<div id="remaining-time" class="col-xs-1">__:__</div>
</div>
</div>
<hr>
<div class="row">
<div class="col-xs-12 col-sm-4">
<div class="well lead step-1"><i class="fa fa-arrows"></i> 1. Navigate to your area of interest</div>
</div>
<div class="col-xs-12 col-sm-4">
<div class="well lead step-2"><i class="glyphicon glyphicon-cloud-download"></i> 2. Click 'Prepare for Offline' button</div>
</div>
<div class="col-xs-12 col-sm-4">
<div class="well lead step-3"><i class="fa fa-chain-broken"></i> 3. Go Offline and enjoy!</div>
</div>
</div>
</div><!-- /.container -->
<script src="//js.arcgis.com/3.7compact"></script>
<script src="../vendor/offline/offline.min.js"></script>
<script src="../vendor/IndexedDBShim/dist/IndexedDBShim.min.js"></script>
<script src="../tiles/offlineProbe.js"></script>
<script src="../tiles/main.js"></script>
<script src="../tiles/src/FileSaver.js"></script>
<script src="../tiles/src/Blog.js"></script>
<script>
function saveFile(){
require(["/offline/tiles/src/dbStore.js"],function(DBStore)
{ console.log('test')
var db = new DBStore();
db.init(function(result,val){
console.log(result + ", " + val)
var csv = "url,img,\r\n";
if(result == true){
db.getAllTiles(function(url,img,evt){
// console.log(url + ", " + img);
csv+= url + "," +img+"\r\n";
if(evt == "end"){
console.log(csv)
var blob = new Blob([csv], {type: "text/plain;charset=utf-8"});
saveAs(blob, "tiles.csv");
}
})
}
})
})
}
</script>
<!-- Bootstrap core JavaScript
================================================== -->
<!-- Placed at the end of the document so the pages load faster -->
<!--
<script src="../vendor/bootstrap-map-js/bootstrap_v3/docs-assets/js/jquery.js"></script>
<script src="../vendor/bootstrap-map-js/bootstrap_v3/dist/js/bootstrap.min.js"></script>
-->
</body>
</html>

View File

@ -12,7 +12,7 @@ require(["esri/map",
"dojo/dom", "dojo/on", "dojo/query",
"../vendor/bootstrap-map-js/src/js/bootstrapmap.js",
"esri/urlUtils", "esri/geometry/webMercatorUtils",
"src/offlineEnabler.js",
"/offline/tiles/src/offlineEnabler.js",
"dojo/dom-construct", "dojo/domReady!"],
function(Map,
GraphicsLayer, Graphic, SimpleFillSymbol,

166
tiles/src/Blob.js Normal file
View File

@ -0,0 +1,166 @@
/* Blob.js
* A Blob implementation.
* 2013-06-20
*
* By Eli Grey, http://eligrey.com
* By Devin Samarin, https://github.com/eboyjr
* License: X11/MIT
* See LICENSE.md
*/
/*global self, unescape */
/*jslint bitwise: true, regexp: true, confusion: true, es5: true, vars: true, white: true,
plusplus: true */
/*! @source http://purl.eligrey.com/github/Blob.js/blob/master/Blob.js */
if (!(typeof Blob === "function" || typeof Blob === "object") || typeof URL === "undefined")
if ((typeof Blob === "function" || typeof Blob === "object") && typeof webkitURL !== "undefined") self.URL = webkitURL;
else var Blob = (function (view) {
"use strict";
var BlobBuilder = view.BlobBuilder || view.WebKitBlobBuilder || view.MozBlobBuilder || view.MSBlobBuilder || (function(view) {
var
get_class = function(object) {
return Object.prototype.toString.call(object).match(/^\[object\s(.*)\]$/)[1];
}
, FakeBlobBuilder = function BlobBuilder() {
this.data = [];
}
, FakeBlob = function Blob(data, type, encoding) {
this.data = data;
this.size = data.length;
this.type = type;
this.encoding = encoding;
}
, FBB_proto = FakeBlobBuilder.prototype
, FB_proto = FakeBlob.prototype
, FileReaderSync = view.FileReaderSync
, FileException = function(type) {
this.code = this[this.name = type];
}
, file_ex_codes = (
"NOT_FOUND_ERR SECURITY_ERR ABORT_ERR NOT_READABLE_ERR ENCODING_ERR "
+ "NO_MODIFICATION_ALLOWED_ERR INVALID_STATE_ERR SYNTAX_ERR"
).split(" ")
, file_ex_code = file_ex_codes.length
, real_URL = view.URL || view.webkitURL || view
, real_create_object_URL = real_URL.createObjectURL
, real_revoke_object_URL = real_URL.revokeObjectURL
, URL = real_URL
, btoa = view.btoa
, atob = view.atob
, ArrayBuffer = view.ArrayBuffer
, Uint8Array = view.Uint8Array
;
FakeBlob.fake = FB_proto.fake = true;
while (file_ex_code--) {
FileException.prototype[file_ex_codes[file_ex_code]] = file_ex_code + 1;
}
if (!real_URL.createObjectURL) {
URL = view.URL = {};
}
URL.createObjectURL = function(blob) {
var
type = blob.type
, data_URI_header
;
if (type === null) {
type = "application/octet-stream";
}
if (blob instanceof FakeBlob) {
data_URI_header = "data:" + type;
if (blob.encoding === "base64") {
return data_URI_header + ";base64," + blob.data;
} else if (blob.encoding === "URI") {
return data_URI_header + "," + decodeURIComponent(blob.data);
} if (btoa) {
return data_URI_header + ";base64," + btoa(blob.data);
} else {
return data_URI_header + "," + encodeURIComponent(blob.data);
}
} else if (real_create_object_URL) {
return real_create_object_URL.call(real_URL, blob);
}
};
URL.revokeObjectURL = function(object_URL) {
if (object_URL.substring(0, 5) !== "data:" && real_revoke_object_URL) {
real_revoke_object_URL.call(real_URL, object_URL);
}
};
FBB_proto.append = function(data/*, endings*/) {
var bb = this.data;
// decode data to a binary string
if (Uint8Array && (data instanceof ArrayBuffer || data instanceof Uint8Array)) {
var
str = ""
, buf = new Uint8Array(data)
, i = 0
, buf_len = buf.length
;
for (; i < buf_len; i++) {
str += String.fromCharCode(buf[i]);
}
bb.push(str);
} else if (get_class(data) === "Blob" || get_class(data) === "File") {
if (FileReaderSync) {
var fr = new FileReaderSync;
bb.push(fr.readAsBinaryString(data));
} else {
// async FileReader won't work as BlobBuilder is sync
throw new FileException("NOT_READABLE_ERR");
}
} else if (data instanceof FakeBlob) {
if (data.encoding === "base64" && atob) {
bb.push(atob(data.data));
} else if (data.encoding === "URI") {
bb.push(decodeURIComponent(data.data));
} else if (data.encoding === "raw") {
bb.push(data.data);
}
} else {
if (typeof data !== "string") {
data += ""; // convert unsupported types to strings
}
// decode UTF-16 to binary string
bb.push(unescape(encodeURIComponent(data)));
}
};
FBB_proto.getBlob = function(type) {
if (!arguments.length) {
type = null;
}
return new FakeBlob(this.data.join(""), type, "raw");
};
FBB_proto.toString = function() {
return "[object BlobBuilder]";
};
FB_proto.slice = function(start, end, type) {
var args = arguments.length;
if (args < 3) {
type = null;
}
return new FakeBlob(
this.data.slice(start, args > 1 ? end : this.data.length)
, type
, this.encoding
);
};
FB_proto.toString = function() {
return "[object Blob]";
};
return FakeBlobBuilder;
}(view));
return function Blob(blobParts, options) {
var type = options ? (options.type || "") : "";
var builder = new BlobBuilder();
if (blobParts) {
for (var i = 0, len = blobParts.length; i < len; i++) {
builder.append(blobParts[i]);
}
}
return builder.getBlob(type);
};
}(self));

232
tiles/src/FileSaver.js Normal file
View File

@ -0,0 +1,232 @@
/* FileSaver.js
* A saveAs() FileSaver implementation.
* 2013-10-21
*
* By Eli Grey, http://eligrey.com
* License: X11/MIT
* See LICENSE.md
*/
/*global self */
/*jslint bitwise: true, regexp: true, confusion: true, es5: true, vars: true, white: true,
plusplus: true */
/*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/FileSaver.js */
var saveAs = saveAs
|| (typeof navigator !== 'undefined' && navigator.msSaveOrOpenBlob && navigator.msSaveOrOpenBlob.bind(navigator))
|| (function(view) {
"use strict";
var
doc = view.document
// only get URL when necessary in case BlobBuilder.js hasn't overridden it yet
, get_URL = function() {
return view.URL || view.webkitURL || view;
}
, URL = view.URL || view.webkitURL || view
, save_link = doc.createElementNS("http://www.w3.org/1999/xhtml", "a")
, can_use_save_link = !view.externalHost && "download" in save_link
, click = function(node) {
var event = doc.createEvent("MouseEvents");
event.initMouseEvent(
"click", true, false, view, 0, 0, 0, 0, 0
, false, false, false, false, 0, null
);
node.dispatchEvent(event);
}
, webkit_req_fs = view.webkitRequestFileSystem
, req_fs = view.requestFileSystem || webkit_req_fs || view.mozRequestFileSystem
, throw_outside = function (ex) {
(view.setImmediate || view.setTimeout)(function() {
throw ex;
}, 0);
}
, force_saveable_type = "application/octet-stream"
, fs_min_size = 0
, deletion_queue = []
, process_deletion_queue = function() {
var i = deletion_queue.length;
while (i--) {
var file = deletion_queue[i];
if (typeof file === "string") { // file is an object URL
URL.revokeObjectURL(file);
} else { // file is a File
file.remove();
}
}
deletion_queue.length = 0; // clear queue
}
, dispatch = function(filesaver, event_types, event) {
event_types = [].concat(event_types);
var i = event_types.length;
while (i--) {
var listener = filesaver["on" + event_types[i]];
if (typeof listener === "function") {
try {
listener.call(filesaver, event || filesaver);
} catch (ex) {
throw_outside(ex);
}
}
}
}
, FileSaver = function(blob, name) {
// First try a.download, then web filesystem, then object URLs
var
filesaver = this
, type = blob.type
, blob_changed = false
, object_url
, target_view
, get_object_url = function() {
var object_url = get_URL().createObjectURL(blob);
deletion_queue.push(object_url);
return object_url;
}
, dispatch_all = function() {
dispatch(filesaver, "writestart progress write writeend".split(" "));
}
// on any filesys errors revert to saving with object URLs
, fs_error = function() {
// don't create more object URLs than needed
if (blob_changed || !object_url) {
object_url = get_object_url(blob);
}
if (target_view) {
target_view.location.href = object_url;
} else {
window.open(object_url, "_blank");
}
filesaver.readyState = filesaver.DONE;
dispatch_all();
}
, abortable = function(func) {
return function() {
if (filesaver.readyState !== filesaver.DONE) {
return func.apply(this, arguments);
}
};
}
, create_if_not_found = {create: true, exclusive: false}
, slice
;
filesaver.readyState = filesaver.INIT;
if (!name) {
name = "download";
}
if (can_use_save_link) {
object_url = get_object_url(blob);
// FF for Android has a nasty garbage collection mechanism
// that turns all objects that are not pure javascript into 'deadObject'
// this means `doc` and `save_link` are unusable and need to be recreated
// `view` is usable though:
doc = view.document;
save_link = doc.createElementNS("http://www.w3.org/1999/xhtml", "a");
save_link.href = object_url;
save_link.download = name;
var event = doc.createEvent("MouseEvents");
event.initMouseEvent(
"click", true, false, view, 0, 0, 0, 0, 0
, false, false, false, false, 0, null
);
save_link.dispatchEvent(event);
filesaver.readyState = filesaver.DONE;
dispatch_all();
return;
}
// Object and web filesystem URLs have a problem saving in Google Chrome when
// viewed in a tab, so I force save with application/octet-stream
// http://code.google.com/p/chromium/issues/detail?id=91158
if (view.chrome && type && type !== force_saveable_type) {
slice = blob.slice || blob.webkitSlice;
blob = slice.call(blob, 0, blob.size, force_saveable_type);
blob_changed = true;
}
// Since I can't be sure that the guessed media type will trigger a download
// in WebKit, I append .download to the filename.
// https://bugs.webkit.org/show_bug.cgi?id=65440
if (webkit_req_fs && name !== "download") {
name += ".download";
}
if (type === force_saveable_type || webkit_req_fs) {
target_view = view;
}
if (!req_fs) {
fs_error();
return;
}
fs_min_size += blob.size;
req_fs(view.TEMPORARY, fs_min_size, abortable(function(fs) {
fs.root.getDirectory("saved", create_if_not_found, abortable(function(dir) {
var save = function() {
dir.getFile(name, create_if_not_found, abortable(function(file) {
file.createWriter(abortable(function(writer) {
writer.onwriteend = function(event) {
target_view.location.href = file.toURL();
deletion_queue.push(file);
filesaver.readyState = filesaver.DONE;
dispatch(filesaver, "writeend", event);
};
writer.onerror = function() {
var error = writer.error;
if (error.code !== error.ABORT_ERR) {
fs_error();
}
};
"writestart progress write abort".split(" ").forEach(function(event) {
writer["on" + event] = filesaver["on" + event];
});
writer.write(blob);
filesaver.abort = function() {
writer.abort();
filesaver.readyState = filesaver.DONE;
};
filesaver.readyState = filesaver.WRITING;
}), fs_error);
}), fs_error);
};
dir.getFile(name, {create: false}, abortable(function(file) {
// delete file if it already exists
file.remove();
save();
}), abortable(function(ex) {
if (ex.code === ex.NOT_FOUND_ERR) {
save();
} else {
fs_error();
}
}));
}), fs_error);
}), fs_error);
}
, FS_proto = FileSaver.prototype
, saveAs = function(blob, name) {
return new FileSaver(blob, name);
}
;
FS_proto.abort = function() {
var filesaver = this;
filesaver.readyState = filesaver.DONE;
dispatch(filesaver, "abort");
};
FS_proto.readyState = FS_proto.INIT = 0;
FS_proto.WRITING = 1;
FS_proto.DONE = 2;
FS_proto.error =
FS_proto.onwritestart =
FS_proto.onprogress =
FS_proto.onwrite =
FS_proto.onabort =
FS_proto.onerror =
FS_proto.onwriteend =
null;
view.addEventListener("unload", process_deletion_queue, false);
return saveAs;
}(this.self || this.window || this.content));
// `self` is undefined in Firefox for Android content script context
// while `this` is nsIContentFrameMessageManager
// with an attribute `content` that corresponds to the window
if (typeof module !== 'undefined') module.exports = saveAs;

View File

@ -6,7 +6,7 @@
* Author: Andy Gup (@agup)
* Contributor: Javier Abadia (@javierabadia)
*/
define(["src/phoneGapConnector.js"],function(phonegap)
define(["/offline/tiles/src/phoneGapConnector.js"],function(phonegap)
{
var DbStore = function()
{
@ -159,10 +159,10 @@ define(["src/phoneGapConnector.js"],function(phonegap)
/**
* Retrieve all tiles from indexeddb
* @param callback callbakck(url, err)
* @param callback callbakck(url, img, err)
*/
this.getAllTiles = function(callback){
if(this._db != null)
if(this._db.hasOwnProperty("name"))
{
var transaction = this._db.transaction(["tilepath"])
.objectStore("tilepath")
@ -173,20 +173,21 @@ define(["src/phoneGapConnector.js"],function(phonegap)
var cursor = event.target.result;
if(cursor){
var url = cursor.value.url;
callback(url);
var img = cursor.value.img;
callback(url,img,null);
cursor.continue();
}
else{
callback(null, "end");
callback(null, null, "end");
}
}.bind(this);
transaction.onerror = function(err){
callback(null, err);
callback(null, null, err);
}
}
else
{
callback(null, "no db");
callback(null, null, "no db");
}
}

View File

@ -3,9 +3,9 @@
define([
"dojo/query",
"esri/geometry",
"src/base64utils.js",
"src/dbStore.js",
"src/tilingScheme.js"
"/offline//tiles/src/base64utils.js",
"/offline/tiles/src/dbStore.js",
"/offline/tiles/src/tilingScheme.js"
], function(query, geometry,Base64Utils,DbStore,TilingScheme)
{
return {
@ -178,7 +178,7 @@ define([
url = url.split('?')[0];
/* download the tile */
var imgurl = "proxy.php?" + url;
var imgurl = "../tiles/proxy.php?" + url;
var req = new XMLHttpRequest();
req.open("GET", imgurl, true);
req.overrideMimeType("text/plain; charset=x-user-defined"); // https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest?redirectlocale=en-US&redirectslug=DOM%2FXMLHttpRequest%2FUsing_XMLHttpRequest#Handling_binary_data
@ -226,7 +226,7 @@ define([
{
var store = this.offline.store;
var tilingScheme = new TilingScheme(this,geometry);
store.getAllTiles(function(url,err)
store.getAllTiles(function(url,img,err)
{
if(url)
{