Reworked raster source rendering
This commit is contained in:
+75
-106
@@ -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);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user