UNPKG

openlayers

Version:

Build tools and sources for developing OpenLayers based mapping applications

388 lines (363 loc) 14.5 kB
goog.provide('ol.render.canvas.PolygonReplay'); goog.require('ol'); goog.require('ol.array'); 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, true, 1 ]); } 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, true, 1 ]); } 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, true, 1 ]); } 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 || !ol.array.equals(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, true, 1 ]); state.currentStrokeStyle = strokeStyle; state.currentLineCap = lineCap; state.currentLineDash = lineDash; state.currentLineJoin = lineJoin; state.currentLineWidth = lineWidth; state.currentMiterLimit = miterLimit; } } };