Skip to content

Commit

Permalink
Adding new renderer: GridLayer
Browse files Browse the repository at this point in the history
  • Loading branch information
erikvullings committed Oct 14, 2015
1 parent 6cdeeb5 commit d572350
Show file tree
Hide file tree
Showing 5 changed files with 336 additions and 2 deletions.
54 changes: 54 additions & 0 deletions csComp/helpers/ColorExt.ts
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);
}

}
}
156 changes: 156 additions & 0 deletions csComp/services/map/layerRenderers/canvasOverlay.ts
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 csComp/services/map/layerRenderers/gridLayerRenderer.ts
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');
}
}
}
7 changes: 5 additions & 2 deletions csComp/services/map/renderers/leafletRenderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -175,14 +175,17 @@ module csComp.Services {

public addLayer(layer: ProjectLayer) {
switch (layer.renderType) {
case "geojson":
GeojsonRenderer.render(this.service, layer, this);
break;
case "tilelayer":
TileLayerRenderer.render(this.service, layer);
break;
case "wms":
WmsRenderer.render(this.service, layer);
break;
case "geojson":
GeojsonRenderer.render(this.service, layer, this);
case "gridlayer":

break;
case "heatmap":
HeatmapRenderer.render(this.service, layer, this);
Expand Down
3 changes: 3 additions & 0 deletions csComp/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@
"directives/Widgets/SimTimeController/SimTimeController.ts",
"directives/Widgets/SimTimeController/SimTimeControllerCtrl.ts",
"directives/Widgets/SimTimeController/SimTimeControllerEditCtrl.ts",
"helpers/ColorExt.ts",
"helpers/conrec.ts",
"helpers/DateExt.ts",
"helpers/Dictionary.ts",
Expand Down Expand Up @@ -197,7 +198,9 @@
"services/layer/sources/RssDataSource.ts",
"services/layer/sources/TileLayerSource.ts",
"services/layer/sources/WmsSource.ts",
"services/map/layerRenderers/canvasOverlay.ts",
"services/map/layerRenderers/geojsonRenderer.ts",
"services/map/layerRenderers/gridLayerRenderer.ts",
"services/map/layerRenderers/heatmapRenderer.ts",
"services/map/layerRenderers/tileLayerRenderer.ts",
"services/map/layerRenderers/wmsRenderer.ts",
Expand Down

0 comments on commit d572350

Please sign in to comment.