Created
October 20, 2015 18:49
-
-
Save fasiha/63d2dbb36fc88f72c078 to your computer and use it in GitHub Desktop.
Imagery Layers Manipulation demo for Cesium.js using custom image processing: try at http://cesiumjs.org/Cesium/Apps/Sandcastle/index.html?src=Imagery%20Layers%20Manipulation.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
// See discussion at https://groups.google.com/d/msg/cesium-dev/aysBQWn9c88/JoR0dpQ_DAAJ | |
// Paste this into http://cesiumjs.org/Cesium/Apps/Sandcastle/index.html?src=Imagery%20Layers%20Manipulation.html, then look at the Cesium logo hovering above Utah, USA (it's colors have been edited) | |
var defined = Cesium.defined; | |
var when = Cesium.when; | |
var DeveloperError = Cesium.DeveloperError; | |
var ImageryProviderHooks = {}; | |
ImageryProviderHooks.addRecolorFunc = function(imageryProvider, recolorFunc) { | |
// Override requestImage to recolor the images. | |
imageryProvider.base_requestImage = imageryProvider.requestImage; | |
imageryProvider.recolorFunc = recolorFunc; | |
imageryProvider.requestImage = function(x, y, level) { | |
var imagePromise = this.base_requestImage(x, y, level); | |
if (!defined(imagePromise)) { | |
return imagePromise; | |
} | |
var that = this; | |
return when(imagePromise, function(image) { | |
if (defined(image)) { | |
var context = getCanvasContext(imageryProvider, image); | |
image = recolorImageWithCanvasContext(context, image, that.recolorFunc); | |
} | |
return image; | |
}); | |
}; | |
}; | |
/* Recolor a raster image pixel by pixel, replacing encoded identifiers with some calculated value. */ | |
ImageryProviderHooks.recolorImage = function(image, colorFunc) { | |
var length = image.data.length; //pixel count * 4 | |
for (var i = 0; i < length; i += 4) { | |
// Convert that identifier into the data-mapped colour it should display as. | |
var clr = colorFunc(image.data[i], image.data[i+1], image.data[i+2], image.data[i+3]); | |
if (defined(clr)) { | |
for (var j = 0; j < 4; j++) { | |
image.data[i+j] = clr[j]; | |
} | |
} | |
} | |
return image; | |
}; | |
function getCanvasContext(imageryProvider, img) { | |
var context = imageryProvider._canvas2dContext; | |
if (!defined(context) || context.canvas.width !== img.width || context.canvas.height !== img.height) { | |
var canvas = document.createElement("canvas"); | |
canvas.width = img.width; | |
canvas.height = img.height; | |
context = canvas.getContext("2d"); | |
imageryProvider._canvas2dContext = context; | |
} | |
return context; | |
} | |
/* Copy an image to a newly created Canvas, then perform recoloring there. */ | |
function recolorImageWithCanvasContext(context, img, colorFunc) { | |
if (!defined(context)) { | |
throw new DeveloperError('No context for image recoloring.'); | |
} | |
// Copy the image contents to the canvas | |
context.clearRect(0, 0, context.canvas.width, context.canvas.height); | |
context.drawImage(img, 0, 0); | |
var image = context.getImageData(0, 0, context.canvas.width, context.canvas.height); | |
image = ImageryProviderHooks.recolorImage(image, colorFunc); | |
return image; | |
} | |
ImageryProviderHooks.addPickFeaturesHook = function(imageryProvider, hook) { | |
// Override pickFeatures to add more metadata. | |
imageryProvider.base_pickFeatures = imageryProvider.pickFeatures; | |
imageryProvider.pickFeatures = function(x, y, level, longitude, latitude) { | |
var featurePromise = this.base_pickFeatures(x, y, level, longitude, latitude); | |
if (!defined(featurePromise)) { | |
return featurePromise; | |
} | |
return featurePromise.then(hook); | |
}; | |
}; | |
/////////////////// | |
var viewer = new Cesium.Viewer('cesiumContainer', { | |
baseLayerPicker : false | |
}); | |
var imageryLayers = viewer.imageryLayers; | |
var viewModel = { | |
layers : [], | |
baseLayers : [], | |
upLayer : null, | |
downLayer : null, | |
selectedLayer : null, | |
isSelectableLayer : function(layer) { | |
return baseLayers.indexOf(layer) >= 0; | |
}, | |
raise : function(layer, index) { | |
imageryLayers.raise(layer); | |
viewModel.upLayer = layer; | |
viewModel.downLayer = viewModel.layers[Math.max(0, index - 1)]; | |
updateLayerList(); | |
window.setTimeout(function() { viewModel.upLayer = viewModel.downLayer = null; }, 10); | |
}, | |
lower : function(layer, index) { | |
imageryLayers.lower(layer); | |
viewModel.upLayer = viewModel.layers[Math.min(viewModel.layers.length - 1, index + 1)]; | |
viewModel.downLayer = layer; | |
updateLayerList(); | |
window.setTimeout(function() { viewModel.upLayer = viewModel.downLayer = null; }, 10); | |
}, | |
canRaise : function(layerIndex) { | |
return layerIndex > 0; | |
}, | |
canLower : function(layerIndex) { | |
return layerIndex >= 0 && layerIndex < imageryLayers.length - 1; | |
} | |
}; | |
Cesium.knockout.track(viewModel); | |
var baseLayers = viewModel.baseLayers; | |
function setupLayers() { | |
// Create all the base layers that this example will support. | |
// These base layers aren't really special. It's possible to have multiple of them | |
// enabled at once, just like the other layers, but it doesn't make much sense because | |
// all of these layers cover the entire globe and are opaque. | |
addBaseLayerOption( | |
'Bing Maps Aerial', | |
undefined); // the current base layer | |
addBaseLayerOption( | |
'Bing Maps Road', | |
new Cesium.BingMapsImageryProvider({ | |
url: '//dev.virtualearth.net', | |
mapStyle: Cesium.BingMapsStyle.ROAD | |
})); | |
addBaseLayerOption( | |
'ArcGIS World Street Maps', | |
new Cesium.ArcGisMapServerImageryProvider({ | |
url : '//server.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer' | |
})); | |
addBaseLayerOption( | |
'OpenStreetMaps', | |
new Cesium.OpenStreetMapImageryProvider()); | |
addBaseLayerOption( | |
'MapQuest OpenStreetMaps', | |
new Cesium.OpenStreetMapImageryProvider({ | |
url: '//otile1-s.mqcdn.com/tiles/1.0.0/osm/' | |
})); | |
addBaseLayerOption( | |
'Stamen Maps', | |
new Cesium.OpenStreetMapImageryProvider({ | |
url: '//stamen-tiles.a.ssl.fastly.net/watercolor/', | |
fileExtension: 'jpg', | |
credit: 'Map tiles by Stamen Design, under CC BY 3.0. Data by OpenStreetMap, under CC BY SA.' | |
})); | |
addBaseLayerOption( | |
'Natural Earth II (local)', | |
new Cesium.TileMapServiceImageryProvider({ | |
url : require.toUrl('Assets/Textures/NaturalEarthII') | |
})); | |
addBaseLayerOption( | |
'USGS Shaded Relief (via WMTS)', | |
new Cesium.WebMapTileServiceImageryProvider({ | |
url : 'http://basemap.nationalmap.gov/arcgis/rest/services/USGSShadedReliefOnly/MapServer/WMTS', | |
layer : 'USGSShadedReliefOnly', | |
style : 'default', | |
format : 'image/jpeg', | |
tileMatrixSetID : 'default028mm', | |
maximumLevel: 19, | |
credit : new Cesium.Credit('U. S. Geological Survey') | |
})); | |
// Create the additional layers | |
addAdditionalLayerOption( | |
'United States GOES Infrared', | |
new Cesium.WebMapServiceImageryProvider({ | |
url : '//mesonet.agron.iastate.edu/cgi-bin/wms/goes/conus_ir.cgi?', | |
layers : 'goes_conus_ir', | |
credit : 'Infrared data courtesy Iowa Environmental Mesonet', | |
parameters : { | |
transparent : 'true', | |
format : 'image/png' | |
}, | |
proxy : new Cesium.DefaultProxy('/proxy/') | |
})); | |
addAdditionalLayerOption( | |
'United States Weather Radar', | |
new Cesium.WebMapServiceImageryProvider({ | |
url : '//mesonet.agron.iastate.edu/cgi-bin/wms/nexrad/n0r.cgi?', | |
layers : 'nexrad-n0r', | |
credit : 'Radar data courtesy Iowa Environmental Mesonet', | |
parameters : { | |
transparent : 'true', | |
format : 'image/png' | |
}, | |
proxy : new Cesium.DefaultProxy('/proxy/') | |
})); | |
addAdditionalLayerOption( | |
'TileMapService Image', | |
new Cesium.TileMapServiceImageryProvider({ | |
url : '../images/cesium_maptiler/Cesium_Logo_Color' | |
}), | |
0.2); | |
var singleTile = new Cesium.SingleTileImageryProvider({ | |
url : '../images/Cesium_Logo_overlay.png', | |
rectangle : Cesium.Rectangle.fromDegrees(-115.0, 38.0, -107, 39.75) | |
}); | |
ImageryProviderHooks.addRecolorFunc(singleTile, (r,g,b,a) => [255-r, 255-g, 255-b, a]); | |
addAdditionalLayerOption( | |
'Single Image', | |
singleTile, | |
1.0); | |
addAdditionalLayerOption( | |
'Grid', | |
new Cesium.GridImageryProvider(), 1.0, false); | |
addAdditionalLayerOption( | |
'Tile Coordinates', | |
new Cesium.TileCoordinatesImageryProvider(), 1.0, false); | |
} | |
function addBaseLayerOption(name, imageryProvider) { | |
var layer; | |
if (typeof imageryProvider === 'undefined') { | |
layer = imageryLayers.get(0); | |
viewModel.selectedLayer = layer; | |
} else { | |
layer = new Cesium.ImageryLayer(imageryProvider); | |
} | |
layer.name = name; | |
baseLayers.push(layer); | |
} | |
function addAdditionalLayerOption(name, imageryProvider, alpha, show) { | |
var layer = imageryLayers.addImageryProvider(imageryProvider); | |
layer.alpha = Cesium.defaultValue(alpha, 0.5); | |
layer.show = Cesium.defaultValue(show, true); | |
layer.name = name; | |
Cesium.knockout.track(layer, ['alpha', 'show', 'name']); | |
} | |
function updateLayerList() { | |
var numLayers = imageryLayers.length; | |
viewModel.layers.splice(0, viewModel.layers.length); | |
for (var i = numLayers - 1; i >= 0; --i) { | |
viewModel.layers.push(imageryLayers.get(i)); | |
} | |
} | |
setupLayers(); | |
updateLayerList(); | |
//Bind the viewModel to the DOM elements of the UI that call for it. | |
var toolbar = document.getElementById('toolbar'); | |
Cesium.knockout.applyBindings(viewModel, toolbar); | |
Cesium.knockout.getObservable(viewModel, 'selectedLayer').subscribe(function(baseLayer) { | |
// Handle changes to the drop-down base layer selector. | |
var activeLayerIndex = 0; | |
var numLayers = viewModel.layers.length; | |
for (var i = 0; i < numLayers; ++i) { | |
if (viewModel.isSelectableLayer(viewModel.layers[i])) { | |
activeLayerIndex = i; | |
break; | |
} | |
} | |
var activeLayer = viewModel.layers[activeLayerIndex]; | |
var show = activeLayer.show; | |
var alpha = activeLayer.alpha; | |
imageryLayers.remove(activeLayer, false); | |
imageryLayers.add(baseLayer, numLayers - activeLayerIndex - 1); | |
baseLayer.show = show; | |
baseLayer.alpha = alpha; | |
updateLayerList(); | |
}); | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment