async function performAnalysis()
{
let result={};
console.log(map.getCenter());
console.log(map.getZoom());
console.log("starting analyze");
const NO_DATA =0;
const WATER=1;
const TREES=2;
const FLOODED_VEGETATION=3;
const CROPS=4;
const BUILT_AREA = 5;
const BARE_GROUND=6;
const SNOW_ICE=7;
const CLOUDS=8;
const RANGELAND=9;
const FRIENDLY_NAMES = ["No Data","Water","Trees","Flooded Vegetation","Crops","Built Area","Bare Ground","Snow/Ice","Clouds","Rangeland"];
const SQM_PER_ACRE = 4046.86;
const WGS_EARTH_RADIUS = 6378137.0;
let geodesicArea = function (latLngs) {
var pointsCount = latLngs.length,
area = 0.0,
d2r = Math.PI / 180,
p1, p2;
if (pointsCount > 2) {
for (var i = 0; i < pointsCount; i++) {
p1 = latLngs[i];
p2 = latLngs[(i + 1) % pointsCount];
area += ((p2.lng - p1.lng) * d2r) *
(2 + Math.sin(p1.lat * d2r) + Math.sin(p2.lat * d2r));
}
area = area * (WGS_EARTH_RADIUS*WGS_EARTH_RADIUS) / 2.0;
}
return Math.abs(area);
}
// We can determine the use type entirely by the red pixels as each item in the symbology varies
function getUseType(redPixel)
{
switch (redPixel)
{
case 65: return WATER;
case 57: return TREES;
case 122: return FLOODED_VEGETATION;
case 228: return CROPS;
case 196: return BUILT_AREA;
case 165: return BARE_GROUND;
case 168: return SNOW_ICE;
case 97: return CLOUDS;
case 227: return RANGELAND;
}
return redPixel;
// console.log("Undefined r of "+ redPixel);
}
// This is a custom forked version of the LeafletImage library that will let me render a single layer
// instead of the map as it shows up on screen.
let complete=false;
let ls2017only = function(l){ return l.name=="2017";}
LeafletImage(map, ls2017only, function(err,canvas2017) {
let ls2021Only = function(l){ return l.name=="2021";}
LeafletImage(map, ls2021Only, function(err,canvas2021) {
var dimensions = map.getSize();
const image2017 = canvas2017.getContext("2d").getImageData(0,0,dimensions.x,dimensions.y);
const image2021 = canvas2021.getContext("2d").getImageData(0,0,dimensions.x,dimensions.y);
result.totalMapAreaSqM = geodesicArea(
[map.getBounds().getNorthWest(),
map.getBounds().getNorthEast(),
map.getBounds().getSouthEast(),
map.getBounds().getSouthWest() ]);
result.acresPerPixel = result.totalMapAreaSqM/ SQM_PER_ACRE / (dimensions.x * dimensions.y);
result.pixelsChangedDict=[];
result.totalPixels=0;
result.pixelsChanged=0;
for (let i = 0; i < image2017.data.length; i += 4)
{
result.totalPixels++;
let pixelUse2017 =getUseType(image2017.data[i]);
let pixelUse2021 =getUseType(image2021.data[i]);
if (pixelUse2017!=pixelUse2021)
{
result.pixelsChanged++;
}
if (!result.pixelsChangedDict[pixelUse2017 + "|" + pixelUse2021])
{
result.pixelsChangedDict[pixelUse2017 + "|" + pixelUse2021]=0;
}
result.pixelsChangedDict[pixelUse2017 + "|" + pixelUse2021]++;
}
result.sankey=[];
for (let src=0;src<FRIENDLY_NAMES.length;src++)
{
for (let dest=0;dest<FRIENDLY_NAMES.length;dest++)
{
if ((result.pixelsChangedDict[src + "|" + dest]) && result.pixelsChangedDict[src + "|" + dest]>1000)
{
result.sankey.push({source:FRIENDLY_NAMES[src] , target: FRIENDLY_NAMES[dest]+" ", value:(result.pixelsChangedDict[src + "|" + dest]*result.acresPerPixel) });
}
}
}
console.log("done analyzing");
complete=true;
console.log(result);
});
});
// THis is horribly hacky, but stops us returning until everything is loaded
while (!complete)
{
await new Promise(r => setTimeout(r, 100));
}
return result;
}