diff --git a/examples/raster.js b/examples/raster.js index 37ea3d5596..e62c55b208 100644 --- a/examples/raster.js +++ b/examples/raster.js @@ -7,7 +7,7 @@ goog.require('ol.layer.Tile'); goog.require('ol.source.BingMaps'); goog.require('ol.source.Raster'); -function tgi(pixels) { +function tgi(pixels, data) { var pixel = pixels[0]; var r = pixel[0] / 255; var g = pixel[1] / 255; @@ -17,20 +17,17 @@ function tgi(pixels) { return pixels; } -var counts = new Counts(0, 25); -function summarize(pixels) { +function summarize(pixels, data) { var value = pixels[0][0]; - counts.increment(value); + data.counts.increment(value); return pixels; } -var threshold = 10; - -function color(pixels) { +function color(pixels, data) { var pixel = pixels[0]; var value = pixel[0]; - if (value > threshold) { + if (value > data.threshold) { pixel[0] = 0; pixel[1] = 255; pixel[2] = 0; @@ -51,12 +48,17 @@ var raster = new ol.source.Raster({ operations: [tgi, summarize, color] }); -raster.on('beforeoperations', function() { +var counts = new Counts(0, 25); +var threshold = 10; + +raster.on('beforeoperations', function(event) { counts.clear(); + event.data.counts = counts; + event.data.threshold = threshold; }); raster.on('afteroperations', function(event) { - schedulePlot(event.resolution); + schedulePlot(event.resolution, event.data.counts); }); var map = new ol.Map({ @@ -114,12 +116,12 @@ Counts.prototype.increment = function(value) { }; var timer = null; -function schedulePlot(resolution) { +function schedulePlot(resolution, counts) { if (timer) { clearTimeout(timer); timer = null; } - timer = setTimeout(plot.bind(null, resolution), 1000 / 60); + timer = setTimeout(plot.bind(null, resolution, counts), 1000 / 60); } var barWidth = 15; @@ -133,7 +135,7 @@ var chartRect = chart[0][0].getBoundingClientRect(); var tip = d3.select(document.body).append('div') .attr('class', 'tip'); -function plot(resolution) { +function plot(resolution, counts) { var yScale = d3.scale.linear() .domain([0, d3.max(counts.values)]) .range([0, plotHeight]); diff --git a/externs/oli.js b/externs/oli.js index 56b8afb229..7d1631024d 100644 --- a/externs/oli.js +++ b/externs/oli.js @@ -284,6 +284,12 @@ oli.source.RasterEvent.prototype.extent; oli.source.RasterEvent.prototype.resolution; +/** + * @type {Object} + */ +oli.source.RasterEvent.prototype.data; + + /** * @interface */ diff --git a/src/ol/raster/operation.js b/src/ol/raster/operation.js index b88d99c8af..340bc37ff7 100644 --- a/src/ol/raster/operation.js +++ b/src/ol/raster/operation.js @@ -21,9 +21,12 @@ ol.raster.OperationType = { * return an array of the same. For `'image'` type operations, functions will * be called with an array of {@link ImageData * https://developer.mozilla.org/en-US/docs/Web/API/ImageData} and should return - * an array of the same. + * an array of the same. The operations are called with a second "data" + * argument, which can be used for storage. The data object is accessible + * from raster events, where it can be initialized in "beforeoperations" and + * accessed again in "afteroperations." * - * @typedef {function((Array.|Array.)): + * @typedef {function((Array.|Array.), Object): * (Array.|Array.)} * @api */ diff --git a/src/ol/source/rastersource.js b/src/ol/source/rastersource.js index cc51c561b4..09bc5f28f3 100644 --- a/src/ol/source/rastersource.js +++ b/src/ol/source/rastersource.js @@ -223,8 +223,9 @@ ol.source.Raster.prototype.composeFrame_ = function(frameState) { this.renderers_[i], frameState, frameState.layerStatesArray[i]); } + var data = {}; this.dispatchEvent(new ol.source.RasterEvent( - ol.source.RasterEventType.BEFOREOPERATIONS, frameState)); + ol.source.RasterEventType.BEFOREOPERATIONS, frameState, data)); var targetImageData = null; if (this.operationType_ === ol.raster.OperationType.PIXEL) { @@ -242,20 +243,20 @@ ol.source.Raster.prototype.composeFrame_ = function(frameState) { pixel[2] = source[j + 2]; pixel[3] = source[j + 3]; } - pixel = this.runPixelOperations_(pixels)[0]; + pixel = this.runPixelOperations_(pixels, data)[0]; target[j] = pixel[0]; target[j + 1] = pixel[1]; target[j + 2] = pixel[2]; target[j + 3] = pixel[3]; } } else if (this.operationType_ === ol.raster.OperationType.IMAGE) { - targetImageData = this.runImageOperations_(imageDatas)[0]; + targetImageData = this.runImageOperations_(imageDatas, data)[0]; } else { goog.asserts.fail('unsupported operation type: ' + this.operationType_); } this.dispatchEvent(new ol.source.RasterEvent( - ol.source.RasterEventType.AFTEROPERATIONS, frameState)); + ol.source.RasterEventType.AFTEROPERATIONS, frameState, data)); context.putImageData(targetImageData, 0, 0); @@ -266,12 +267,13 @@ ol.source.Raster.prototype.composeFrame_ = function(frameState) { /** * Run pixel-wise operations to transform pixels. * @param {Array.} pixels The input pixels. + * @param {Object} data User storage. * @return {Array.} The modified pixels. * @private */ -ol.source.Raster.prototype.runPixelOperations_ = function(pixels) { +ol.source.Raster.prototype.runPixelOperations_ = function(pixels, data) { for (var i = 0, ii = this.operations_.length; i < ii; ++i) { - pixels = this.operations_[i](pixels); + pixels = this.operations_[i](pixels, data); } return pixels; }; @@ -280,12 +282,13 @@ ol.source.Raster.prototype.runPixelOperations_ = function(pixels) { /** * Run image operations. * @param {Array.} imageDatas The input image data. + * @param {Object} data User storage. * @return {Array.} The output image data. * @private */ -ol.source.Raster.prototype.runImageOperations_ = function(imageDatas) { +ol.source.Raster.prototype.runImageOperations_ = function(imageDatas, data) { for (var i = 0, ii = this.operations_.length; i < ii; ++i) { - imageDatas = this.operations_[i](imageDatas); + imageDatas = this.operations_[i](imageDatas, data); } return imageDatas; }; @@ -396,8 +399,9 @@ ol.source.Raster.createTileRenderer_ = function(source) { * @implements {oli.source.RasterEvent} * @param {string} type Type. * @param {olx.FrameState} frameState The frame state. + * @param {Object} data An object made available to operations. */ -ol.source.RasterEvent = function(type, frameState) { +ol.source.RasterEvent = function(type, frameState, data) { goog.base(this, type); /** @@ -414,6 +418,14 @@ ol.source.RasterEvent = function(type, frameState) { */ this.resolution = frameState.viewState.resolution / frameState.pixelRatio; + /** + * An object made available to all operations. This can be used by operations + * as a storage object (e.g. for calculating statistics). + * @type {Object} + * @api + */ + this.data = data; + }; goog.inherits(ol.source.RasterEvent, goog.events.Event);