Reworked raster source rendering

This commit is contained in:
Tim Schaub
2017-03-30 22:02:54 -06:00
parent 7f74f238fd
commit a65e30fe41
+75 -106
View File
@@ -65,12 +65,6 @@ ol.source.Raster = function(options) {
this.changed, this); this.changed, this);
} }
/**
* @private
* @type {CanvasRenderingContext2D}
*/
this.canvasContext_ = ol.dom.createCanvasContext2D();
/** /**
* @private * @private
* @type {ol.TileQueue} * @type {ol.TileQueue}
@@ -88,11 +82,11 @@ ol.source.Raster = function(options) {
} }
/** /**
* The most recently rendered state. * The most recently requested frame state.
* @type {?ol.SourceRasterRenderedState} * @type {olx.FrameState}
* @private * @private
*/ */
this.renderedState_ = null; this.requestedFrameState_;
/** /**
* The most recently rendered image canvas. * The most recently rendered image canvas.
@@ -101,6 +95,12 @@ ol.source.Raster = function(options) {
*/ */
this.renderedImageCanvas_ = null; this.renderedImageCanvas_ = null;
/**
* The most recently rendered revision.
* @type {number}
*/
this.renderedRevision_;
/** /**
* @private * @private
* @type {olx.FrameState} * @type {olx.FrameState}
@@ -176,13 +176,11 @@ ol.source.Raster.prototype.updateFrameState_ = function(extent, resolution, proj
ol.obj.assign({}, frameState.viewState)); ol.obj.assign({}, frameState.viewState));
var center = ol.extent.getCenter(extent); var center = ol.extent.getCenter(extent);
var width = Math.round(ol.extent.getWidth(extent) / resolution);
var height = Math.round(ol.extent.getHeight(extent) / resolution);
frameState.extent = extent; frameState.extent = extent.slice();
frameState.focus = ol.extent.getCenter(extent); frameState.focus = center;
frameState.size[0] = width; frameState.size[0] = Math.round(ol.extent.getWidth(extent) / resolution);
frameState.size[1] = height; frameState.size[1] = Math.round(ol.extent.getHeight(extent) / resolution);
var viewState = frameState.viewState; var viewState = frameState.viewState;
viewState.center = center; viewState.center = center;
@@ -192,66 +190,6 @@ ol.source.Raster.prototype.updateFrameState_ = function(extent, resolution, proj
}; };
/**
* Determine if the most recently rendered image canvas is dirty.
* @param {ol.Extent} extent The requested extent.
* @param {number} resolution The requested resolution.
* @return {boolean} The image is dirty.
* @private
*/
ol.source.Raster.prototype.isDirty_ = function(extent, resolution) {
var state = this.renderedState_;
return !state ||
this.getRevision() !== state.revision ||
resolution !== state.resolution ||
!ol.extent.equals(extent, state.extent);
};
/**
* @inheritDoc
*/
ol.source.Raster.prototype.getImage = function(extent, resolution, pixelRatio, projection) {
if (!this.allSourcesReady_()) {
return null;
}
var currentExtent = extent.slice();
if (!this.isDirty_(currentExtent, resolution)) {
return this.renderedImageCanvas_;
}
var context = this.canvasContext_;
var canvas = context.canvas;
var width = Math.round(ol.extent.getWidth(currentExtent) / resolution);
var height = Math.round(ol.extent.getHeight(currentExtent) / resolution);
if (width !== canvas.width ||
height !== canvas.height) {
canvas.width = width;
canvas.height = height;
}
var frameState = this.updateFrameState_(currentExtent, resolution, projection);
var imageCanvas = new ol.ImageCanvas(
currentExtent, resolution, 1, this.getAttributions(), canvas,
this.composeFrame_.bind(this, frameState));
this.renderedImageCanvas_ = imageCanvas;
this.renderedState_ = {
extent: currentExtent,
resolution: resolution,
revision: this.getRevision()
};
return imageCanvas;
};
/** /**
* Determine if all sources are ready. * Determine if all sources are ready.
* @return {boolean} All sources are ready. * @return {boolean} All sources are ready.
@@ -272,13 +210,41 @@ ol.source.Raster.prototype.allSourcesReady_ = function() {
/** /**
* Compose the frame. This renders data from all sources, runs pixel-wise * @inheritDoc
* operations, and renders the result to the stored canvas context. */
* @param {olx.FrameState} frameState The frame state. ol.source.Raster.prototype.getImage = function(extent, resolution, pixelRatio, projection) {
* @param {function(Error)} callback Called when composition is complete. if (!this.allSourcesReady_()) {
return null;
}
var frameState = this.updateFrameState_(extent, resolution, projection);
this.requestedFrameState_ = frameState;
frameState.tileQueue.loadMoreTiles(16, 16);
// check if we can't reuse the existing ol.ImageCanvas
if (this.renderedImageCanvas_) {
var renderedResolution = this.renderedImageCanvas_.getResolution();
var renderedExtent = this.renderedImageCanvas_.getExtent();
if (resolution !== renderedResolution || !ol.extent.equals(extent, renderedExtent)) {
this.renderedImageCanvas_ = null;
}
}
if (!this.renderedImageCanvas_ || this.getRevision() !== this.renderedRevision_) {
this.processSources_();
}
return this.renderedImageCanvas_;
};
/**
* Start processing source data.
* @private * @private
*/ */
ol.source.Raster.prototype.composeFrame_ = function(frameState, callback) { ol.source.Raster.prototype.processSources_ = function() {
var frameState = this.requestedFrameState_;
var len = this.renderers_.length; var len = this.renderers_.length;
var imageDatas = new Array(len); var imageDatas = new Array(len);
for (var i = 0; i < len; ++i) { for (var i = 0; i < len; ++i) {
@@ -287,53 +253,56 @@ ol.source.Raster.prototype.composeFrame_ = function(frameState, callback) {
if (imageData) { if (imageData) {
imageDatas[i] = imageData; imageDatas[i] = imageData;
} else { } else {
// image not yet ready return;
imageDatas = null;
break;
} }
} }
if (imageDatas) { var data = {};
var data = {}; this.dispatchEvent(new ol.source.Raster.Event(
this.dispatchEvent(new ol.source.Raster.Event( ol.source.Raster.EventType_.BEFOREOPERATIONS, frameState, data));
ol.source.Raster.EventType_.BEFOREOPERATIONS, frameState, data)); this.worker_.process(imageDatas, data,
this.onWorkerComplete_.bind(this, frameState));
this.worker_.process(imageDatas, data,
this.onWorkerComplete_.bind(this, frameState, callback));
}
frameState.tileQueue.loadMoreTiles(16, 16);
}; };
/** /**
* Called when pixel processing is complete. * Called when pixel processing is complete.
* @param {olx.FrameState} frameState The frame state. * @param {olx.FrameState} frameState The frame state.
* @param {function(Error)} callback Called when rendering is complete.
* @param {Error} err Any error during processing. * @param {Error} err Any error during processing.
* @param {ImageData} output The output image data. * @param {ImageData} output The output image data.
* @param {Object} data The user data. * @param {Object} data The user data.
* @private * @private
*/ */
ol.source.Raster.prototype.onWorkerComplete_ = function(frameState, callback, err, output, data) { ol.source.Raster.prototype.onWorkerComplete_ = function(frameState, err, output, data) {
if (err) { if (err || !output) {
callback(err);
return; return;
} }
if (!output) {
// job aborted // do nothing if extent or resolution changed
var extent = frameState.extent;
var resolution = frameState.viewState.resolution;
if (resolution !== this.requestedFrameState_.viewState.resolution ||
!ol.extent.equals(extent, this.requestedFrameState_.extent)) {
return; return;
} }
var context;
if (this.renderedImageCanvas_) {
context = this.renderedImageCanvas_.getImage().getContext('2d');
} else {
var width = Math.round(ol.extent.getWidth(extent) / resolution);
var height = Math.round(ol.extent.getHeight(extent) / resolution);
context = ol.dom.createCanvasContext2D(width, height);
this.renderedImageCanvas_ = new ol.ImageCanvas(
extent, resolution, 1, this.getAttributions(), context.canvas);
}
context.putImageData(output, 0, 0);
this.changed();
this.renderedRevision_ = this.getRevision();
this.dispatchEvent(new ol.source.Raster.Event( this.dispatchEvent(new ol.source.Raster.Event(
ol.source.Raster.EventType_.AFTEROPERATIONS, frameState, data)); ol.source.Raster.EventType_.AFTEROPERATIONS, frameState, data));
var resolution = frameState.viewState.resolution / frameState.pixelRatio;
if (!this.isDirty_(frameState.extent, resolution)) {
this.canvasContext_.putImageData(output, 0, 0);
}
callback(null);
}; };