-
-
Save brookisme/f6557dd5df0b37f3846ae81e5e9c8187 to your computer and use it in GitHub Desktop.
TCD Tile Viewer - 2000 vs 2010
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
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset=utf-8 /> | |
<title>TCD Tile Comparison</title> | |
<meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' /> | |
<!-- Load Leaflet from CDN--> | |
<link rel="stylesheet" href="https://cdn.jsdelivr.net/leaflet/0.7.7/leaflet.css" /> | |
<script src="https://cdn.jsdelivr.net/leaflet/0.7.7/leaflet.js"></script> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet-hash/0.2.1/leaflet-hash.min.js"></script> | |
<link rel="stylesheet" type="text/css" href="https://gist.githubusercontent.com/mappingvermont/9bda617b9a35b0c4f2140d48b41368b8/raw/8ab5b4d1ed17065da5cd36de962d0701c7e51589/style.css"> | |
<script type="text/javascript" src="https://gist.githubusercontent.com/mappingvermont/9bda617b9a35b0c4f2140d48b41368b8/raw/8ab5b4d1ed17065da5cd36de962d0701c7e51589/canvas-layer.js"></script> | |
<script type="text/javascript" src="https://gist.githubusercontent.com/mappingvermont/9bda617b9a35b0c4f2140d48b41368b8/raw/8ab5b4d1ed17065da5cd36de962d0701c7e51589/script.js"></script> | |
</head> | |
<body onLoad="init();"> | |
<div id="map"></div> | |
</body> | |
</html> |
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
/** | |
If possible, I would avoid looking in here/editing any of the code | |
It was written by Gerardo Pacheco, and is fairly complex with respect | |
to scaling GLAD map tiles dynamically. | |
I've commented out the tile cache stuff-- was interfering with my poor | |
implementation of dynamic tile filtering-- but otherwise this code is as | |
he wrote it. | |
Ideally this should be included in the project and then referenced only as it | |
is in script.js-- using the getTile method to overwrite Leaflet's CanvasLayer drawTile | |
*/ | |
function Canvas(options) { | |
this.dataMaxZoom = options.maxZoom || 12; | |
this.tiles = {}; | |
this.urlTemplate = options.urlTemplate || ''; | |
} | |
Canvas.prototype.getTile = function(coord, zoom, canvas) { | |
/** | |
* Enable cache of tiles | |
*/ | |
//var tileId = this._getTileId(coord.x, coord.y, zoom); | |
//var objKeys = Object.keys(this.tiles); | |
//for (var i = 0; i < objKeys.length; i++) { | |
// if (this.tiles[objKeys[i]].z !== zoom) { | |
// delete this.tiles[objKeys[i]]; | |
// } | |
//} | |
//if (this.tiles[tileId]) { | |
// return this.tiles[tileId].canvas; | |
//} | |
var url = this._getUrl.apply(this, this._getTileCoords(coord.x, coord.y, zoom)); | |
this._getImage(url, function(image) { | |
var canvasData = { | |
canvas: canvas, | |
image: image, | |
x: coord.x, | |
y: coord.y, | |
z: zoom | |
}; | |
//this._cacheTile(canvasData); | |
this._drawCanvasImage(canvasData); | |
}.bind(this)); | |
return canvas; | |
}; | |
Canvas.prototype._getImage = function(url, callback) { | |
var xhr = new XMLHttpRequest(); | |
xhr.onload = function() { | |
var url = URL.createObjectURL(this.response); | |
var image = new Image(); | |
image.onload = function() { | |
image.crossOrigin = ''; | |
callback(image); | |
URL.revokeObjectURL(url); | |
}; | |
image.src = url; | |
}; | |
xhr.open('GET', url, true); | |
xhr.responseType = 'blob'; | |
xhr.send(); | |
}; | |
Canvas.prototype._getTileId = function(x, y, z) { | |
return x + '_' + y + '_' + z; | |
}; | |
Canvas.prototype._getZoomSteps = function(z) { | |
return z - this.dataMaxZoom; | |
}; | |
Canvas.prototype.pad = function(num) { | |
var s = '00' + num; | |
return s.substr(s.length - 3); | |
}; | |
Canvas.prototype.filterTileImgdata = function(data) { | |
for (var i = 0; i < data.length; i += 4) { | |
var rgba = data.slice(i, i + 4) | |
var intensityBand = 1 | |
// if the pixel passes the date + conf filters, recolor it in some way | |
if (rgba[intensityBand] > 0) { | |
var intensity = rgba[intensityBand] * 0.8 | |
if (intensity > 255) { | |
intensity = 255 | |
} | |
// this just turns all pixels green | |
data[i] = 151 | |
data[i + 1] = 189, | |
data[i + 2] = 61 | |
data[i + 3] = intensity | |
// if it doesn't match the filter, set opacity to 0 | |
} else { | |
data[i + 3] = 0 | |
} | |
} | |
return data; | |
}; | |
Canvas.prototype._drawCanvasImage = function(canvasData) { | |
"use asm"; | |
var canvas = canvasData.canvas, | |
ctx = canvas.getContext('2d'), | |
image = canvasData.image, | |
zsteps = this._getZoomSteps(canvasData.z) | 0; // force 32bit int type | |
ctx.clearRect(0, 0, 256, 256); // this will allow us to sum up the dots when the timeline is running | |
if (zsteps < 0) { | |
ctx.drawImage(image, 0, 0); | |
} else { // over the maxzoom, we'll need to scale up each tile | |
ctx.imageSmoothingEnabled = false; // disable pic enhancement | |
ctx.mozImageSmoothingEnabled = false; | |
// tile scaling | |
var srcX = (256 / Math.pow(2, zsteps) * (canvasData.x % Math.pow(2, zsteps))) |0, | |
srcY = (256 / Math.pow(2, zsteps) * (canvasData.y % Math.pow(2, zsteps))) |0, | |
srcW = (256 / Math.pow(2, zsteps)) |0, | |
srcH = (256 / Math.pow(2, zsteps)) |0; | |
ctx.drawImage(image, srcX, srcY, srcW, srcH, 0, 0, 256, 256); | |
} | |
var I = ctx.getImageData(0, 0, canvas.width, canvas.height); | |
this.filterTileImgdata(I.data); | |
ctx.putImageData(I, 0, 0); | |
}; | |
Canvas.prototype._getUrl = function(x, y, z) { | |
return this.urlTemplate.replace('%z', z).replace('%x', x).replace('%y', y); | |
}; | |
Canvas.prototype._getTileCoords = function(x, y, z) { | |
if (z > this.dataMaxZoom) { | |
x = Math.floor(x / (Math.pow(2, z - this.dataMaxZoom))); | |
y = Math.floor(y / (Math.pow(2, z - this.dataMaxZoom))); | |
z = this.dataMaxZoom; | |
} else { | |
y = (y > Math.pow(2, z) ? y % Math.pow(2, z) : y); | |
if (x >= Math.pow(2, z)) { | |
x = x % Math.pow(2, z); | |
} else if (x < 0) { | |
x = Math.pow(2, z) - Math.abs(x); | |
} | |
} | |
return [x, y, z]; | |
}; | |
Canvas.prototype._cacheTile = function(canvasData) { | |
var tileId = this._getTileId(canvasData.x, canvasData.y, canvasData.z); | |
canvasData.canvas.setAttribute('id', tileId); | |
this.tiles[tileId] = canvasData; | |
}; |
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
function init() { | |
// create canvas layer place holder | |
var tcd2000Layer = new Canvas({ | |
maxZoom: 12, | |
urlTemplate: 'http://earthengine.google.org/static/hansen_2014/gfw_loss_tree_year_30_2014/%z/%x/%y.png' | |
}); | |
// create canvas layer place holder | |
var tcd2010Layer = new Canvas({ | |
maxZoom: 12, | |
//urlTemplate: 'http://storage.googleapis.com/wri-public/treecover2010/thresholds/30/%z/%x/%y' | |
//urlTemplate: 'https://storage.googleapis.com/wri-public/treecover2010/tiles/thresholds/30/%z/%x/%y.png' | |
//urlTemplate: 'https://storage.googleapis.com/wri-public/treecover2000/tiles/thresholds/30/%z/%x/%y.png' | |
//urlTemplate: 'https://storage.googleapis.com/wri-public/treecover2000-test/tiles/thresholds/30/%z/%x/%y.png' | |
//urlTemplate: 'https://storage.googleapis.com/wri-public/treecover2000/30/%z/%x/%y.png' | |
urlTemplate: 'https://storage.googleapis.com/wri-public/treecover2010/30/%z/%x/%y.png' | |
}); | |
var tcd2000 = L.tileLayer.canvas({noWrap: true}); | |
var tcd2010 = L.tileLayer.canvas({noWrap: true}); | |
// set bounding box for map + create it | |
var southWest = L.latLng(-90, -179), | |
northEast = L.latLng(90, 179), | |
worldBounds = L.latLngBounds(southWest, northEast); | |
var map = L.map('map', { | |
noWrap: true, | |
minZoom: 3, | |
maxZoom: 16, | |
maxBounds: worldBounds | |
}).setView([0, 15], 3); | |
// initialize the Leaflet hash plugin to add zoom/lat/lon hash to our url | |
var hash = new L.Hash(map); | |
// add the OSM basemap | |
var osm = L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { | |
maxZoom: 19, | |
attribution: '© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>' | |
}); | |
map.addLayer(osm); | |
tcd2000.drawTile = function(canvas, tilePoint, zoom) { | |
// pass these and the confidence to the custom getTile method so we can filter GLAD | |
tcd2000Layer.getTile(tilePoint, zoom, canvas); | |
}; | |
tcd2000.addTo(map); | |
tcd2010.drawTile = function(canvas, tilePoint, zoom) { | |
// pass these and the confidence to the custom getTile method so we can filter GLAD | |
tcd2010Layer.getTile(tilePoint, zoom, canvas); | |
}; | |
L.control.layers({'TCD 2000 - Original': tcd2000, 'TCD 2000 - New': tcd2010}, null).addTo(map); | |
} |
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
body { | |
margin: 0; | |
padding: 0; | |
} | |
#map { | |
position: absolute; | |
top: 0; | |
bottom: 0; | |
right: 0; | |
left: 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment