From 5627a467cd274cfa2bb16c70d6ec1d161d7cfaf0 Mon Sep 17 00:00:00 2001 From: Frederic Junod Date: Fri, 21 Oct 2016 14:20:31 +0200 Subject: [PATCH 01/17] Remove unused ol.extent.normalize function --- src/ol/extent.js | 13 ------------- test/spec/ol/extent.test.js | 27 --------------------------- 2 files changed, 40 deletions(-) diff --git a/src/ol/extent.js b/src/ol/extent.js index c352b62b6f..304d9fc4d2 100644 --- a/src/ol/extent.js +++ b/src/ol/extent.js @@ -730,19 +730,6 @@ ol.extent.isInfinite = function(extent) { }; -/** - * @param {ol.Extent} extent Extent. - * @param {ol.Coordinate} coordinate Coordinate. - * @return {ol.Coordinate} Coordinate. - */ -ol.extent.normalize = function(extent, coordinate) { - return [ - (coordinate[0] - extent[0]) / (extent[2] - extent[0]), - (coordinate[1] - extent[1]) / (extent[3] - extent[1]) - ]; -}; - - /** * @param {ol.Extent} extent Extent. * @param {ol.Extent=} opt_extent Extent. diff --git a/test/spec/ol/extent.test.js b/test/spec/ol/extent.test.js index b8406104d8..469694cf7f 100644 --- a/test/spec/ol/extent.test.js +++ b/test/spec/ol/extent.test.js @@ -642,33 +642,6 @@ describe('ol.extent', function() { }); }); - describe('normalize', function() { - it('returns the expected coordinate', function() { - var extent = [0, 1, 2, 3]; - var coordinate; - - coordinate = ol.extent.normalize(extent, [1, 2]); - expect(coordinate[0]).to.eql(0.5); - expect(coordinate[1]).to.eql(0.5); - - coordinate = ol.extent.normalize(extent, [0, 3]); - expect(coordinate[0]).to.eql(0); - expect(coordinate[1]).to.eql(1); - - coordinate = ol.extent.normalize(extent, [2, 1]); - expect(coordinate[0]).to.eql(1); - expect(coordinate[1]).to.eql(0); - - coordinate = ol.extent.normalize(extent, [0, 0]); - expect(coordinate[0]).to.eql(0); - expect(coordinate[1]).to.eql(-0.5); - - coordinate = ol.extent.normalize(extent, [-1, 1]); - expect(coordinate[0]).to.eql(-0.5); - expect(coordinate[1]).to.eql(0); - }); - }); - describe('scaleFromCenter', function() { it('scales the extent from its center', function() { var extent = [1, 1, 3, 3]; From 2a1a9ec337be750b4fadf3f844c3882de4645e7c Mon Sep 17 00:00:00 2001 From: Frederic Junod Date: Fri, 21 Oct 2016 14:22:37 +0200 Subject: [PATCH 02/17] Remove unused ol.extent.isInfinite function --- src/ol/extent.js | 10 ---------- test/spec/ol/extent.test.js | 23 ----------------------- 2 files changed, 33 deletions(-) diff --git a/src/ol/extent.js b/src/ol/extent.js index 304d9fc4d2..5d98818581 100644 --- a/src/ol/extent.js +++ b/src/ol/extent.js @@ -720,16 +720,6 @@ ol.extent.isEmpty = function(extent) { }; -/** - * @param {ol.Extent} extent Extent. - * @return {boolean} Is infinite. - */ -ol.extent.isInfinite = function(extent) { - return extent[0] == -Infinity || extent[1] == -Infinity || - extent[2] == Infinity || extent[3] == Infinity; -}; - - /** * @param {ol.Extent} extent Extent. * @param {ol.Extent=} opt_extent Extent. diff --git a/test/spec/ol/extent.test.js b/test/spec/ol/extent.test.js index 469694cf7f..63b1976e65 100644 --- a/test/spec/ol/extent.test.js +++ b/test/spec/ol/extent.test.js @@ -602,29 +602,6 @@ describe('ol.extent', function() { }); }); - describe('isInfinite', function() { - it('returns true for infinite extents', function() { - var extents = [ - [-Infinity, 0, 0, 0], - [0, -Infinity, 0, 0], - [0, 0, +Infinity, 0], - [0, 0, 0, +Infinity] - ]; - expect(ol.extent.isInfinite(extents[0])).to.be(true); - expect(ol.extent.isInfinite(extents[1])).to.be(true); - expect(ol.extent.isInfinite(extents[2])).to.be(true); - expect(ol.extent.isInfinite(extents[3])).to.be(true); - }); - it('returns false for other extents', function() { - var extents = [ - ol.extent.createEmpty(), - [1, 2, 3, 4] - ]; - expect(ol.extent.isInfinite(extents[0])).to.be(false); - expect(ol.extent.isInfinite(extents[1])).to.be(false); - }); - }); - describe('touches', function() { it('returns the expected value', function() { From 0f8d26d82915335ed081137ec3013b69a13bbfbc Mon Sep 17 00:00:00 2001 From: Frederic Junod Date: Fri, 21 Oct 2016 14:23:31 +0200 Subject: [PATCH 03/17] Remove unused ol.extent.touches function --- src/ol/extent.js | 13 ------------- test/spec/ol/extent.test.js | 17 ----------------- 2 files changed, 30 deletions(-) diff --git a/src/ol/extent.js b/src/ol/extent.js index 5d98818581..ce025e29c8 100644 --- a/src/ol/extent.js +++ b/src/ol/extent.js @@ -808,19 +808,6 @@ ol.extent.intersectsSegment = function(extent, start, end) { }; -/** - * @param {ol.Extent} extent1 Extent 1. - * @param {ol.Extent} extent2 Extent 2. - * @return {boolean} Touches. - */ -ol.extent.touches = function(extent1, extent2) { - var intersects = ol.extent.intersects(extent1, extent2); - return intersects && - (extent1[0] == extent2[2] || extent1[2] == extent2[0] || - extent1[1] == extent2[3] || extent1[3] == extent2[1]); -}; - - /** * Apply a transform function to the extent. * @param {ol.Extent} extent Extent. diff --git a/test/spec/ol/extent.test.js b/test/spec/ol/extent.test.js index 63b1976e65..c158c660c3 100644 --- a/test/spec/ol/extent.test.js +++ b/test/spec/ol/extent.test.js @@ -602,23 +602,6 @@ describe('ol.extent', function() { }); }); - describe('touches', function() { - - it('returns the expected value', function() { - var touches = ol.extent.touches; - var extent = [50, 50, 100, 100]; - expect(touches(extent, [20, 20, 80, 80])).to.be(false); - expect(touches(extent, [20, 20, 50, 80])).to.be(true); - expect(touches(extent, [20, 20, 50, 40])).to.be(false); - expect(touches(extent, [100, 20, 140, 80])).to.be(true); - expect(touches(extent, [100, 20, 140, 40])).to.be(false); - expect(touches(extent, [20, 20, 80, 50])).to.be(true); - expect(touches(extent, [20, 20, 40, 50])).to.be(false); - expect(touches(extent, [20, 100, 80, 140])).to.be(true); - expect(touches(extent, [20, 100, 40, 140])).to.be(false); - }); - }); - describe('scaleFromCenter', function() { it('scales the extent from its center', function() { var extent = [1, 1, 3, 3]; From 0a2b145fd5c869dee424f6214a878700c66fcff6 Mon Sep 17 00:00:00 2001 From: Frederic Junod Date: Fri, 21 Oct 2016 14:25:46 +0200 Subject: [PATCH 04/17] Remove unused ol.extent.empty function --- src/ol/extent.js | 12 ------------ test/spec/ol/extent.test.js | 18 ------------------ 2 files changed, 30 deletions(-) diff --git a/src/ol/extent.js b/src/ol/extent.js index ce025e29c8..2f118d5001 100644 --- a/src/ol/extent.js +++ b/src/ol/extent.js @@ -307,18 +307,6 @@ ol.extent.createOrUpdateFromRings = function(rings, opt_extent) { }; -/** - * Empty an extent in place. - * @param {ol.Extent} extent Extent. - * @return {ol.Extent} Extent. - */ -ol.extent.empty = function(extent) { - extent[0] = extent[1] = Infinity; - extent[2] = extent[3] = -Infinity; - return extent; -}; - - /** * Determine if two extents are equivalent. * @param {ol.Extent} extent1 Extent 1. diff --git a/test/spec/ol/extent.test.js b/test/spec/ol/extent.test.js index c158c660c3..e2483b7af5 100644 --- a/test/spec/ol/extent.test.js +++ b/test/spec/ol/extent.test.js @@ -167,24 +167,6 @@ describe('ol.extent', function() { }); - describe('empty', function() { - - it('returns the empty extent', function() { - var extent = [1, 2, 3, 4]; - var expected = [Infinity, Infinity, -Infinity, -Infinity]; - var got = ol.extent.empty(extent); - expect(got).to.eql(expected); - }); - - it('empties a passed extent in place', function() { - var extent = [1, 2, 3, 4]; - var expected = [Infinity, Infinity, -Infinity, -Infinity]; - ol.extent.empty(extent); - expect(extent).to.eql(expected); - }); - - }); - describe('forEachCorner', function() { var callbackFalse; From 42d1c51cbb893ef8db6b9f2cbe57e7e0052b30a8 Mon Sep 17 00:00:00 2001 From: Marc Jansen Date: Sat, 22 Oct 2016 11:17:04 +0200 Subject: [PATCH 05/17] Combine standard coverage and rendering coverage --- tasks/test-coverage.js | 88 ++++++++++++++++++++++++++++++++++-------- test_rendering/test.js | 15 +++++++ 2 files changed, 87 insertions(+), 16 deletions(-) diff --git a/tasks/test-coverage.js b/tasks/test-coverage.js index a5b6732ef1..901ae583e4 100644 --- a/tasks/test-coverage.js +++ b/tasks/test-coverage.js @@ -20,6 +20,8 @@ var backupDir = path.join(__dirname, '../src-backup'); var instrumentedDir = path.join(__dirname, '../src-instrumented'); var coverageDir = path.join(__dirname, '../coverage'); +fs.mkdirSync(coverageDir); + // The main players in the coverage generation via istanbul var instrumenter = new istanbul.Instrumenter(); var reporter = new istanbul.Reporter(false, coverageDir); @@ -76,16 +78,23 @@ var revertBackupAndInstrumentationDir = function() { fs.removeSync(instrumentedDir); }; - /** * Callback for when runTestsuite() has finished. */ var collectAndWriteCoverageData = function() { - log('• collect data from coverage.json'); + log('• collect data from coverage *.json files'); - var coverageFile = path.join(__dirname,'../coverage/coverage.json'); - var coverageJson = JSON.parse(fs.readFileSync(coverageFile, 'utf8')); - collector.add(coverageJson); + var coverageFiles = [ + path.join(__dirname, '..', 'coverage', 'coverage.json'), + path.join(__dirname, '..', 'coverage', 'coverage-rendering.json') + ]; + coverageFiles.forEach(function(coverageFile) { + if (fs.existsSync(coverageFile)) { + log(' • collect data from ' + path.basename(coverageFile)); + var coverageJson = JSON.parse(fs.readFileSync(coverageFile, 'utf8')); + collector.add(coverageJson); + } + }); reporter.addAll(['lcovonly','html']); @@ -97,6 +106,44 @@ var collectAndWriteCoverageData = function() { }); }; +/** + * Runs the rendering test by spawning a call to `make test-rendering`. The + * `make`-call sets up certain things so that the rendering tests can actually + * run, which is why we call it this way. + * + * @param {Function} callback The callback to invoke once `make` has exited. + * Will receive the exit code. + */ +var runRenderingTestsuite = function(callback) { + var spawn = require('child_process').spawn; + var child = spawn('make', ['test-rendering'], {stdio: 'inherit'}); + child.on('exit', function(code) { + callback(code); + }); +}; + +/** + * Derive output file name from input file name, by replacing the *last* + * occurence of `/src/` by `/src-instrumented/` + * + * @param {String} file The input filename. + * @return {String} file The output filename. + */ +var outputFilenameByFilename = function(file) { + var search = '/src/'; + var replace = '/src-instrumented/'; + var re = new RegExp(search, 'g'); + var m, match; + while ((m = re.exec(file)) !== null) { + match = m; + } + var idx = match.index; + var outfile = file.substr(0, idx) + replace + + file.substr(idx + search.length); + + return outfile; +}; + /** * Will instrument all JavaScript files that are passed as second parameter. * This is the callback to the glob call. @@ -113,15 +160,7 @@ var foundAllJavaScriptSourceFiles = function(err, files) { files.forEach(function(file) { cnt++; var content = fs.readFileSync(file, 'utf-8'); - // derive output file name from input file name, by replacing the *last* - // occurence of /src/ by /src-instrumented/ - var re = new RegExp('/src/', 'g'); - var m, match; - while ((m = re.exec(file)) !== null) { - match = m; - } - var outfile = file.substr(0, match.index) + '/src-instrumented/' + - file.substr(match.index + '/src/'.length); + var outfile = outputFilenameByFilename(file); var instrumented = instrumenter.instrumentSync(content, file); fs.writeFileSync(outfile, instrumented); if (cnt % 10 === 0) { @@ -133,8 +172,25 @@ var foundAllJavaScriptSourceFiles = function(err, files) { fs.copySync(instrumentedDir, dir, copyOpts); - log('• run test suite on instrumented code'); - runTestsuite({coverage: true, reporter: 'dot'}, collectAndWriteCoverageData); + log('• run test suites on instrumented code'); + + log(' • run rendering test suite'); + runRenderingTestsuite(function(codeRendering) { + if (codeRendering === 0) { + log(' • run standard test suite'); + runTestsuite({coverage: true, reporter: 'dot'}, function(code) { + if (code === 0) { + collectAndWriteCoverageData(); + } else { + process.stderr.write('Trouble running the standard testsuite\n'); + process.exit(1); + } + }); + } else { + process.stderr.write('Trouble running the rendering testsuite\n'); + process.exit(1); + } + }); }; /** diff --git a/test_rendering/test.js b/test_rendering/test.js index 239798095c..6ebeb0cfff 100644 --- a/test_rendering/test.js +++ b/test_rendering/test.js @@ -19,8 +19,23 @@ page.open(url).then(function(status) { } console.error(failedTests.length + ' test(s) failed.'); } else { + // check for cov here + var coverage = page.evaluate(function() { + return window.__coverage__; + }); + + if (coverage) { + console.log('Writing coverage to coverage/coverage-rendering.json'); + var fs = require('fs'); + fs.write( + fs.workingDirectory + '/coverage/coverage-rendering.json', + JSON.stringify(coverage), + 'w' + ); + } console.log('All tests passed.'); } + page.close(); phantom.exit(failedTests.length === 0 ? 0 : 1); }; From 9659d8598cb29d8bc114ac165d826cf0fa362309 Mon Sep 17 00:00:00 2001 From: greenkeeperio-bot Date: Sat, 22 Oct 2016 12:05:00 -0700 Subject: [PATCH 06/17] chore(package): update browserify to version 13.1.1 https://greenkeeper.io/ --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8cddf8b9b7..1ef745e25c 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,7 @@ ], "dependencies": { "async": "2.1.2", - "browserify": "13.1.0", + "browserify": "13.1.1", "closure-util": "1.15.1", "derequire": "2.0.3", "fs-extra": "0.30.0", From 2132a02f765e895c7323458df2f8129560ecca6d Mon Sep 17 00:00:00 2001 From: Bart van den Eijnden Date: Mon, 24 Oct 2016 09:31:38 +0200 Subject: [PATCH 07/17] Revert "Point to the English workshop" This reverts commit ede6fc6e013a3ebf74ad31034dff9161b945be79. --- doc/index.hbs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/index.hbs b/doc/index.hbs index 3efa8e4921..11c17feb93 100644 --- a/doc/index.hbs +++ b/doc/index.hbs @@ -9,7 +9,7 @@ If you're eager to get your first OpenLayers 3 map on a page, dive into the [qui For a more in-depth overview of OpenLayers 3 core concepts, check out the [tutorials](tutorials/). -Make sure to also check out the [OpenLayers 3 workshop](/workshop/en/). +Make sure to also check out the [OpenLayers 3 workshop](/workshop/). Find additional reference material in the [API docs](../apidoc). From 2fe4d63893dbb1fcd05f9f4495d934d433bef490 Mon Sep 17 00:00:00 2001 From: Bart van den Eijnden Date: Mon, 24 Oct 2016 10:31:15 +0200 Subject: [PATCH 08/17] Make sure updateParams reloads in TileArcGISRest --- src/ol/source/tilearcgisrest.js | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/ol/source/tilearcgisrest.js b/src/ol/source/tilearcgisrest.js index 06ad9da371..1004d00264 100644 --- a/src/ol/source/tilearcgisrest.js +++ b/src/ol/source/tilearcgisrest.js @@ -55,10 +55,25 @@ ol.source.TileArcGISRest = function(opt_options) { */ this.tmpExtent_ = ol.extent.createEmpty(); + this.setKey(this.getKeyForParams_()); }; ol.inherits(ol.source.TileArcGISRest, ol.source.TileImage); +/** + * @private + * @return {string} The key for the current params. + */ +ol.source.TileArcGISRest.prototype.getKeyForParams_ = function() { + var i = 0; + var res = []; + for (var key in this.params_) { + res[i++] = key + '-' + this.params_[key]; + } + return res.join('/'); +}; + + /** * Get the user-provided params, i.e. those passed to the constructor through * the "params" option, and possibly updated using the updateParams method. @@ -168,5 +183,5 @@ ol.source.TileArcGISRest.prototype.fixedTileUrlFunction = function(tileCoord, pi */ ol.source.TileArcGISRest.prototype.updateParams = function(params) { ol.obj.assign(this.params_, params); - this.changed(); + this.setKey(this.getKeyForParams_()); }; From f973eaa24d69d952ed5d8846079e2eaaf109b047 Mon Sep 17 00:00:00 2001 From: Marc Jansen Date: Mon, 24 Oct 2016 10:39:48 +0200 Subject: [PATCH 09/17] Test that ol.obj.assign throws on undefined/null --- test/spec/ol/objectutil.test.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/test/spec/ol/objectutil.test.js b/test/spec/ol/objectutil.test.js index 7b5204021b..0c29f620fd 100644 --- a/test/spec/ol/objectutil.test.js +++ b/test/spec/ol/objectutil.test.js @@ -31,6 +31,18 @@ describe('ol.obj.assign()', function() { }); + it('throws a TypeError with `undefined` as target', function() { + expect(ol.obj.assign).withArgs(undefined).to.throwException(function(e) { + expect(e).to.be.a(TypeError); + }); + }); + + it('throws a TypeError with `null` as target', function() { + expect(ol.obj.assign).withArgs(null).to.throwException(function(e) { + expect(e).to.be.a(TypeError); + }); + }); + }); describe('ol.obj.clear()', function() { From 70338b928eaf0cd9f686bd64899fe51c604a5e03 Mon Sep 17 00:00:00 2001 From: Andreas Hocevar Date: Tue, 25 Oct 2016 11:13:43 +0200 Subject: [PATCH 10/17] Revert "Merge pull request #5890 from ahocevar/no-white-lines" This partially reverts commit 5f18246355a11b40edf751a598f48c7586c3673d, reversing most of the changes made to 004afa6b9abe06b0a1728f16e5e62c5731e569b2. --- src/ol/renderer/canvas/tilelayer.js | 34 +++++++---------------------- 1 file changed, 8 insertions(+), 26 deletions(-) diff --git a/src/ol/renderer/canvas/tilelayer.js b/src/ol/renderer/canvas/tilelayer.js index aa4d5e032e..a83f80ab38 100644 --- a/src/ol/renderer/canvas/tilelayer.js +++ b/src/ol/renderer/canvas/tilelayer.js @@ -12,7 +12,6 @@ goog.require('ol.extent'); goog.require('ol.render.canvas'); goog.require('ol.render.Event'); goog.require('ol.renderer.canvas.Layer'); -goog.require('ol.size'); /** @@ -216,7 +215,7 @@ ol.renderer.canvas.TileLayer.prototype.forEachLayerAtPixel = function( */ ol.renderer.canvas.TileLayer.prototype.renderTileImages = function(context, frameState, layerState) { var tilesToDraw = this.renderedTiles; - if (tilesToDraw.length == 0) { + if (tilesToDraw.length === 0) { return; } @@ -264,17 +263,6 @@ ol.renderer.canvas.TileLayer.prototype.renderTileImages = function(context, fram var alpha = renderContext.globalAlpha; renderContext.globalAlpha = layerState.opacity; - // Origin of the lowest resolution tile that contains the map center. We will - // try to use the same origin for all resolutions for pixel-perfect tile - // alignment across resolutions. - var lowResTileCoord = tilesToDraw[0].getTileCoord(); - var minZOrigin = ol.extent.getBottomLeft(tileGrid.getTileCoordExtent( - tileGrid.getTileCoordForCoordAndZ(center, - lowResTileCoord[0], this.tmpTileCoord_), this.tmpExtent)); - var maxZ = tilesToDraw[tilesToDraw.length - 1].getTileCoord()[0]; - var maxZResolution = tileGrid.getResolution(maxZ); - var maxZTileSize = ol.size.toSize(tileGrid.getTileSize(maxZ)); - var pixelExtents; var opaque = source.getOpaque(projection) && layerState.opacity == 1; if (!opaque) { @@ -317,23 +305,17 @@ ol.renderer.canvas.TileLayer.prototype.renderTileImages = function(context, fram for (var i = 0, ii = tilesToDraw.length; i < ii; ++i) { var tile = tilesToDraw[i]; var tileCoord = tile.getTileCoord(); + var tileExtent = tileGrid.getTileCoordExtent(tileCoord, this.tmpExtent); var currentZ = tileCoord[0]; - var tileSize = ol.size.toSize(tileGrid.getTileSize(currentZ)); // Calculate all insert points by tile widths from a common origin to avoid // gaps caused by rounding - var originTileCoord = tileGrid.getTileCoordForCoordAndZ(minZOrigin, currentZ, this.tmpTileCoord_); - var origin = ol.extent.getBottomLeft(tileGrid.getTileCoordExtent(originTileCoord, this.tmpExtent)); - // Calculate tile width and height by a tile size factor from the highest - // resolution tile size to avoid gaps when combining tiles from different - // resolutions - var resolutionFactor = tileGrid.getResolution(currentZ) / maxZResolution; - var tileSizeFactorW = tileSize[0] / maxZTileSize[0] * resolutionFactor; - var tileSizeFactorH = tileSize[1] / maxZTileSize[1] * resolutionFactor; - var w = Math.round(maxZTileSize[0] / resolution * maxZResolution * pixelRatio * drawScale) * tileSizeFactorW; - var h = Math.round(maxZTileSize[1] / resolution * maxZResolution * pixelRatio * drawScale) * tileSizeFactorH; - var left = (tileCoord[1] - originTileCoord[1]) * w + + var origin = ol.extent.getBottomLeft(tileGrid.getTileCoordExtent( + tileGrid.getTileCoordForCoordAndZ(center, currentZ, this.tmpTileCoord_))); + var w = Math.round(ol.extent.getWidth(tileExtent) * pixelScale); + var h = Math.round(ol.extent.getHeight(tileExtent) * pixelScale); + var left = Math.round((tileExtent[0] - origin[0]) * pixelScale / w) * w + offsetX + Math.round((origin[0] - center[0]) * pixelScale); - var top = (originTileCoord[2] - tileCoord[2] - 1) * h + + var top = Math.round((origin[1] - tileExtent[3]) * pixelScale / h) * h + offsetY + Math.round((center[1] - origin[1]) * pixelScale); if (!opaque) { var pixelExtent = [left, top, left + w, top + h]; From 1bd11c19581d59f1b8184507d62ef96720b9d4dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Harrtell?= Date: Tue, 25 Oct 2016 21:57:38 +0200 Subject: [PATCH 11/17] Close polygon sketch at all times --- src/ol/interaction/draw.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/ol/interaction/draw.js b/src/ol/interaction/draw.js index 970e157e91..554ec6573a 100644 --- a/src/ol/interaction/draw.js +++ b/src/ol/interaction/draw.js @@ -152,7 +152,11 @@ ol.interaction.Draw = function(options) { geometryFunction = function(coordinates, opt_geometry) { var geometry = opt_geometry; if (geometry) { - geometry.setCoordinates(coordinates); + if (mode === ol.interaction.Draw.Mode.POLYGON) { + geometry.setCoordinates([coordinates[0].concat([coordinates[0][0]])]); + } else { + geometry.setCoordinates(coordinates); + } } else { geometry = new Constructor(coordinates); } @@ -617,12 +621,10 @@ ol.interaction.Draw.prototype.finishDrawing = function() { coordinates.pop(); this.geometryFunction_(coordinates, geometry); } else if (this.mode_ === ol.interaction.Draw.Mode.POLYGON) { - // When we finish drawing a polygon on the last point, - // the last coordinate is duplicated as for LineString - // we force the replacement by the first point + // remove the redundant last point in ring coordinates[0].pop(); - coordinates[0].push(coordinates[0][0]); this.geometryFunction_(coordinates, geometry); + coordinates = geometry.getCoordinates(); } // cast multi-part geometries From 9d5453a92729e8bf373f75529466f23dfeee418d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Harrtell?= Date: Thu, 27 Oct 2016 18:56:11 +0200 Subject: [PATCH 12/17] Test to validate sketch polygon --- test/spec/ol/interaction/draw.test.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/test/spec/ol/interaction/draw.test.js b/test/spec/ol/interaction/draw.test.js index 603a59dde7..e51b06f548 100644 --- a/test/spec/ol/interaction/draw.test.js +++ b/test/spec/ol/interaction/draw.test.js @@ -494,21 +494,30 @@ describe('ol.interaction.Draw', function() { map.addInteraction(draw); }); + function isClosed(polygon) { + var first = polygon.getFirstCoordinate(); + var last = polygon.getLastCoordinate(); + expect(first).to.eql(last); + } + it('draws polygon with clicks, finishing on first point', function() { // first point simulateEvent('pointermove', 10, 20); simulateEvent('pointerdown', 10, 20); simulateEvent('pointerup', 10, 20); + isClosed(draw.sketchFeature_.getGeometry()); // second point simulateEvent('pointermove', 30, 20); simulateEvent('pointerdown', 30, 20); simulateEvent('pointerup', 30, 20); + isClosed(draw.sketchFeature_.getGeometry()); // third point simulateEvent('pointermove', 40, 10); simulateEvent('pointerdown', 40, 10); simulateEvent('pointerup', 40, 10); + isClosed(draw.sketchFeature_.getGeometry()); // finish on first point simulateEvent('pointermove', 10, 20); From a2a2a53e08b906182127666590bafc94677535a0 Mon Sep 17 00:00:00 2001 From: Andreas Hocevar Date: Thu, 27 Oct 2016 21:27:17 +0200 Subject: [PATCH 13/17] Use geometry extent's top left corner as pattern/gradient origin --- changelog/upgrade-notes.md | 5 ++++ examples/canvas-gradient-pattern.js | 11 +++---- src/ol/render/canvas/polygonreplay.js | 19 +++++++----- src/ol/render/canvas/replay.js | 27 +++++++++--------- src/ol/typedefs.js | 4 ++- .../polygon-pattern-gradient-canvas.png | Bin 1325 -> 1304 bytes 6 files changed, 39 insertions(+), 27 deletions(-) diff --git a/changelog/upgrade-notes.md b/changelog/upgrade-notes.md index b1ce5f6d12..4cd45e5919 100644 --- a/changelog/upgrade-notes.md +++ b/changelog/upgrade-notes.md @@ -1,5 +1,10 @@ ## Upgrade notes +#### `ol.style.Fill` with `CanvasGradient` or `CanvasPattern` + +The origin for gradients and patterns has changed from `[0, 0]` to the top-left +corner of the extent of the geometry being filled. + ### v3.19.0 #### `ol.style.Fill` with `CanvasGradient` or `CanvasPattern` diff --git a/examples/canvas-gradient-pattern.js b/examples/canvas-gradient-pattern.js index c3dde464b3..58ffb8ad75 100644 --- a/examples/canvas-gradient-pattern.js +++ b/examples/canvas-gradient-pattern.js @@ -1,5 +1,6 @@ goog.require('ol.Map'); goog.require('ol.View'); +goog.require('ol.extent'); goog.require('ol.format.GeoJSON'); goog.require('ol.has'); goog.require('ol.layer.Vector'); @@ -20,11 +21,11 @@ var pixelRatio = ol.has.DEVICE_PIXEL_RATIO; function gradient(feature, resolution) { var extent = feature.getGeometry().getExtent(); // Gradient starts on the left edge of each feature, and ends on the right. - // Coordinate origin is [0, 0], so we just divide by resolution and multiply - // with pixelRatio to match the renderer's pixel coordinate system. - var grad = context.createLinearGradient( - extent[0] / resolution * pixelRatio, 0, - extent[2] / resolution * pixelRatio, 0); + // Coordinate origin is the top-left corner of the extent of the geometry, so + // we just divide the geometry's extent width by resolution and multiply with + // pixelRatio to match the renderer's pixel coordinate system. + var grad = context.createLinearGradient(0, 0, + ol.extent.getWidth(extent) / resolution * pixelRatio, 0); grad.addColorStop(0, 'red'); grad.addColorStop(1 / 6, 'orange'); grad.addColorStop(2 / 6, 'yellow'); diff --git a/src/ol/render/canvas/polygonreplay.js b/src/ol/render/canvas/polygonreplay.js index d12243f3d7..b845e5aa88 100644 --- a/src/ol/render/canvas/polygonreplay.js +++ b/src/ol/render/canvas/polygonreplay.js @@ -132,7 +132,7 @@ ol.render.canvas.PolygonReplay.prototype.drawCircle = function(circleGeometry, f ol.DEBUG && console.assert(state.lineWidth !== undefined, 'state.lineWidth should be defined'); } - this.setFillStrokeStyles_(); + this.setFillStrokeStyles_(circleGeometry); this.beginGeometry(circleGeometry, feature); // always fill the circle for hit detection this.hitDetectionInstructions.push( @@ -182,7 +182,7 @@ ol.render.canvas.PolygonReplay.prototype.drawPolygon = function(polygonGeometry, ol.DEBUG && console.assert(state.lineWidth !== undefined, 'state.lineWidth should be defined'); } - this.setFillStrokeStyles_(); + this.setFillStrokeStyles_(polygonGeometry); this.beginGeometry(polygonGeometry, feature); // always fill the polygon for hit detection this.hitDetectionInstructions.push( @@ -217,7 +217,7 @@ ol.render.canvas.PolygonReplay.prototype.drawMultiPolygon = function(multiPolygo ol.DEBUG && console.assert(state.lineWidth !== undefined, 'state.lineWidth should be defined'); } - this.setFillStrokeStyles_(); + this.setFillStrokeStyles_(multiPolygonGeometry); this.beginGeometry(multiPolygonGeometry, feature); // always fill the multi-polygon for hit detection this.hitDetectionInstructions.push( @@ -332,8 +332,9 @@ ol.render.canvas.PolygonReplay.prototype.setFillStrokeStyle = function(fillStyle /** * @private + * @param {ol.geom.Geometry|ol.render.Feature} geometry Geometry. */ -ol.render.canvas.PolygonReplay.prototype.setFillStrokeStyles_ = function() { +ol.render.canvas.PolygonReplay.prototype.setFillStrokeStyles_ = function(geometry) { var state = this.state_; var fillStyle = state.fillStyle; var strokeStyle = state.strokeStyle; @@ -342,9 +343,13 @@ ol.render.canvas.PolygonReplay.prototype.setFillStrokeStyles_ = function() { var lineJoin = state.lineJoin; var lineWidth = state.lineWidth; var miterLimit = state.miterLimit; - if (fillStyle !== undefined && state.currentFillStyle != fillStyle) { - this.instructions.push( - [ol.render.canvas.Instruction.SET_FILL_STYLE, fillStyle, typeof fillStyle != 'string']); + if (typeof fillStyle !== 'string' || fillStyle !== undefined && 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) { diff --git a/src/ol/render/canvas/replay.js b/src/ol/render/canvas/replay.js index f5993bb782..cb9fce4c17 100644 --- a/src/ol/render/canvas/replay.js +++ b/src/ol/render/canvas/replay.js @@ -60,9 +60,9 @@ ol.render.canvas.Replay = function(tolerance, maxExtent, resolution, overlaps) { /** * @private - * @type {boolean} + * @type {ol.Coordinate} */ - this.alignFill_ = false; + this.fillOrigin_; /** * @private @@ -194,18 +194,17 @@ ol.render.canvas.Replay.prototype.beginGeometry = function(geometry, feature) { /** * @private * @param {CanvasRenderingContext2D} context Context. - * @param {ol.Transform} transform Transform. * @param {number} rotation Rotation. */ -ol.render.canvas.Replay.prototype.fill_ = function(context, transform, rotation) { - if (this.alignFill_) { - context.translate(transform[4], transform[5]); +ol.render.canvas.Replay.prototype.fill_ = function(context, rotation) { + if (this.fillOrigin_) { + var origin = ol.transform.apply(this.renderedTransform_, this.fillOrigin_.slice()); + context.translate(origin[0], origin[1]); context.rotate(rotation); } context.fill(); - if (this.alignFill_) { - context.rotate(-rotation); - context.translate(-transform[4], -transform[5]); + if (this.fillOrigin_) { + context.setTransform.apply(context, this.resetTransform_); } }; @@ -275,7 +274,7 @@ ol.render.canvas.Replay.prototype.replay_ = function( break; case ol.render.canvas.Instruction.BEGIN_PATH: if (pendingFill > batchSize) { - this.fill_(context, transform, viewRotation); + this.fill_(context, viewRotation); pendingFill = 0; } if (pendingStroke > batchSize) { @@ -452,7 +451,7 @@ ol.render.canvas.Replay.prototype.replay_ = function( if (batchSize) { pendingFill++; } else { - this.fill_(context, transform, viewRotation); + this.fill_(context, viewRotation); } ++i; break; @@ -490,10 +489,10 @@ ol.render.canvas.Replay.prototype.replay_ = function( ol.colorlike.isColorLike(instruction[1]), '2nd instruction should be a string, ' + 'CanvasPattern, or CanvasGradient'); - this.alignFill_ = instruction[2]; + this.fillOrigin_ = instruction[2]; if (pendingFill) { - this.fill_(context, transform, viewRotation); + this.fill_(context, viewRotation); pendingFill = 0; } @@ -559,7 +558,7 @@ ol.render.canvas.Replay.prototype.replay_ = function( } } if (pendingFill) { - this.fill_(context, transform, viewRotation); + this.fill_(context, viewRotation); } if (pendingStroke) { context.stroke(); diff --git a/src/ol/typedefs.js b/src/ol/typedefs.js index 74d3f29fef..7901c923f0 100644 --- a/src/ol/typedefs.js +++ b/src/ol/typedefs.js @@ -121,7 +121,9 @@ ol.Color; /** * A type accepted by CanvasRenderingContext2D.fillStyle * or CanvasRenderingContext2D.strokeStyle. - * Represents a color, pattern, or gradient. + * Represents a color, pattern, or gradient. The origin for patterns and + * gradients as fill style is the top-left corner of the extent of the geometry + * being filled. * * @typedef {string|CanvasPattern|CanvasGradient} */ diff --git a/test_rendering/spec/ol/style/expected/polygon-pattern-gradient-canvas.png b/test_rendering/spec/ol/style/expected/polygon-pattern-gradient-canvas.png index bb4302a78f6b9da5d2b4891919fba1e7a1be6a31..4a2fb3412acafaed1be8f9fba9a5a28d3960aba3 100644 GIT binary patch delta 1284 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 Q0RR9107*qoM6N<$f;u{Y@c;k- From 5d5d49ad122d8e3c3a95eef250730dc3aec25f46 Mon Sep 17 00:00:00 2001 From: greenkeeperio-bot Date: Thu, 27 Oct 2016 14:44:29 -0600 Subject: [PATCH 14/17] chore(package): update metalsmith to version 2.2.1 https://greenkeeper.io/ --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1ef745e25c..f40301d3d3 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,7 @@ "handlebars": "4.0.5", "jsdoc": "3.4.2", "marked": "0.3.6", - "metalsmith": "2.2.0", + "metalsmith": "2.2.1", "metalsmith-layouts": "1.6.5", "nomnom": "1.8.1", "pbf": "3.0.2", From e0a9910d4ecd6929db93a5c25ed547b802af4fe3 Mon Sep 17 00:00:00 2001 From: Frederic Junod Date: Fri, 28 Oct 2016 09:07:37 +0200 Subject: [PATCH 15/17] Add new timeout option to ol.interaction.MouseWheelZoom And remove the `ol.MOUSEWHEELZOOM_TIMEOUT_DURATION` define. --- externs/olx.js | 9 ++++++ src/ol/index.js | 6 ---- src/ol/interaction/mousewheelzoom.js | 9 ++++-- .../ol/interaction/mousewheelzoom.test.js | 30 +++++++++++++++++++ 4 files changed, 46 insertions(+), 8 deletions(-) diff --git a/externs/olx.js b/externs/olx.js index 56ebd4fbbd..ee532d33a5 100644 --- a/externs/olx.js +++ b/externs/olx.js @@ -2935,6 +2935,7 @@ olx.interaction.ModifyOptions.prototype.wrapX; /** * @typedef {{duration: (number|undefined), + * timeout: (number|undefined), * useAnchor: (boolean|undefined)}} */ olx.interaction.MouseWheelZoomOptions; @@ -2948,6 +2949,14 @@ olx.interaction.MouseWheelZoomOptions; olx.interaction.MouseWheelZoomOptions.prototype.duration; +/** + * Mouse wheel timeout duration in milliseconds. Default is `80`. + * @type {number|undefined} + * @api + */ +olx.interaction.MouseWheelZoomOptions.prototype.timeout; + + /** * Enable zooming using the mouse's location as the anchor. Default is `true`. * When set to false, zooming in and out will zoom to the center of the screen diff --git a/src/ol/index.js b/src/ol/index.js index 385d51f39e..642a0ff937 100644 --- a/src/ol/index.js +++ b/src/ol/index.js @@ -142,12 +142,6 @@ ol.MAX_ATLAS_SIZE = -1; ol.MOUSEWHEELZOOM_MAXDELTA = 1; -/** - * @define {number} Mouse wheel timeout duration. - */ -ol.MOUSEWHEELZOOM_TIMEOUT_DURATION = 80; - - /** * @define {number} Maximum width and/or height extent ratio that determines * when the overview map should be zoomed out. diff --git a/src/ol/interaction/mousewheelzoom.js b/src/ol/interaction/mousewheelzoom.js index 395d32c33a..19f18dd13a 100644 --- a/src/ol/interaction/mousewheelzoom.js +++ b/src/ol/interaction/mousewheelzoom.js @@ -36,6 +36,12 @@ ol.interaction.MouseWheelZoom = function(opt_options) { */ this.duration_ = options.duration !== undefined ? options.duration : 250; + /** + * @private + * @type {number} + */ + this.timeout_ = options.timeout !== undefined ? options.timeout : 80; + /** * @private * @type {boolean} @@ -109,8 +115,7 @@ ol.interaction.MouseWheelZoom.handleEvent = function(mapBrowserEvent) { this.startTime_ = Date.now(); } - var duration = ol.MOUSEWHEELZOOM_TIMEOUT_DURATION; - var timeLeft = Math.max(duration - (Date.now() - this.startTime_), 0); + var timeLeft = Math.max(this.timeout_ - (Date.now() - this.startTime_), 0); clearTimeout(this.timeoutId_); this.timeoutId_ = setTimeout( diff --git a/test/spec/ol/interaction/mousewheelzoom.test.js b/test/spec/ol/interaction/mousewheelzoom.test.js index 643289e171..c2aebc5e06 100644 --- a/test/spec/ol/interaction/mousewheelzoom.test.js +++ b/test/spec/ol/interaction/mousewheelzoom.test.js @@ -27,6 +27,36 @@ describe('ol.interaction.MouseWheelZoom', function() { disposeMap(map); }); + describe('timeout duration', function() { + var clock; + beforeEach(function() { + clock = sinon.useFakeTimers(); + }); + + afterEach(function() { + clock.restore(); + }); + + it('works with the defaut value', function(done) { + var spy = sinon.spy(ol.interaction.Interaction, 'zoomByDelta'); + var event = new ol.MapBrowserEvent('mousewheel', map, { + type: 'mousewheel', + target: map.getViewport(), + preventDefault: ol.events.Event.prototype.preventDefault + }); + map.handleMapBrowserEvent(event); + clock.tick(50); + // default timeout is 80 ms, not called yet + expect(spy.called).to.be(false); + clock.tick(30); + expect(spy.called).to.be(true); + + ol.interaction.Interaction.zoomByDelta.restore(); + done(); + }); + + }); + describe('handleEvent()', function() { it('[wheel] works on Firefox in DOM_DELTA_PIXEL mode', function(done) { var origHasFirefox = ol.has.FIREFOX; From aa7e54833da0ff2c864a26db628cf1c12d32f6f0 Mon Sep 17 00:00:00 2001 From: Andreas Hocevar Date: Fri, 28 Oct 2016 10:34:27 +0200 Subject: [PATCH 16/17] Do not fill when there is no fillStyle --- src/ol/render/canvas/polygonreplay.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ol/render/canvas/polygonreplay.js b/src/ol/render/canvas/polygonreplay.js index b845e5aa88..fa6dd6ecd2 100644 --- a/src/ol/render/canvas/polygonreplay.js +++ b/src/ol/render/canvas/polygonreplay.js @@ -343,7 +343,7 @@ ol.render.canvas.PolygonReplay.prototype.setFillStrokeStyles_ = function(geometr var lineJoin = state.lineJoin; var lineWidth = state.lineWidth; var miterLimit = state.miterLimit; - if (typeof fillStyle !== 'string' || fillStyle !== undefined && state.currentFillStyle != fillStyle) { + 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(); From 8a69f1f6ea17e5362e3f7d26ba7975367de0b8e5 Mon Sep 17 00:00:00 2001 From: Marc Jansen Date: Fri, 28 Oct 2016 10:51:34 +0200 Subject: [PATCH 17/17] Update the coveralls badge --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 976db69b67..e82c9aec20 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # OpenLayers 3 [![Travis CI Status](https://secure.travis-ci.org/openlayers/ol3.svg)](http://travis-ci.org/#!/openlayers/ol3) -[![Coverage Status](https://coveralls.io/repos/openlayers/ol3/badge.svg?branch=master)](https://coveralls.io/r/openlayers/ol3?branch=master) +[![Coverage Status](https://coveralls.io/repos/github/openlayers/ol3/badge.svg?branch=master)](https://coveralls.io/github/openlayers/ol3?branch=master) [![OSGeo Project](https://img.shields.io/badge/OSGeo-Project-brightgreen.svg)](http://osgeo.org/) [OpenLayers 3](https://openlayers.org/) is a high-performance, feature-packed library for creating interactive maps on the web. It can display map tiles, vector data and markers loaded from any source on any web page. OpenLayers has been developed to further the use of geographic information of all kinds. It is completely free, Open Source JavaScript, released under the 2-clause BSD License (also known as the FreeBSD).