380 lines
14 KiB
JavaScript
380 lines
14 KiB
JavaScript
goog.provide('ol.render.canvas.PolygonReplay');
|
|
|
|
goog.require('ol');
|
|
goog.require('ol.color');
|
|
goog.require('ol.colorlike');
|
|
goog.require('ol.extent');
|
|
goog.require('ol.geom.flat.simplify');
|
|
goog.require('ol.render.canvas');
|
|
goog.require('ol.render.canvas.Instruction');
|
|
goog.require('ol.render.canvas.Replay');
|
|
|
|
|
|
/**
|
|
* @constructor
|
|
* @extends {ol.render.canvas.Replay}
|
|
* @param {number} tolerance Tolerance.
|
|
* @param {ol.Extent} maxExtent Maximum extent.
|
|
* @param {number} resolution Resolution.
|
|
* @param {boolean} overlaps The replay can have overlapping geometries.
|
|
* @struct
|
|
*/
|
|
ol.render.canvas.PolygonReplay = function(tolerance, maxExtent, resolution, overlaps) {
|
|
|
|
ol.render.canvas.Replay.call(this, tolerance, maxExtent, resolution, overlaps);
|
|
|
|
/**
|
|
* @private
|
|
* @type {ol.Extent}
|
|
*/
|
|
this.bufferedMaxExtent_ = null;
|
|
|
|
/**
|
|
* @private
|
|
* @type {{currentFillStyle: (ol.ColorLike|undefined),
|
|
* currentStrokeStyle: (ol.ColorLike|undefined),
|
|
* currentLineCap: (string|undefined),
|
|
* currentLineDash: Array.<number>,
|
|
* currentLineJoin: (string|undefined),
|
|
* currentLineWidth: (number|undefined),
|
|
* currentMiterLimit: (number|undefined),
|
|
* fillStyle: (ol.ColorLike|undefined),
|
|
* strokeStyle: (ol.ColorLike|undefined),
|
|
* lineCap: (string|undefined),
|
|
* lineDash: Array.<number>,
|
|
* lineJoin: (string|undefined),
|
|
* lineWidth: (number|undefined),
|
|
* miterLimit: (number|undefined)}|null}
|
|
*/
|
|
this.state_ = {
|
|
currentFillStyle: undefined,
|
|
currentStrokeStyle: undefined,
|
|
currentLineCap: undefined,
|
|
currentLineDash: null,
|
|
currentLineJoin: undefined,
|
|
currentLineWidth: undefined,
|
|
currentMiterLimit: undefined,
|
|
fillStyle: undefined,
|
|
strokeStyle: undefined,
|
|
lineCap: undefined,
|
|
lineDash: null,
|
|
lineJoin: undefined,
|
|
lineWidth: undefined,
|
|
miterLimit: undefined
|
|
};
|
|
|
|
};
|
|
ol.inherits(ol.render.canvas.PolygonReplay, ol.render.canvas.Replay);
|
|
|
|
|
|
/**
|
|
* @param {Array.<number>} flatCoordinates Flat coordinates.
|
|
* @param {number} offset Offset.
|
|
* @param {Array.<number>} ends Ends.
|
|
* @param {number} stride Stride.
|
|
* @private
|
|
* @return {number} End.
|
|
*/
|
|
ol.render.canvas.PolygonReplay.prototype.drawFlatCoordinatess_ = function(flatCoordinates, offset, ends, stride) {
|
|
var state = this.state_;
|
|
var fill = state.fillStyle !== undefined;
|
|
var stroke = state.strokeStyle != undefined;
|
|
var numEnds = ends.length;
|
|
var beginPathInstruction = [ol.render.canvas.Instruction.BEGIN_PATH];
|
|
this.instructions.push(beginPathInstruction);
|
|
this.hitDetectionInstructions.push(beginPathInstruction);
|
|
for (var i = 0; i < numEnds; ++i) {
|
|
var end = ends[i];
|
|
var myBegin = this.coordinates.length;
|
|
var myEnd = this.appendFlatCoordinates(
|
|
flatCoordinates, offset, end, stride, true, !stroke);
|
|
var moveToLineToInstruction =
|
|
[ol.render.canvas.Instruction.MOVE_TO_LINE_TO, myBegin, myEnd];
|
|
this.instructions.push(moveToLineToInstruction);
|
|
this.hitDetectionInstructions.push(moveToLineToInstruction);
|
|
if (stroke) {
|
|
// Performance optimization: only call closePath() when we have a stroke.
|
|
// Otherwise the ring is closed already (see appendFlatCoordinates above).
|
|
var closePathInstruction = [ol.render.canvas.Instruction.CLOSE_PATH];
|
|
this.instructions.push(closePathInstruction);
|
|
this.hitDetectionInstructions.push(closePathInstruction);
|
|
}
|
|
offset = end;
|
|
}
|
|
var fillInstruction = [ol.render.canvas.Instruction.FILL];
|
|
this.hitDetectionInstructions.push(fillInstruction);
|
|
if (fill) {
|
|
this.instructions.push(fillInstruction);
|
|
}
|
|
if (stroke) {
|
|
ol.DEBUG && console.assert(state.lineWidth !== undefined,
|
|
'state.lineWidth should be defined');
|
|
var strokeInstruction = [ol.render.canvas.Instruction.STROKE];
|
|
this.instructions.push(strokeInstruction);
|
|
this.hitDetectionInstructions.push(strokeInstruction);
|
|
}
|
|
return offset;
|
|
};
|
|
|
|
|
|
/**
|
|
* @inheritDoc
|
|
*/
|
|
ol.render.canvas.PolygonReplay.prototype.drawCircle = function(circleGeometry, feature) {
|
|
var state = this.state_;
|
|
ol.DEBUG && console.assert(state, 'state should not be null');
|
|
var fillStyle = state.fillStyle;
|
|
var strokeStyle = state.strokeStyle;
|
|
if (fillStyle === undefined && strokeStyle === undefined) {
|
|
return;
|
|
}
|
|
if (strokeStyle !== undefined) {
|
|
ol.DEBUG && console.assert(state.lineWidth !== undefined,
|
|
'state.lineWidth should be defined');
|
|
}
|
|
this.setFillStrokeStyles_(circleGeometry);
|
|
this.beginGeometry(circleGeometry, feature);
|
|
// always fill the circle for hit detection
|
|
this.hitDetectionInstructions.push(
|
|
[ol.render.canvas.Instruction.SET_FILL_STYLE,
|
|
ol.color.asString(ol.render.canvas.defaultFillStyle)]);
|
|
if (state.strokeStyle !== undefined) {
|
|
this.hitDetectionInstructions.push(
|
|
[ol.render.canvas.Instruction.SET_STROKE_STYLE,
|
|
state.strokeStyle, state.lineWidth, state.lineCap, state.lineJoin,
|
|
state.miterLimit, state.lineDash]);
|
|
}
|
|
var flatCoordinates = circleGeometry.getFlatCoordinates();
|
|
var stride = circleGeometry.getStride();
|
|
var myBegin = this.coordinates.length;
|
|
this.appendFlatCoordinates(
|
|
flatCoordinates, 0, flatCoordinates.length, stride, false, false);
|
|
var beginPathInstruction = [ol.render.canvas.Instruction.BEGIN_PATH];
|
|
var circleInstruction = [ol.render.canvas.Instruction.CIRCLE, myBegin];
|
|
this.instructions.push(beginPathInstruction, circleInstruction);
|
|
this.hitDetectionInstructions.push(beginPathInstruction, circleInstruction);
|
|
var fillInstruction = [ol.render.canvas.Instruction.FILL];
|
|
this.hitDetectionInstructions.push(fillInstruction);
|
|
if (state.fillStyle !== undefined) {
|
|
this.instructions.push(fillInstruction);
|
|
}
|
|
if (state.strokeStyle !== undefined) {
|
|
ol.DEBUG && console.assert(state.lineWidth !== undefined,
|
|
'state.lineWidth should be defined');
|
|
var strokeInstruction = [ol.render.canvas.Instruction.STROKE];
|
|
this.instructions.push(strokeInstruction);
|
|
this.hitDetectionInstructions.push(strokeInstruction);
|
|
}
|
|
this.endGeometry(circleGeometry, feature);
|
|
};
|
|
|
|
|
|
/**
|
|
* @inheritDoc
|
|
*/
|
|
ol.render.canvas.PolygonReplay.prototype.drawPolygon = function(polygonGeometry, feature) {
|
|
var state = this.state_;
|
|
ol.DEBUG && console.assert(state, 'state should not be null');
|
|
var strokeStyle = state.strokeStyle;
|
|
ol.DEBUG && console.assert(state.fillStyle !== undefined || strokeStyle !== undefined,
|
|
'fillStyle or strokeStyle should be defined');
|
|
if (strokeStyle !== undefined) {
|
|
ol.DEBUG && console.assert(state.lineWidth !== undefined,
|
|
'state.lineWidth should be defined');
|
|
}
|
|
this.setFillStrokeStyles_(polygonGeometry);
|
|
this.beginGeometry(polygonGeometry, feature);
|
|
// always fill the polygon for hit detection
|
|
this.hitDetectionInstructions.push(
|
|
[ol.render.canvas.Instruction.SET_FILL_STYLE,
|
|
ol.color.asString(ol.render.canvas.defaultFillStyle)]);
|
|
if (state.strokeStyle !== undefined) {
|
|
this.hitDetectionInstructions.push(
|
|
[ol.render.canvas.Instruction.SET_STROKE_STYLE,
|
|
state.strokeStyle, state.lineWidth, state.lineCap, state.lineJoin,
|
|
state.miterLimit, state.lineDash]);
|
|
}
|
|
var ends = polygonGeometry.getEnds();
|
|
var flatCoordinates = polygonGeometry.getOrientedFlatCoordinates();
|
|
var stride = polygonGeometry.getStride();
|
|
this.drawFlatCoordinatess_(flatCoordinates, 0, ends, stride);
|
|
this.endGeometry(polygonGeometry, feature);
|
|
};
|
|
|
|
|
|
/**
|
|
* @inheritDoc
|
|
*/
|
|
ol.render.canvas.PolygonReplay.prototype.drawMultiPolygon = function(multiPolygonGeometry, feature) {
|
|
var state = this.state_;
|
|
ol.DEBUG && console.assert(state, 'state should not be null');
|
|
var fillStyle = state.fillStyle;
|
|
var strokeStyle = state.strokeStyle;
|
|
if (fillStyle === undefined && strokeStyle === undefined) {
|
|
return;
|
|
}
|
|
if (strokeStyle !== undefined) {
|
|
ol.DEBUG && console.assert(state.lineWidth !== undefined,
|
|
'state.lineWidth should be defined');
|
|
}
|
|
this.setFillStrokeStyles_(multiPolygonGeometry);
|
|
this.beginGeometry(multiPolygonGeometry, feature);
|
|
// always fill the multi-polygon for hit detection
|
|
this.hitDetectionInstructions.push(
|
|
[ol.render.canvas.Instruction.SET_FILL_STYLE,
|
|
ol.color.asString(ol.render.canvas.defaultFillStyle)]);
|
|
if (state.strokeStyle !== undefined) {
|
|
this.hitDetectionInstructions.push(
|
|
[ol.render.canvas.Instruction.SET_STROKE_STYLE,
|
|
state.strokeStyle, state.lineWidth, state.lineCap, state.lineJoin,
|
|
state.miterLimit, state.lineDash]);
|
|
}
|
|
var endss = multiPolygonGeometry.getEndss();
|
|
var flatCoordinates = multiPolygonGeometry.getOrientedFlatCoordinates();
|
|
var stride = multiPolygonGeometry.getStride();
|
|
var offset = 0;
|
|
var i, ii;
|
|
for (i = 0, ii = endss.length; i < ii; ++i) {
|
|
offset = this.drawFlatCoordinatess_(
|
|
flatCoordinates, offset, endss[i], stride);
|
|
}
|
|
this.endGeometry(multiPolygonGeometry, feature);
|
|
};
|
|
|
|
|
|
/**
|
|
* @inheritDoc
|
|
*/
|
|
ol.render.canvas.PolygonReplay.prototype.finish = function() {
|
|
ol.DEBUG && console.assert(this.state_, 'this.state_ should not be null');
|
|
this.reverseHitDetectionInstructions();
|
|
this.state_ = null;
|
|
// We want to preserve topology when drawing polygons. Polygons are
|
|
// simplified using quantization and point elimination. However, we might
|
|
// have received a mix of quantized and non-quantized geometries, so ensure
|
|
// that all are quantized by quantizing all coordinates in the batch.
|
|
var tolerance = this.tolerance;
|
|
if (tolerance !== 0) {
|
|
var coordinates = this.coordinates;
|
|
var i, ii;
|
|
for (i = 0, ii = coordinates.length; i < ii; ++i) {
|
|
coordinates[i] = ol.geom.flat.simplify.snap(coordinates[i], tolerance);
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
/**
|
|
* @inheritDoc
|
|
*/
|
|
ol.render.canvas.PolygonReplay.prototype.getBufferedMaxExtent = function() {
|
|
if (!this.bufferedMaxExtent_) {
|
|
this.bufferedMaxExtent_ = ol.extent.clone(this.maxExtent);
|
|
if (this.maxLineWidth > 0) {
|
|
var width = this.resolution * (this.maxLineWidth + 1) / 2;
|
|
ol.extent.buffer(this.bufferedMaxExtent_, width, this.bufferedMaxExtent_);
|
|
}
|
|
}
|
|
return this.bufferedMaxExtent_;
|
|
};
|
|
|
|
|
|
/**
|
|
* @inheritDoc
|
|
*/
|
|
ol.render.canvas.PolygonReplay.prototype.setFillStrokeStyle = function(fillStyle, strokeStyle) {
|
|
ol.DEBUG && console.assert(this.state_, 'this.state_ should not be null');
|
|
ol.DEBUG && console.assert(fillStyle || strokeStyle,
|
|
'fillStyle or strokeStyle should not be null');
|
|
var state = this.state_;
|
|
if (fillStyle) {
|
|
var fillStyleColor = fillStyle.getColor();
|
|
state.fillStyle = ol.colorlike.asColorLike(fillStyleColor ?
|
|
fillStyleColor : ol.render.canvas.defaultFillStyle);
|
|
} else {
|
|
state.fillStyle = undefined;
|
|
}
|
|
if (strokeStyle) {
|
|
var strokeStyleColor = strokeStyle.getColor();
|
|
state.strokeStyle = ol.colorlike.asColorLike(strokeStyleColor ?
|
|
strokeStyleColor : ol.render.canvas.defaultStrokeStyle);
|
|
var strokeStyleLineCap = strokeStyle.getLineCap();
|
|
state.lineCap = strokeStyleLineCap !== undefined ?
|
|
strokeStyleLineCap : ol.render.canvas.defaultLineCap;
|
|
var strokeStyleLineDash = strokeStyle.getLineDash();
|
|
state.lineDash = strokeStyleLineDash ?
|
|
strokeStyleLineDash.slice() : ol.render.canvas.defaultLineDash;
|
|
var strokeStyleLineJoin = strokeStyle.getLineJoin();
|
|
state.lineJoin = strokeStyleLineJoin !== undefined ?
|
|
strokeStyleLineJoin : ol.render.canvas.defaultLineJoin;
|
|
var strokeStyleWidth = strokeStyle.getWidth();
|
|
state.lineWidth = strokeStyleWidth !== undefined ?
|
|
strokeStyleWidth : ol.render.canvas.defaultLineWidth;
|
|
var strokeStyleMiterLimit = strokeStyle.getMiterLimit();
|
|
state.miterLimit = strokeStyleMiterLimit !== undefined ?
|
|
strokeStyleMiterLimit : ol.render.canvas.defaultMiterLimit;
|
|
|
|
if (state.lineWidth > this.maxLineWidth) {
|
|
this.maxLineWidth = state.lineWidth;
|
|
// invalidate the buffered max extent cache
|
|
this.bufferedMaxExtent_ = null;
|
|
}
|
|
} else {
|
|
state.strokeStyle = undefined;
|
|
state.lineCap = undefined;
|
|
state.lineDash = null;
|
|
state.lineJoin = undefined;
|
|
state.lineWidth = undefined;
|
|
state.miterLimit = undefined;
|
|
}
|
|
};
|
|
|
|
|
|
/**
|
|
* @private
|
|
* @param {ol.geom.Geometry|ol.render.Feature} geometry Geometry.
|
|
*/
|
|
ol.render.canvas.PolygonReplay.prototype.setFillStrokeStyles_ = function(geometry) {
|
|
var state = this.state_;
|
|
var fillStyle = state.fillStyle;
|
|
var strokeStyle = state.strokeStyle;
|
|
var lineCap = state.lineCap;
|
|
var lineDash = state.lineDash;
|
|
var lineJoin = state.lineJoin;
|
|
var lineWidth = state.lineWidth;
|
|
var miterLimit = state.miterLimit;
|
|
if (fillStyle !== undefined && (typeof fillStyle !== 'string' || state.currentFillStyle != fillStyle)) {
|
|
var fillInstruction = [ol.render.canvas.Instruction.SET_FILL_STYLE, fillStyle];
|
|
if (typeof fillStyle !== 'string') {
|
|
var fillExtent = geometry.getExtent();
|
|
fillInstruction.push([fillExtent[0], fillExtent[3]]);
|
|
}
|
|
this.instructions.push(fillInstruction);
|
|
state.currentFillStyle = state.fillStyle;
|
|
}
|
|
if (strokeStyle !== undefined) {
|
|
ol.DEBUG && console.assert(lineCap !== undefined, 'lineCap should be defined');
|
|
ol.DEBUG && console.assert(lineDash, 'lineDash should not be null');
|
|
ol.DEBUG && console.assert(lineJoin !== undefined, 'lineJoin should be defined');
|
|
ol.DEBUG && console.assert(lineWidth !== undefined, 'lineWidth should be defined');
|
|
ol.DEBUG && console.assert(miterLimit !== undefined,
|
|
'miterLimit should be defined');
|
|
if (state.currentStrokeStyle != strokeStyle ||
|
|
state.currentLineCap != lineCap ||
|
|
state.currentLineDash != lineDash ||
|
|
state.currentLineJoin != lineJoin ||
|
|
state.currentLineWidth != lineWidth ||
|
|
state.currentMiterLimit != miterLimit) {
|
|
this.instructions.push(
|
|
[ol.render.canvas.Instruction.SET_STROKE_STYLE,
|
|
strokeStyle, lineWidth, lineCap, lineJoin, miterLimit, lineDash]);
|
|
state.currentStrokeStyle = strokeStyle;
|
|
state.currentLineCap = lineCap;
|
|
state.currentLineDash = lineDash;
|
|
state.currentLineJoin = lineJoin;
|
|
state.currentLineWidth = lineWidth;
|
|
state.currentMiterLimit = miterLimit;
|
|
}
|
|
}
|
|
};
|