Skip to content

Instantly share code, notes, and snippets.

@asizer
Created February 17, 2017 22:51
Show Gist options
  • Save asizer/3b78e9732bf8b1251a92219b26d05d8d to your computer and use it in GitHub Desktop.
Save asizer/3b78e9732bf8b1251a92219b26d05d8d to your computer and use it in GitHub Desktop.
Simulating loading of 5 webmaps in Cascade, and trying to wait for context loss and previous webmap load. Occasionally crashes iOS Safari.
<!DOCTYPE html>
<html>
<head>
<title>Waiting for context recycling and webmap load</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no,width=device-width" />
<meta http-equiv="X-UA-Compatible" content="IE=Edge">
<link rel="stylesheet" href="http://js.arcgis.com/3.19/esri/css/esri.css">
<script
src="https://code.jquery.com/jquery-3.1.1.min.js"
integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8="
crossorigin="anonymous">
</script>
<style>
html, body {
width: 100%;
margin: 0;
padding: 0;
}
.text-divider {
background-color: gray;
color: #eee;
width: 100%;
height: 1.5em;
font-size: 30px;
text-align: center;
line-height: 1.5em;
}
.text-divider table {
width: 100%;
height: 100%;
}
.explainer {
height: auto;
width: 100%;
line-height: 1.4em;
font-size: 16px;
padding: 10px 20px;
box-sizing: border-box;
background-color: #bf40bf;
color: white;
}
@media (max-device-width: 1000px) {
.text-divider {
font-size: 12px;
height: 2em;
line-height: 1.5em;
}
.explainer {
font-size: 12px;
}
}
.my-map {
height: 40vh;
width: 80%;
margin: 0 19% 0 0%;
}
</style>
<script src="http://js.arcgis.com/3.19/"></script>
<script>
var maps = [];
var canvasCounter = 0;
var lostCounter = 0;
var timeoutSeconds = 3;
var defs = {
webGL: [],
map: []
};
require([
'esri/arcgis/utils',
'esri/geometry/Extent',
'esri/tasks/query',
'esri/geometry/Point',
'dojo/Deferred',
'dojo/promise/all',
'dojo/on'
], function(arcgisUtils, Extent, Query, Point, Deferred, dojoAll, dojoOn) {
var medias = [{
type: 'webmap',
id: '26e7bf668ba943c0bc63f7a38259a6ca'
}, {
type: 'webmap',
id: 'e6d5c9a33489482bb7fb6efeb3c0f8d6',
layers: ['National_Bridge_Inventory_2013_3794'],
options: {
mapOptions: {
extent: new Extent({
'xmin': -9111324.08957585,
'ymin': 3524642.291722416,
'xmax': -9055983.681097455,
'ymax': 3561561.3763841065,
'spatialReference': {
'wkid': 102100
}
})
}
}
}, {
type: 'webmap',
id: 'e6d5c9a33489482bb7fb6efeb3c0f8d6',
layers: ['USA_States_Generalized_4441', 'Bad_roads_2295_6768', 'Bad_roads_2295']
}, {
type: 'webmap',
id: 'e6d5c9a33489482bb7fb6efeb3c0f8d6',
layers: ['ShipRoutes_7525', 'World_Ocean_Reference_5411', 'World_Ocean_Base_988', 'featColl_4094_3304_0'],
}, {
type: 'webmap',
id: 'e6d5c9a33489482bb7fb6efeb3c0f8d6',
layers: ['Airports_Cargo_Passengers_3360'],
}];
$('.timeout-seconds').text(timeoutSeconds);
medias.forEach(function(media, i) {
setTimeout(function() {
preloadWebmap(media, i);
}, timeoutSeconds * 1000 * i);
});
function preloadWebmap(media, i) {
var webglCount = defs.webGL.length;
setWaitingText(i);
if (!defs.map[i]) {
defs.map[i] = new Deferred();
}
dojoAll(defs.webGL).then(function() {
var previousMapDef = defs.map[i - 1];
if (webglCount !== defs.webGL.length) {
preloadWebmap(media, i);
} else if (!previousMapDef || previousMapDef.isResolved()) {
loadWebmap(media, i);
} else {
previousMapDef.then(function() {
preloadWebmap(media, i);
});
}
});
}
function loadWebmap(media, i) {
setLoadingText(i);
resetCurrentlyWaitingCounters(i);
arcgisUtils.createMap(media.id, 'map' + i, media.options || null).then(function(response) {
resetCurrentlyLoadingCounters(i);
var map = response.map;
maps.push(map);
configureMapLayers(media.layers, map);
setListenersToResolveMapDeferred(map, i);
dojoOn.once(map, 'update-end', function() {
setCanvasListeners(map.container);
});
});
}
function configureMapLayers(layerIds, map) {
if (layerIds) {
layerIds.forEach(function(lyrId) {
setLayerVisible(map, lyrId);
});
}
}
function setLayerVisible(map, lyrId) {
var lyr = map.getLayer(lyrId);
if (lyr) {
lyr.setVisibility(true);
}
}
function setLoadingText(i) {
$('.text-divider').css('background-color', 'dodgerblue');
var oldLoading = $('.currently-loading').first().text().trim();
var newText = ' ' + i;
$('.currently-loading').text(oldLoading + newText);
}
function resetCurrentlyLoadingCounters(i) {
var oldLoading = $('.currently-loading').first().text();
var newText = oldLoading.replace(new RegExp(i, 'g'), '');
$('.currently-loading').text(newText);
if (!newText.trim()) {
$('.text-divider').css('background-color', 'gray');
}
}
function resetCurrentlyWaitingCounters(i) {
var oldWaiting = $('.currently-waiting').first().text();
var newText = oldWaiting.replace(new RegExp(i, 'g'), '');
$('.currently-waiting').text(newText);
}
function setWaitingText(i) {
var oldWaiting = $('.currently-waiting').first().text().trim();
var newText = ' ' + i;
$('.currently-waiting').text(oldWaiting + newText);
}
function setCanvasListeners(mapContainer) {
$(mapContainer).find('canvas').each(function(i, canvas) {
var webglDef = new Deferred();
$('.canvas-counter').html(++canvasCounter);
$(canvas).on('webglcontextlost', function() {
defs.webGL.push(webglDef);
$('.lost-counter').html(++lostCounter);
console.debug('webglcontextlost');
setTimeout(function() {
webglDef.resolve();
}, 2000);
});
});
}
function setListenersToResolveMapDeferred(map, i) {
var mapDef = defs.map[i];
dojoOn.once(map, 'update-end', function() {
if (!mapDef.isResolved()) {
mapDef.resolve();
}
});
// fallback in case the map doesn't load
setTimeout(function() {
if (!mapDef.isResolved()) {
mapDef.resolve();
}
}, 5000);
}
});
</script>
</head>
<body>
<div class="explainer">
(Blue divider backgrounds mean a webmap is currently loading.)
This app loads one non-VTL webmap and then a different webmap with 8 VTL's four times, at <span class="timeout-seconds"></span> second intervals, with different layers visible.
It waits for the previous map to load (or 5 seconds after the previous map starts loading) and 2 seconds after
the last webglcontextlost event to load the next webmap. <br>
This still occasionally crashes iOS Safari.
</div>
<div class="text-divider">
<table>
<tr>
<td>Map 0 below</td>
<td>Canvases: <span class="canvas-counter"></span></td>
<td>Lost: <span class="lost-counter"></span></td>
<td>Loading index: <span class="currently-loading"></span></td>
<td>Waiting indices: <span class="currently-waiting"></span></td>
</tr>
</table>
</div>
<div id="map0" class="my-map"></div>
<div class="text-divider">
<table>
<tr>
<td>Map 0 below</td>
<td>Canvases: <span class="canvas-counter"></span></td>
<td>Lost: <span class="lost-counter"></span></td>
<td>Loading index: <span class="currently-loading"></span></td>
<td>Waiting indices: <span class="currently-waiting"></span></td>
</tr>
</table>
</div>
<div id="map1" class="my-map"></div>
<div class="text-divider">
<table>
<tr>
<td>Map 0 below</td>
<td>Canvases: <span class="canvas-counter"></span></td>
<td>Lost: <span class="lost-counter"></span></td>
<td>Loading index: <span class="currently-loading"></span></td>
<td>Waiting indices: <span class="currently-waiting"></span></td>
</tr>
</table>
</div>
<div id="map2" class="my-map"></div>
<div class="text-divider">
<table>
<tr>
<td>Map 0 below</td>
<td>Canvases: <span class="canvas-counter"></span></td>
<td>Lost: <span class="lost-counter"></span></td>
<td>Loading index: <span class="currently-loading"></span></td>
<td>Waiting indices: <span class="currently-waiting"></span></td>
</tr>
</table>
</div>
<div id="map3" class="my-map"></div>
<div class="text-divider">
<table>
<tr>
<td>Map 0 below</td>
<td>Canvases: <span class="canvas-counter"></span></td>
<td>Lost: <span class="lost-counter"></span></td>
<td>Loading index: <span class="currently-loading"></span></td>
<td>Waiting indices: <span class="currently-waiting"></span></td>
</tr>
</table>
</div>
<div id="map4" class="my-map"></div>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment