Created
February 20, 2019 11:02
-
-
Save fxi/27467b2508810de4c3d43cdf570a5a6a to your computer and use it in GitHub Desktop.
Custom code to animate a serie of images in MapX custom code view
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Custom method for custom view in map-x | |
* Parameters for onInit and onClose function ; | |
* @param {Object} o Options | |
* @param {Object} o.view Map-x view object | |
* @param {Object} o.map mapbox-gl map object | |
* @param {String} o.idView If of the view | |
* @param {String} o.idSource Id of the source | |
* @param {Element} o.elLegend Element containing the legend | |
* | |
*/ | |
return { | |
onClose: function(o) { | |
console.log("Custom view closed"); | |
/** | |
* Remove source and layers | |
*/ | |
o._destroy(); | |
}, | |
onInit: function(o) { | |
console.log("Custom view added"); | |
var busy = false; | |
var layers = [ | |
"Mogadisho_Landsat7_20010628-531", | |
"Mogadisho_Landsat7_20031227-531", | |
"Mogadisho_Landsat7_20040924-531", | |
"Mogadisho_Landsat7_20070309-531", | |
"Mogadisho_Landsat7_20090314-531", | |
"Mogadisho_Landsat7_20120118-531", | |
"Mogadisho_Landsat7_20140616-531", | |
"Mogadisho_Landsat7_20160214-531", | |
"Mogadisho_Landsat7_20180102-531" | |
]; | |
var stepsBack = 9; | |
var images; | |
var map = o.map; | |
var stepCurrent = 0; | |
var idCurrent; | |
var bbxCurrent; | |
var renderedOnce = false; | |
/** | |
* Set custom legend | |
*/ | |
o.elLegend.innerText = "Time filter (2001 - 2018)"; | |
o.elLegend.style = "margin-bottom:15px"; | |
/** | |
* Init | |
*/ | |
makeInput(); | |
recalc(); | |
/** | |
* Destroy function | |
*/ | |
o._destroy = function() { | |
console.log("destroy"); | |
map.off("moveend", recalc); | |
removeLayers(); | |
}; | |
/** | |
* Patch events | |
* destroy is not called when view is unchecked OR when layer stack is evaluted... | |
*/ | |
if (!window.patchDestroy) { | |
window.patchDestroy = {}; | |
} | |
if (window.patchDestroy[o.idView]) { | |
var d = window.patchDestroy[o.idView]; | |
if (d instanceof Function) { | |
d(); | |
window.patchDestroy[o.id] = null; | |
} | |
} | |
window.patchDestroy[o.idView] = function() { | |
o._destroy() | |
} | |
var elCheck = document.getElementById("check_view_enable_MX-9NTPU-NYUM0-KAS45") | |
elCheck.addEventListener("change", patchDestroy); | |
function patchDestroy() { | |
if (!this.checked) { | |
o._destroy(); | |
this.removeEventListener("change", patchDestroy); | |
} | |
} | |
/** | |
* | |
* HELPERS | |
*/ | |
function recalc() { | |
if (!isBusy() && extentChanged()) { | |
isBusy(true); | |
console.log("recalc!"); | |
fetchAll(layers) | |
.then(createLayers) | |
.then(showLayer) | |
.then(function() { | |
map.once("moveend", recalc); | |
}); | |
} | |
} | |
function firstRender() { | |
if (renderedOnce === false) { | |
renderedOnce = true; | |
return true; | |
} | |
return false; | |
} | |
function createLayers(images) { | |
return new Promise(function(resolve, reject) { | |
images.forEach(function(image) { | |
var idNew = o.idView + "@" + image.step; | |
var l = { | |
id: idNew, | |
source: { | |
type: 'image', | |
url: image.url, | |
coordinates: image.bbx | |
}, | |
type: 'raster', | |
paint: { | |
'raster-opacity': 0, | |
'raster-opacity-transition': { | |
'duration': 1000 | |
} | |
} | |
}; | |
removeLayer(idNew); | |
map.addLayer(l, "mxlayers"); | |
}); | |
resolve(0); | |
}); | |
} | |
function showLayer(step) { | |
isBusy(true); | |
step = step && step.constructor === Event ? | |
this.value * 1 : | |
step * 1 || | |
stepCurrent || 0; | |
stepCurrent = step; | |
var idStep = o.idView + "@" + step; | |
forEachLayers(function(layer) { | |
var id = layer.id; | |
if (idStep === id) { | |
idCurrent = id; | |
map.setPaintProperty(id, | |
'raster-opacity', | |
1); | |
} else { | |
setTimeout(function() { | |
if (id !== idCurrent) { | |
map.setPaintProperty(id, | |
'raster-opacity', | |
0); | |
} | |
}, 100); | |
} | |
}); | |
isBusy(false); | |
} | |
function forEachLayers(cb) { | |
/** | |
* Get all currently displayed layer with the same | |
* prefix ID | |
*/ | |
var layers = mx.helpers.getLayerByPrefix({ | |
id: 'map_main', | |
prefix: o.idView | |
}); | |
layers.forEach(function(layer) { | |
cb(layer); | |
}); | |
} | |
function removeLayers() { | |
forEachLayers(function(layer) { | |
removeLayer(layer.id); | |
}); | |
} | |
function removeLayer(id) { | |
var src = map.getSource(id); | |
var ol = map.getLayer(id); | |
if (ol) { | |
map.removeLayer(id); | |
} | |
if (src) { | |
map.removeSource(id); | |
} | |
} | |
function fetchAll(layers) { | |
var bbxArray = getBoundsLatLngArray(); | |
return new Promise(function(resolve, reject) { | |
console.log("fetch all!"); | |
var urlImages = []; | |
var loaded = 0; | |
function pushImageUrl(res) { | |
loaded++; | |
loadProgress(loaded / stepsBack); | |
urlImages.push({ | |
step: res.pos, | |
layer: res.layer, | |
url: res.url, | |
bbx: bbxArray | |
}); | |
if (loaded === stepsBack) { | |
resolve(urlImages); | |
} | |
} | |
for (var i = 0, iL = stepsBack; i < iL; i++) { | |
layer = layers[i]; | |
getImageUrlBlob(layer, i) | |
.then(pushImageUrl); | |
} | |
}); | |
} | |
function loadProgress(p) { | |
p = p * 100; | |
mx.helpers.progressScreen({ | |
enable: p < 100, | |
id: "download_images", | |
percent: p, | |
text: " Downloading data ( " + Math.ceil(p) + "% )" | |
}); | |
} | |
function makeInput() { | |
console.log("Create input !"); | |
var elInputDate = document.createElement("INPUT"); | |
elInputDate.setAttribute("type", "range"); | |
elInputDate.setAttribute("min", "0"); | |
elInputDate.setAttribute("max", stepsBack - 1); | |
elInputDate.setAttribute("step", "1"); | |
elInputDate.setAttribute("value", 0); | |
elInputDate.style = "margin-top:15px"; | |
elInputDate.addEventListener("input", showLayer); | |
o.elLegend.parentElement.appendChild(elInputDate); | |
} | |
function getBoundsMeter() { | |
var b = map.getBounds(); | |
var ne = degreesToMeters(b.getEast(), b.getNorth()); | |
var sw = degreesToMeters(b.getWest(), b.getSouth()); | |
return { | |
n: ne.y, | |
s: sw.y, | |
e: ne.x, | |
w: sw.x | |
}; | |
} | |
function getBoundsMeterString() { | |
var b = getBoundsMeter(); | |
return b.w + "," + b.s + "," + b.e + "," + b.n; | |
} | |
function extentChanged() { | |
return getBoundsMeterString() !== bbxCurrent; | |
} | |
function isBusy(set) { | |
if (typeof set !== "undefined") { | |
busy = set; | |
} else { | |
console.log("Is busy ? " + (busy ? 'yes' : 'no') + "!"); | |
} | |
return busy === true; | |
} | |
function getBoundsLatLngArray() { | |
var b = map.getBounds(); | |
var nw = b.getNorthWest(); | |
var se = b.getSouthEast(); | |
return [ | |
[ | |
nw.lng, nw.lat | |
], | |
[ | |
se.lng, nw.lat | |
], | |
[ | |
se.lng, se.lat | |
], | |
[ | |
nw.lng, se.lat | |
] | |
]; | |
} | |
function getTilesUrlLayer(layer) { | |
var res = window.document.body.getBoundingClientRect(); | |
bbxCurrent = getBoundsMeterString(); | |
return 'https://datacore.unepgrid.ch/geoserver' + | |
'/MAPX/wms?REQUEST=GetMap&' + | |
'layers=' + layer + | |
'&WIDTH=' + res.width + | |
'&HEIGHT=' + res.height + | |
'&bbox=' + bbxCurrent + | |
'&SRS=EPSG:3857&' + | |
'version=1.1.1&format=image/png&transparent=true'; | |
} | |
function getImageUrlBlob(layer, pos) { | |
var url = getTilesUrlLayer(layer); | |
return fetch(url) | |
.then(function(response) { | |
return response.blob(); | |
}).then(function(blob) { | |
return { | |
layer: layer, | |
url: window.URL.createObjectURL(blob), | |
pos: pos | |
}; | |
}); | |
} | |
function degreesToMeters(lon, lat) { | |
var x = lon * 20037508.34 / 180; | |
var y = Math.log(Math.tan((90 + lat) * Math.PI / 360)) / (Math.PI / 180); | |
y = y * 20037508.34 / 180; | |
return { | |
x: x, | |
y: y | |
}; | |
} | |
} | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment