From 18f3d7243daf1fee5f98aae912ab1642d66ce8a2 Mon Sep 17 00:00:00 2001 From: Andreas Hocevar Date: Wed, 30 Mar 2016 22:10:58 +0200 Subject: [PATCH 1/2] Batch polygon fill and stroke instructions --- src/ol/render/canvas/canvasreplay.js | 65 +++++++++++++++++++--------- 1 file changed, 45 insertions(+), 20 deletions(-) diff --git a/src/ol/render/canvas/canvasreplay.js b/src/ol/render/canvas/canvasreplay.js index b907b04eb5..cacf01d346 100644 --- a/src/ol/render/canvas/canvasreplay.js +++ b/src/ol/render/canvas/canvasreplay.js @@ -1196,7 +1196,9 @@ ol.render.canvas.PolygonReplay = function(tolerance, maxExtent, resolution) { * lineDash: Array., * lineJoin: (string|undefined), * lineWidth: (number|undefined), - * miterLimit: (number|undefined)}|null} + * miterLimit: (number|undefined), + * pendingFill: number, + * pendingStroke: number}|null} */ this.state_ = { currentFillStyle: undefined, @@ -1212,7 +1214,9 @@ ol.render.canvas.PolygonReplay = function(tolerance, maxExtent, resolution) { lineDash: null, lineJoin: undefined, lineWidth: undefined, - miterLimit: undefined + miterLimit: undefined, + pendingFill: 0, + pendingStroke: 0 }; }; @@ -1229,8 +1233,13 @@ goog.inherits(ol.render.canvas.PolygonReplay, ol.render.canvas.Replay); */ ol.render.canvas.PolygonReplay.prototype.drawFlatCoordinatess_ = function(flatCoordinates, offset, ends, stride) { var state = this.state_; + if (state.pendingFill > 200 || state.pendingStroke > 200) { + this.fillStroke_(); + } var beginPathInstruction = [ol.render.canvas.Instruction.BEGIN_PATH]; - this.instructions.push(beginPathInstruction); + if (!state.pendingFill && !state.pendingStroke) { + this.instructions.push(beginPathInstruction); + } this.hitDetectionInstructions.push(beginPathInstruction); var i, ii; for (i = 0, ii = ends.length; i < ii; ++i) { @@ -1246,19 +1255,15 @@ ol.render.canvas.PolygonReplay.prototype.drawFlatCoordinatess_ = function(flatCo closePathInstruction); offset = end; } - // FIXME is it quicker to fill and stroke each polygon individually, - // FIXME or all polygons together? - var fillInstruction = [ol.render.canvas.Instruction.FILL]; - this.hitDetectionInstructions.push(fillInstruction); + this.hitDetectionInstructions.push([ol.render.canvas.Instruction.FILL]); if (state.fillStyle !== undefined) { - this.instructions.push(fillInstruction); + state.pendingFill++; } if (state.strokeStyle !== undefined) { goog.asserts.assert(state.lineWidth !== undefined, 'state.lineWidth should be defined'); - var strokeInstruction = [ol.render.canvas.Instruction.STROKE]; - this.instructions.push(strokeInstruction); - this.hitDetectionInstructions.push(strokeInstruction); + state.pendingStroke++; + this.hitDetectionInstructions.push([ol.render.canvas.Instruction.STROKE]); } return offset; }; @@ -1298,19 +1303,20 @@ ol.render.canvas.PolygonReplay.prototype.drawCircle = function(circleGeometry, f flatCoordinates, 0, flatCoordinates.length, stride, 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.pendingFill && !state.pendingStroke) { + this.instructions.push(beginPathInstruction); + } + this.instructions.push(circleInstruction); + this.hitDetectionInstructions.push(circleInstruction, beginPathInstruction); + this.hitDetectionInstructions.push([ol.render.canvas.Instruction.FILL]); if (state.fillStyle !== undefined) { - this.instructions.push(fillInstruction); + state.pendingFill++; } if (state.strokeStyle !== undefined) { goog.asserts.assert(state.lineWidth !== undefined, 'state.lineWidth should be defined'); - var strokeInstruction = [ol.render.canvas.Instruction.STROKE]; - this.instructions.push(strokeInstruction); - this.hitDetectionInstructions.push(strokeInstruction); + state.pendingStroke++; + this.hitDetectionInstructions.push([ol.render.canvas.Instruction.STROKE]); } this.endGeometry(circleGeometry, feature); }; @@ -1391,13 +1397,28 @@ ol.render.canvas.PolygonReplay.prototype.drawMultiPolygon = function(multiPolygo }; +/** + * @private + */ +ol.render.canvas.PolygonReplay.prototype.fillStroke_ = function() { + var state = this.state_; + if (state.pendingFill) { + this.instructions.push([ol.render.canvas.Instruction.FILL]); + state.pendingFill = 0; + } + if (state.pendingStroke) { + this.instructions.push([ol.render.canvas.Instruction.STROKE]); + state.pendingStroke = 0; + } +}; + + /** * @inheritDoc */ ol.render.canvas.PolygonReplay.prototype.finish = function() { goog.asserts.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 @@ -1410,6 +1431,8 @@ ol.render.canvas.PolygonReplay.prototype.finish = function() { coordinates[i] = ol.geom.flat.simplify.snap(coordinates[i], tolerance); } } + this.fillStroke_(); + this.state_ = null; }; @@ -1492,6 +1515,7 @@ ol.render.canvas.PolygonReplay.prototype.setFillStrokeStyles_ = function() { var lineWidth = state.lineWidth; var miterLimit = state.miterLimit; if (fillStyle !== undefined && state.currentFillStyle != fillStyle) { + this.fillStroke_(); this.instructions.push( [ol.render.canvas.Instruction.SET_FILL_STYLE, fillStyle]); state.currentFillStyle = state.fillStyle; @@ -1509,6 +1533,7 @@ ol.render.canvas.PolygonReplay.prototype.setFillStrokeStyles_ = function() { state.currentLineJoin != lineJoin || state.currentLineWidth != lineWidth || state.currentMiterLimit != miterLimit) { + this.fillStroke_(); this.instructions.push( [ol.render.canvas.Instruction.SET_STROKE_STYLE, strokeStyle, lineWidth, lineCap, lineJoin, miterLimit, lineDash]); From ee53fd772d6ffeb04c28fc2959a45e4f85cbbedc Mon Sep 17 00:00:00 2001 From: Andreas Hocevar Date: Thu, 31 Mar 2016 14:47:07 +0200 Subject: [PATCH 2/2] Remove unnecessary duplicated polygon close points --- src/ol/render/canvas/canvasreplay.js | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/src/ol/render/canvas/canvasreplay.js b/src/ol/render/canvas/canvasreplay.js index cacf01d346..4cb107c3ae 100644 --- a/src/ol/render/canvas/canvasreplay.js +++ b/src/ol/render/canvas/canvasreplay.js @@ -153,11 +153,10 @@ goog.inherits(ol.render.canvas.Replay, ol.render.VectorContext); * @param {number} offset Offset. * @param {number} end End. * @param {number} stride Stride. - * @param {boolean} close Close. * @protected * @return {number} My end. */ -ol.render.canvas.Replay.prototype.appendFlatCoordinates = function(flatCoordinates, offset, end, stride, close) { +ol.render.canvas.Replay.prototype.appendFlatCoordinates = function(flatCoordinates, offset, end, stride) { var myEnd = this.coordinates.length; var extent = this.getBufferedMaxExtent(); @@ -196,10 +195,6 @@ ol.render.canvas.Replay.prototype.appendFlatCoordinates = function(flatCoordinat this.coordinates[myEnd++] = lastCoord[1]; } - if (close) { - this.coordinates[myEnd++] = flatCoordinates[offset]; - this.coordinates[myEnd++] = flatCoordinates[offset + 1]; - } return myEnd; }; @@ -771,8 +766,7 @@ goog.inherits(ol.render.canvas.ImageReplay, ol.render.canvas.Replay); * @return {number} My end. */ ol.render.canvas.ImageReplay.prototype.drawCoordinates_ = function(flatCoordinates, offset, end, stride) { - return this.appendFlatCoordinates( - flatCoordinates, offset, end, stride, false); + return this.appendFlatCoordinates(flatCoordinates, offset, end, stride); }; @@ -993,8 +987,7 @@ goog.inherits(ol.render.canvas.LineStringReplay, ol.render.canvas.Replay); */ ol.render.canvas.LineStringReplay.prototype.drawFlatCoordinates_ = function(flatCoordinates, offset, end, stride) { var myBegin = this.coordinates.length; - var myEnd = this.appendFlatCoordinates( - flatCoordinates, offset, end, stride, false); + var myEnd = this.appendFlatCoordinates(flatCoordinates, offset, end, stride); var moveToLineToInstruction = [ol.render.canvas.Instruction.MOVE_TO_LINE_TO, myBegin, myEnd]; this.instructions.push(moveToLineToInstruction); @@ -1245,8 +1238,7 @@ ol.render.canvas.PolygonReplay.prototype.drawFlatCoordinatess_ = function(flatCo for (i = 0, ii = ends.length; i < ii; ++i) { var end = ends[i]; var myBegin = this.coordinates.length; - var myEnd = this.appendFlatCoordinates( - flatCoordinates, offset, end, stride, true); + var myEnd = this.appendFlatCoordinates(flatCoordinates, offset, end, stride); var moveToLineToInstruction = [ol.render.canvas.Instruction.MOVE_TO_LINE_TO, myBegin, myEnd]; var closePathInstruction = [ol.render.canvas.Instruction.CLOSE_PATH]; @@ -1300,7 +1292,7 @@ ol.render.canvas.PolygonReplay.prototype.drawCircle = function(circleGeometry, f var stride = circleGeometry.getStride(); var myBegin = this.coordinates.length; this.appendFlatCoordinates( - flatCoordinates, 0, flatCoordinates.length, stride, false); + flatCoordinates, 0, flatCoordinates.length, stride); var beginPathInstruction = [ol.render.canvas.Instruction.BEGIN_PATH]; var circleInstruction = [ol.render.canvas.Instruction.CIRCLE, myBegin]; if (!state.pendingFill && !state.pendingStroke) { @@ -1648,8 +1640,7 @@ ol.render.canvas.TextReplay.prototype.drawText = function(flatCoordinates, offse this.setReplayTextState_(this.textState_); this.beginGeometry(geometry, feature); var myBegin = this.coordinates.length; - var myEnd = - this.appendFlatCoordinates(flatCoordinates, offset, end, stride, false); + var myEnd = this.appendFlatCoordinates(flatCoordinates, offset, end, stride); var fill = !!this.textFillState_; var stroke = !!this.textStrokeState_; var drawTextInstruction = [