-
Notifications
You must be signed in to change notification settings - Fork 18
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
6cdeeb5
commit d572350
Showing
5 changed files
with
336 additions
and
2 deletions.
There are no files selected for viewing
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
module ColorExt { | ||
/** Color utility class */ | ||
export class Utils { | ||
|
||
/** | ||
* HSV to RGB color conversion. | ||
* | ||
* HSV: | ||
* Hue (the actual color between 0 and 360 degrees), | ||
* Saturation between 0 (grey) and 100 (full color), | ||
* Value of Brightness between 0 (black) and 100 white. | ||
*/ | ||
public static hsv2rgb(h, s, v) { | ||
// adapted from http://schinckel.net/2012/01/10/hsv-to-rgb-in-javascript/ | ||
var rgb, i, data = []; | ||
if (s === 0) { | ||
rgb = [v, v, v]; | ||
} else { | ||
h = h / 60; | ||
i = Math.floor(h); | ||
data = [v * (1 - s), v * (1 - s * (h - i)), v * (1 - s * (1 - (h - i)))]; | ||
switch (i) { | ||
case 0: | ||
rgb = [v, data[2], data[0]]; | ||
break; | ||
case 1: | ||
rgb = [data[1], v, data[0]]; | ||
break; | ||
case 2: | ||
rgb = [data[0], v, data[2]]; | ||
break; | ||
case 3: | ||
rgb = [data[0], data[1], v]; | ||
break; | ||
case 4: | ||
rgb = [data[2], data[0], v]; | ||
break; | ||
default: | ||
rgb = [v, data[0], data[1]]; | ||
break; | ||
} | ||
} | ||
return '#' + rgb.map(function(x) { | ||
return ("0" + Math.round(x * 255).toString(16)).slice(-2); | ||
}).join(''); | ||
} | ||
|
||
public static toColor(val: number, min: number, max: number, primaryColorHue: number, secondaryColorHue) { | ||
var h = primaryColorHue + Math.floor(val/(max-min) * (secondaryColorHue - primaryColorHue)); | ||
return Utils.hsv2rgb(h, 1, 1); | ||
} | ||
|
||
} | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,156 @@ | ||
/* | ||
Generic Canvas Overlay for leaflet, | ||
Stanislav Sumbera, April , 2014 | ||
- added userDrawFunc that is called when Canvas need to be redrawn | ||
- added few useful params for userDrawFunc callback | ||
- fixed resize map bug | ||
inspired & portions taken from : https://github.com/Leaflet/Leaflet.heat | ||
*/ | ||
|
||
module L { | ||
var CanvasOverlay = L.Class.extend({ | ||
initialize: function(userDrawFunc, options) { | ||
this._userDrawFunc = userDrawFunc; | ||
Util.setOptions(this, options); | ||
}, | ||
|
||
drawing: function(userDrawFunc) { | ||
this._userDrawFunc = userDrawFunc; | ||
return this; | ||
}, | ||
|
||
params: function(options) { | ||
Util.setOptions(this, options); | ||
return this; | ||
}, | ||
|
||
canvas: function() { | ||
return this._canvas; | ||
}, | ||
|
||
redraw: function() { | ||
if (!this._frame) { | ||
this._frame = (<any>L.Util).requestAnimFrame(this._redraw, this); | ||
} | ||
return this; | ||
}, | ||
|
||
onAdd: function(map) { | ||
this._map = map; | ||
this._canvas = L.DomUtil.create('canvas', 'leaflet-heatmap-layer'); | ||
|
||
var size = this._map.getSize(); | ||
this._canvas.width = size.x; | ||
this._canvas.height = size.y; | ||
|
||
var animated = this._map.options.zoomAnimation && (<any>L.Browser).any3d; | ||
L.DomUtil.addClass(this._canvas, 'leaflet-zoom-' + (animated ? 'animated' : 'hide')); | ||
|
||
map._panes.overlayPane.appendChild(this._canvas); | ||
|
||
map.on('moveend', this._reset, this); | ||
map.on('resize', this._resize, this); | ||
|
||
if (map.options.zoomAnimation && (<any>L.Browser).any3d) { | ||
map.on('zoomanim', this._animateZoom, this); | ||
} | ||
|
||
this._reset(); | ||
}, | ||
|
||
onRemove: function(map) { | ||
map.getPanes().overlayPane.removeChild(this._canvas); | ||
|
||
map.off('moveend', this._reset, this); | ||
map.off('resize', this._resize, this); | ||
|
||
if (map.options.zoomAnimation) { | ||
map.off('zoomanim', this._animateZoom, this); | ||
} | ||
this._canvas = null; | ||
}, | ||
|
||
addTo: function(map) { | ||
map.addLayer(this); | ||
return this; | ||
}, | ||
|
||
_resize: function(resizeEvent) { | ||
this._canvas.width = resizeEvent.newSize.x; | ||
this._canvas.height = resizeEvent.newSize.y; | ||
}, | ||
|
||
_reset: function() { | ||
var topLeft = this._map.containerPointToLayerPoint([0, 0]); | ||
L.DomUtil.setPosition(this._canvas, topLeft); | ||
this._redraw(); | ||
}, | ||
|
||
_redraw: function() { | ||
var size = this._map.getSize(); | ||
var bounds = this._map.getBounds(); | ||
var zoomScale = (size.x * 180) / (20037508.34 * (bounds.getEast() - bounds.getWest())); // resolution = 1/zoomScale | ||
var zoom = this._map.getZoom(); | ||
|
||
// console.time('process'); | ||
|
||
if (this._userDrawFunc) { | ||
this._userDrawFunc(this, | ||
{ | ||
canvas: this._canvas, | ||
bounds: bounds, | ||
size: size, | ||
zoomScale: zoomScale, | ||
zoom: zoom, | ||
options: this.options | ||
}); | ||
} | ||
|
||
// console.timeEnd('process'); | ||
this._frame = null; | ||
}, | ||
|
||
_animateZoom: function(e) { | ||
var scale = this._map.getZoomScale(e.zoom), | ||
offset = this._map._getCenterOffset(e.center)._multiplyBy(-scale).subtract(this._map._getMapPanePos()); | ||
|
||
this._canvas.style[L.DomUtil.TRANSFORM] = L.DomUtil.getTranslateString(offset) + ' scale(' + scale + ')'; | ||
} | ||
}); | ||
|
||
export interface IUserDrawSettings { | ||
/** Canvas element for drawing */ | ||
canvas: HTMLCanvasElement; | ||
/** Bounds of the map in WGS84 */ | ||
bounds: L.Bounds; | ||
/** Size of the map in pixels in x and y direction */ | ||
size: { | ||
x: number; | ||
y: number; | ||
}; | ||
/** Zoom scale, e.g. 0.0026 */ | ||
zoomScale: number; | ||
/** Zoom level, e.g. 12 */ | ||
zoom: number; | ||
options: { | ||
// Grid data values | ||
data: number[][], | ||
// Values that must be ignored | ||
noDataValue: number, | ||
topLeftLat: number, | ||
topLeftLon: number, | ||
deltaLat: number, | ||
deltaLon: number, | ||
/** A value between 0 (transparent) and 1 (opaque) */ | ||
opacity?: number, | ||
legend?: { val: number, color: string}[], | ||
[key: string]: any | ||
} | ||
} | ||
|
||
export function canvasOverlay(userDrawFunc: (overlay: any, settings: IUserDrawSettings) => void, options: Object) { | ||
return new CanvasOverlay(userDrawFunc, options); | ||
}; | ||
} |
118 changes: 118 additions & 0 deletions
118
csComp/services/map/layerRenderers/gridLayerRenderer.ts
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
module csComp.Services { | ||
export class GridLayerRenderer { | ||
static render(service: LayerService, layer: ProjectLayer) { | ||
var legend: { val: number, color: string }[] = []; | ||
var levels = [0.1, 0.5, 1, 2, 3, 4, 5]; | ||
for (let i = 0; i < levels.length; i++) { | ||
let level = levels[i]; | ||
legend.push({ val: level, color: ColorExt.Utils.toColor(level, levels[0], levels[levels.length - 1], 180, 240) }); | ||
} | ||
|
||
var overlay = L.canvasOverlay(GridLayerRenderer.drawFunction, { | ||
// data: data, | ||
noDataValue: -9999, | ||
topLeftLat: 51.99990035800966, | ||
topLeftLon: 4.624149821641468, | ||
deltaLat: -0.0008877220420775024, | ||
deltaLon: 0.0014584581460220312, | ||
legend: legend, | ||
opacity: 0.6 | ||
}); | ||
|
||
layer.mapLayer = new L.LayerGroup<L.ILayer>(); | ||
service.map.map.addLayer(layer.mapLayer); | ||
layer.mapLayer.addLayer(overlay); | ||
|
||
// var wms: any = L.tileLayer.wms(layer.url, <any>{ | ||
// layers: layer.wmsLayers, | ||
// opacity: layer.opacity / 100, | ||
// format: 'image/png', | ||
// transparent: true, | ||
// attribution: layer.description, | ||
// tiled: true | ||
// }); | ||
// layer.mapLayer = new L.LayerGroup<L.ILayer>(); | ||
// service.map.map.addLayer(layer.mapLayer); | ||
// layer.mapLayer.addLayer(wms); | ||
// wms.on('loading', (event) => { | ||
// layer.isLoading = true; | ||
// service.$rootScope.$apply(); | ||
// if (service.$rootScope.$$phase != '$apply' && service.$rootScope.$$phase != '$digest') { service.$rootScope.$apply(); } | ||
// }); | ||
// wms.on('load', (event) => { | ||
// layer.isLoading = false; | ||
// if (service.$rootScope.$$phase != '$apply' && service.$rootScope.$$phase != '$digest') { service.$rootScope.$apply(); } | ||
// }); | ||
// layer.isLoading = true; | ||
} | ||
|
||
static drawFunction(overlay: any, settings: L.IUserDrawSettings) { | ||
var map: L.Map = (<any>this)._map; | ||
var opt = settings.options, | ||
data = opt.data; | ||
|
||
var row = data.length, | ||
col = data[0].length, | ||
size = settings.size, | ||
legend = opt.legend; | ||
|
||
var topLeft = map.latLngToContainerPoint(new L.LatLng(opt.topLeftLat, opt.topLeftLon)), | ||
botRight = map.latLngToContainerPoint(new L.LatLng(opt.topLeftLat + row * opt.deltaLat, opt.topLeftLon + col * opt.deltaLon)); | ||
|
||
var startX = topLeft.x, | ||
startY = topLeft.y, | ||
deltaX = (botRight.x - topLeft.x) / col, | ||
deltaY = (botRight.y - topLeft.y) / row; | ||
|
||
var ctx = settings.canvas.getContext("2d"); | ||
ctx.clearRect(0, 0, size.x, size.y); | ||
|
||
// Check the boundaries | ||
if (startX > size.x || startY > size.y || botRight.x < 0 || botRight.y < 0) { | ||
//console.log('Outside boundary'); | ||
return; | ||
} | ||
var sI = 0, | ||
sJ = 0, | ||
eI = row, | ||
eJ = col; | ||
|
||
if (startX < -deltaX) { | ||
sJ = -Math.ceil(startX / deltaX); | ||
startX += sJ * deltaX; | ||
} | ||
if (startY < -deltaY) { | ||
sI = -Math.ceil(startY / deltaY); | ||
//startY += sI * deltaY; | ||
} | ||
if (botRight.x > size.x) { | ||
eJ -= Math.floor((botRight.x - size.x) / deltaX); | ||
} | ||
if (botRight.y > size.y) { | ||
eI -= Math.floor((botRight.y - size.y) / deltaY); | ||
} | ||
|
||
//console.log(`Bounds: ${JSON.stringify(settings, null, 2)}`); | ||
var noDataValue = opt.noDataValue; | ||
|
||
ctx.globalAlpha = opt.opacity || 0.3; | ||
|
||
console.time('process'); | ||
for (var i = sI; i < eI; i++) { | ||
let x = startX - deltaX; | ||
let y = startY + i * deltaY; | ||
for (var j = sJ; j < eJ; j++) { | ||
x += deltaX; | ||
var cell = data[i][j]; | ||
if (cell === noDataValue) continue; | ||
var closest = legend.reduce(function(prev, curr) { | ||
return (Math.abs(curr.val - cell) < Math.abs(prev.val - cell) ? curr : prev); | ||
}); | ||
ctx.fillStyle = closest.color; | ||
ctx.fillRect(x, y, deltaX, deltaY); | ||
} | ||
} | ||
console.timeEnd('process'); | ||
} | ||
} | ||
} |
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
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