"use strict" var map; var basemapLayer; var graphics; var cancelRequested, startTime, errorList; var showTiles = false; require(["esri/map", "esri/layers/GraphicsLayer", "esri/graphic", "esri/symbols/SimpleFillSymbol", "esri/dijit/Scalebar", "esri/arcgis/utils", "esri/geometry", "dojo/dom", "dojo/on", "dojo/query", "vendor/bootstrap-map-js/src/js/bootstrapmap", "esri/urlUtils", "esri/geometry/webMercatorUtils", "tiles/offlineEnabler", "dojo/dom-construct", "dojo/domReady!"], function(Map, GraphicsLayer, Graphic, SimpleFillSymbol, Scalebar, esriUtils, geometry, dom, on, query, BootstrapMap, urlUtils, webMercatorUtils, offlineEnabler, domConstruct) { var scalebar; var symbol; // Load web map when page loads var urlObject = urlUtils.urlToObject(window.location.href); var webmapid; if( urlObject.query && urlObject.query.webmap) webmapid = urlObject.query.webmap; loadWebmap(webmapid); function loadWebmap(webmapid) { webmapid = webmapid || "bbc1a04a3eca4430be144d7a08b43a17"; // Get new webmap and extract map and map parts var mapDeferred = esriUtils.createMap(webmapid, "mapDiv", { mapOptions: { slider: true, nav:false, smartNavigation:false } }); mapDeferred.then(function(response) { map = response.map; // Bind to map BootstrapMap.bindTo(map); // Add title and description dom.byId("mapTitle").innerHTML = response.itemInfo.item.title; dom.byId("mapDescription").innerHTML = response.itemInfo.item.snippet; if(map.loaded) { basemapLayer = map.getLayer( map.layerIds[0] ); initMapParts(); initEvents(); initOffline(); } else { on(map,"load",function() { basemapLayer = map.getLayer( map.layerIds[0] ); initMapParts(); initEvents(); initOffline(); }); } },function(error){ showAlert('alert-danger',"Sorry, couldn't load webmap: " + error.message); console.log("Error loading webmap:",error); }); } function initMapParts() { scalebar = new Scalebar({ map:map, scalebarUnit: 'metric' }); graphics = new GraphicsLayer(); map.addLayer( graphics ); symbol = new SimpleFillSymbol({ "type": "esriSFS", "style": "esriSFSSolid", "color": [255,0,0,5], "outline": { "type": "esriSLS", "style": "esriSLSSolid", "color": [0,0,0,100], "width": 0.5 } }); } function initEvents() { map.on('extent-change', updateTileCountEstimation ); on(dojo.byId('minLevel'),'change', updateTileCountEstimation); on(dojo.byId('maxLevel'),'change', updateTileCountEstimation); dojo.byId('minLevel').value = basemapLayer.minLevel = basemapLayer.tileInfo.lods[0].level; dojo.byId('maxLevel').value = basemapLayer.maxLevel = basemapLayer.tileInfo.lods[basemapLayer.tileInfo.lods.length-1].level; } function initOffline() { console.log("extending"); offlineEnabler.extend(basemapLayer,function(success) { if(success) { basemapLayer.offline.proxyPath = window.proxyPath || "../../lib/proxy.php"; on(dojo.byId('prepare-for-offline-btn'),'click', prepareForOffline); on(dojo.byId('cancel-btn'),'click', cancel); on(dojo.byId('delete-all-tiles-btn'),'click', deleteAllTiles); on(dojo.byId('go-offline-btn'),'click', goOffline); on(dojo.byId('go-online-btn'),'click', goOnline); on(dojo.byId('update-offline-usage'),'click', updateOfflineUsage); on(dojo.byId('show-stored-tiles'),'click', toggleShowStoredTiles); on(dojo.byId('save-file'),'click', saveToFile); on(dojo.byId('file-select'),'change', loadFromFile); dojo.byId('go-online-btn').style.display = "none"; esri.show(dojo.byId('ready-to-download-ui')); esri.hide(dojo.byId('downloading-ui')); updateOfflineUsage(); updateTileCountEstimation(); } else { dojo.byId('prepare-for-offline-btn').disabled = true; dojo.byId('delete-all-tiles-btn').disabled = true; dojo.byId('go-offline-btn').disabled = true; dojo.byId('go-online-btn').disabled = true; esri.hide(dojo.byId('go-online-btn')); dojo.byId('update-offline-usage').disabled = true; dojo.byId('show-stored-tiles').disabled = true; esri.hide(dojo.byId('downloading-ui')); showAlert("alert-danger","Failed initializing storage, probably your browser doesn't support IndexedDB nor WebSQL"); } }); Offline.on('up', goOnline ); Offline.on('down', goOffline ); } function updateOfflineUsage() { dojo.byId('offline-usage').innerHTML = "updating..."; basemapLayer.getOfflineUsage(function(usage) { console.log(usage); console.log("Avg tile size:", Math.round(usage.size * 1024 / usage.tileCount * 100) / 100, "Kb"); var usageStr = usage.size + " Mb (" + usage.tileCount + " tiles)"; dojo.byId('offline-usage').innerHTML = usageStr; }); } function updateTileCountEstimation() { console.log('updating'); var zoomLevel = map.getLevel(); dojo.byId('currentLevel').value = zoomLevel; var minLevel = parseInt(dojo.byId('minLevel').value); var maxLevel = parseInt(dojo.byId('maxLevel').value); if( maxLevel > zoomLevel + 3 || maxLevel > basemapLayer.maxLevel) { maxLevel = Math.min(basemapLayer.maxLevel, zoomLevel + 3); dojo.byId('maxLevel').value = maxLevel; } var totalEstimation = { tileCount:0, sizeBytes:0 } domConstruct.empty('tile-count-table-body'); for(var level=minLevel; level<=maxLevel; level++) { var levelEstimation = basemapLayer.getLevelEstimation(map.extent,level); totalEstimation.tileCount += levelEstimation.tileCount; totalEstimation.sizeBytes += levelEstimation.sizeBytes; if( levelEstimation.tileCount > 1) { var rowContent = [levelEstimation.level, levelEstimation.tileCount, Math.round(levelEstimation.sizeBytes / 1024 / 1024 * 100) / 100 + " Mb"] rowContent = "" + rowContent.join("") + ""; var tr = domConstruct.place("", dojo.byId('tile-count-table-body'),'last') domConstruct.place(rowContent, tr,'last'); } if( totalEstimation.tileCount > 5000 ) { var tr = domConstruct.place("", dojo.byId('tile-count-table-body'),'last') domConstruct.place("...", tr,'last'); break; } } rowContent = ["Total", totalEstimation.tileCount, Math.floor(totalEstimation.sizeBytes / 1024 / 1024 * 100)/100 + " Mb"]; rowContent = "" + rowContent.join("") + ""; tr = domConstruct.place("", dojo.byId('tile-count-table-body'),'last') domConstruct.place(rowContent, tr,'last'); } function goOffline() { dojo.byId('go-offline-btn').disabled = true; dojo.byId('go-online-btn').disabled = undefined; dojo.byId('go-offline-btn').style.display = "none"; dojo.byId('go-online-btn').style.display = ""; basemapLayer.goOffline(); } function goOnline() { dojo.byId('go-offline-btn').disabled = undefined; dojo.byId('go-online-btn').disabled = true; dojo.byId('go-offline-btn').style.display = ""; dojo.byId('go-online-btn').style.display = "none"; basemapLayer.goOnline(); } function deleteAllTiles() { basemapLayer.deleteAllTiles(function(success, err) { console.log("deleteAllTiles():", success,err); if( success ) showAlert("alert-success", "All tiles deleted"); else showAlert("alert-danger", "Can't delete tiles: " + err); setTimeout(function() { updateOfflineUsage(); showStoredTiles(showTiles); },0); // request execution in the next turn of the event loop }); } function prepareForOffline() { /* put UI in downloading mode */ cancelRequested = false; errorList = []; query('#download-progress [role=progressbar]') .removeClass('progress-bar-warning') .addClass('progress-bar-success'); hideAlert(); reportProgress({countNow:0,countMax:1}); esri.hide(dojo.byId('ready-to-download-ui')); esri.show(dojo.byId('downloading-ui')); startTime = new Date(); /* launch offline preparation process */ var minLevel = parseInt(dojo.byId('minLevel').value); var maxLevel = parseInt(dojo.byId('maxLevel').value); basemapLayer.prepareForOffline(minLevel, maxLevel, map.extent, reportProgress); } function cancel() { cancelRequested = true; } function reportProgress(progress) { if( progress.finishedDownloading ) { if( progress.cancelRequested ) showAlert('alert-warning', 'Cancelled'); else if (errorList.length == 0) showAlert('alert-success', 'All tiles downloaded and stored'); else showAlert('alert-warning', "Finished downloading tiles, " + errorList.length + " tiles couldn't be downloaded"); setTimeout(function() { esri.show(dojo.byId('ready-to-download-ui')); esri.hide(dojo.byId('downloading-ui')); updateOfflineUsage(); showStoredTiles(showTiles); }, 1000); } else { // progress bar var pbar = query('#download-progress [role=progressbar]')[0]; var percent = progress.countMax? (progress.countNow / progress.countMax * 100) : 0; pbar.style.width = percent+"%"; // any errors? if( progress.error ) { query('#download-progress [role=progressbar]') .removeClass('progress-bar-success') .addClass('progress-bar-warning'); errorList.push(progress.error.msg); showAlert('alert-warning', progress.error.msg); } // remaining time if( progress.countNow > 5 ) { var currentTime = new Date(); var elapsedTime = currentTime - startTime; var remainingTime = (elapsedTime / progress.countNow) * (progress.countMax - progress.countNow); var sec = 1 + Math.floor(remainingTime / 1000); var min = Math.floor(sec / 60); sec -= (min * 60); dojo.byId('remaining-time').innerHTML = ((min<10)? "0" + min : min) + ":" + ((sec<10)? "0" + sec : sec); } return cancelRequested; } } function toggleShowStoredTiles() { showTiles = !showTiles; dojo.byId('show-stored-tiles-caption').innerHTML = showTiles? "Hide Stored Tiles" : "Show Stored Tiles"; showStoredTiles(showTiles); } function showStoredTiles(showTiles) { graphics.clear(); if( showTiles ) { basemapLayer.getTilePolygons(function(polygon,err) { if(polygon) { var graphic = new Graphic(polygon, symbol); graphics.add(graphic); } else { console.log("showStoredTiles: ", err); } }.bind(this)); } } function saveToFile() { basemapLayer.saveToFile("tiles.csv", function(success,msg) { if(success) showAlert('alert-success',msg); else showAlert('alert-danger',msg); }); } function loadFromFile() { var selectedFile = dojo.byId('file-select').files[0]; // clear input.files variable, so that next time it is empty again // otherwise selecting the same file twice will not trigger the 'change' event the second time var form = domConstruct.create('form'); domConstruct.place(dojo.byId('file-select'), form, "before"); form.reset(); if( !selectedFile ) { showAlert('alert-warning',"Please, select one file"); return; } basemapLayer.loadFromFile(selectedFile, function(success,msg) { if(success) showAlert('alert-success',msg); else showAlert('alert-danger',msg); updateOfflineUsage(); showStoredTiles(showTiles); }); } function showAlert(type, msg) { var icon = ""; switch(type) { case 'alert-success': icon = "fa-check"; break; case 'alert-info': icon = "fa-info-circle"; break; case 'alert-warning': icon = "fa-warning"; break; case 'alert-danger': icon = "fa-ban"; break; } dojo.byId('error-msg').innerHTML = msg; dojo.query('#error-div .close').onclick(hideAlert); dojo.query('#error-div .alert') .removeClass('alert-success') .removeClass('alert-info') .removeClass('alert-warning') .removeClass('alert-danger') .addClass(type); dojo.query('#error-div .fa') .removeClass('fa-info-circle') .addClass(icon); esri.show(dojo.byId('error-div')); } function hideAlert() { esri.hide(dojo.byId('error-div')); } });