From 971c1137bc420a528cd999e385098123461720d8 Mon Sep 17 00:00:00 2001 From: Andreas Hocevar Date: Tue, 8 Jul 2014 01:00:38 +0200 Subject: [PATCH 01/19] Download and use new proj4js --- build.py | 18 +++--------------- examples/wms-custom-proj.html | 4 ++-- examples/wms-image-custom-proj.html | 4 ++-- test/index.html | 2 +- 4 files changed, 8 insertions(+), 20 deletions(-) diff --git a/build.py b/build.py index cf7ff7a6b7..ff6b9a4ded 100755 --- a/build.py +++ b/build.py @@ -128,9 +128,7 @@ SRC = [path if path.endswith('.js') if path not in SHADER_SRC] -PROJ4JS = 'build/proj4js/lib/proj4js-combined.js' -PROJ4JS_ZIP = 'build/proj4js-1.1.0.zip' -PROJ4JS_ZIP_MD5 = '17caad64cf6ebc6e6fe62f292b134897' +PROJ4JS = 'build/proj4js/dist/proj4.js' def report_sizes(t): @@ -671,23 +669,13 @@ def check_examples(t): t.run('%(PHANTOMJS)s', 'bin/check-example.js', example) -@target(PROJ4JS, PROJ4JS_ZIP) +@target(PROJ4JS) def proj4js(t): - from zipfile import ZipFile - zf = ZipFile(PROJ4JS_ZIP) - contents = zf.open('proj4js/lib/proj4js-combined.js').read() + contents = open('node_modules/proj4/dist/proj4.js').read() with open(t.name, 'wb') as f: f.write(contents) -@target(PROJ4JS_ZIP, clean=False) -def proj4js_zip(t): - t.info('downloading %r', t.name) - t.download('http://download.osgeo.org/proj4js/' + - os.path.basename(t.name), md5=PROJ4JS_ZIP_MD5) - t.info('downloaded %r', t.name) - - @target('test', PROJ4JS, phony=True) def test(t): t.run('node', 'tasks/test.js') diff --git a/examples/wms-custom-proj.html b/examples/wms-custom-proj.html index 12a1dec0f1..3251b437e0 100644 --- a/examples/wms-custom-proj.html +++ b/examples/wms-custom-proj.html @@ -44,8 +44,8 @@ - - + + diff --git a/examples/wms-image-custom-proj.html b/examples/wms-image-custom-proj.html index e8c7230996..474aa9540a 100644 --- a/examples/wms-image-custom-proj.html +++ b/examples/wms-image-custom-proj.html @@ -45,8 +45,8 @@ - - + + diff --git a/test/index.html b/test/index.html index 09681d5542..ae9d85feaa 100644 --- a/test/index.html +++ b/test/index.html @@ -20,7 +20,7 @@ bail: false }); - + From dc09b0a27f6c2b84d93addd07279d9c31c52d329 Mon Sep 17 00:00:00 2001 From: Andreas Hocevar Date: Tue, 8 Jul 2014 01:01:54 +0200 Subject: [PATCH 02/19] Update externs and ol.HAVE_PROJ4JS for new proj4js API --- externs/proj4js.js | 88 ++++++++++----------------------------------- src/ol/proj/proj.js | 2 +- 2 files changed, 20 insertions(+), 70 deletions(-) diff --git a/externs/proj4js.js b/externs/proj4js.js index d91a06b561..d8e42e1d72 100644 --- a/externs/proj4js.js +++ b/externs/proj4js.js @@ -1,92 +1,42 @@ /** * @externs - * @see http://trac.osgeo.org/proj4js/ + * @see http://proj4js.org/ */ /** - * @type {Object} + * @type {Function} */ -var Proj4js = {}; +var proj4 = function() {}; /** * @type {Object.} */ -Proj4js.defs; - - -/** - * @type {function(string)} - */ -Proj4js.reportError; +proj4.defs; /** * @constructor - * @param {number} x - * @param {number} y + * @param {Object|string} proj */ -Proj4js.Point = function(x, y) {}; +proj4.Proj = function(proj) {}; + + +/** + * @type {string} + */ +proj4.Proj.prototype.axis; + + +/** + * @type {string} + */ +proj4.Proj.prototype.units; /** * @type {number} */ -Proj4js.Point.prototype.x; - - -/** - * @type {number} - */ -Proj4js.Point.prototype.y; - - - -/** - * @constructor - * @param {string} srsCode - * @param {Function=} opt_callback - */ -Proj4js.Proj = function(srsCode, opt_callback) {}; - - -/** - * @type {string} - */ -Proj4js.Proj.prototype.axis; - - -/** - * @type {string} - */ -Proj4js.Proj.prototype.title; - - -/** - * @type {string} - */ -Proj4js.Proj.prototype.units; - - -/** - * @type {string} - */ -Proj4js.Proj.prototype.srsCode; - - -/** - * @type {number} - */ -Proj4js.Proj.prototype.to_meter; - - -/** - * @nosideeffects - * @param {Proj4js.Proj} source - * @param {Proj4js.Proj} dest - * @param {Proj4js.Point|{x:number, y:number}} point - * @return {Proj4js.Point} - */ -Proj4js.transform = function(source, dest, point) {return null;}; +proj4.Proj.prototype.to_meter; diff --git a/src/ol/proj/proj.js b/src/ol/proj/proj.js index 421874a57f..c205ffffe8 100644 --- a/src/ol/proj/proj.js +++ b/src/ol/proj/proj.js @@ -19,7 +19,7 @@ goog.require('ol.sphere.NORMAL'); * @const * @type {boolean} */ -ol.HAVE_PROJ4JS = ol.ENABLE_PROJ4JS && typeof Proj4js == 'object'; +ol.HAVE_PROJ4JS = ol.ENABLE_PROJ4JS && typeof proj4 == 'function'; /** From 8b89f5b6892b4af422477ef2e5b32d80aa0bd323 Mon Sep 17 00:00:00 2001 From: Andreas Hocevar Date: Tue, 8 Jul 2014 01:08:00 +0200 Subject: [PATCH 03/19] Update API to work with custom transforms, including proj4js All transparent proj4js handling is now in ol.proj.get, and a new addCoordinateTransforms function makes it easy to configure custom transform functions. ol.Proj4jsProjection is no longer needed. --- externs/olx.js | 30 ++-- src/ol/proj/proj.js | 352 +++++++++++++++++--------------------------- 2 files changed, 150 insertions(+), 232 deletions(-) diff --git a/externs/olx.js b/externs/olx.js index 4dc7e75a87..af32ea0812 100644 --- a/externs/olx.js +++ b/externs/olx.js @@ -275,34 +275,28 @@ olx.OverlayOptions.prototype.insertFirst; /** - * Object literal with config options for the Proj4js projection. - * @typedef {{code: string, - * extent: (ol.Extent|undefined), - * global: (boolean|undefined)}} + * Object literal with forward and inverse coordinate transforms. + * @typedef {{forward: function(ol.Coordinate): ol.Coordinate, + * inverse: function(ol.Coordinate): ol.Coordinate}} * @api */ -olx.Proj4jsProjectionOptions; +olx.CoordinateTransforms; /** - * The SRS identifier code, e.g. `EPSG:31256`. - * @type {string} + * The forward transform function that takes a {@link ol.Coordinate} as argument + * and returns the transformed {@link ol.Coordinate}. + * @type {function(ol.Coordinate): ol.Coordinate} */ -olx.Proj4jsProjectionOptions.prototype.code; +olx.CoordinateTransforms.prototype.forward; /** - * The validity extent for the SRS. - * @type {ol.Extent|undefined} + * The inverse transform function that takes a {@link ol.Coordinate} as argument + * and returns the transformed {@link ol.Coordinate}. + * @type {function(ol.Coordinate): ol.Coordinate} */ -olx.Proj4jsProjectionOptions.prototype.extent; - - -/** - * Whether the projection is valid for the whole globe. Default is `false`. - * @type {boolean|undefined} - */ -olx.Proj4jsProjectionOptions.prototype.global; +olx.CoordinateTransforms.prototype.inverse; /** diff --git a/src/ol/proj/proj.js b/src/ol/proj/proj.js index c205ffffe8..20d2397c50 100644 --- a/src/ol/proj/proj.js +++ b/src/ol/proj/proj.js @@ -64,10 +64,10 @@ ol.proj.METERS_PER_UNIT[ol.proj.Units.METERS] = 1; * geographic (EPSG:4326) and web or spherical mercator (EPSG:3857) * coordinate reference systems. * - * Additional transforms may be added by using the - * {@link http://proj4js.org/|proj4js} library. If the proj4js library is - * included, the method will work between any two coordinate - * reference systems with proj4js definitions. + * Additional transforms may be added by using the {@link http://proj4js.org/} + * library. If the proj4js library is loaded, transforms will work between any + * coordinate reference systems with proj4js definitions. These definitions can + * be obtained from {@link http://epsg.io/}. * * @constructor * @param {olx.ProjectionOptions} options Projection options. @@ -136,19 +136,6 @@ ol.proj.Projection.prototype.getExtent = function() { }; -/** - * Get the resolution of the point in degrees. For projections with degrees as - * the unit this will simply return the provided resolution. For other - * projections the point resolution is estimated by transforming the center - * pixel to EPSG:4326, measuring its width and height on the normal sphere, - * and taking the average of the width and height. - * @param {number} resolution Resolution. - * @param {ol.Coordinate} point Point. - * @return {number} Point resolution. - */ -ol.proj.Projection.prototype.getPointResolution = goog.abstractMethod; - - /** * Get the units of this projection. * @return {ol.proj.Units} Units. @@ -209,80 +196,42 @@ ol.proj.Projection.prototype.setDefaultTileGrid = function(tileGrid) { }; - /** - * @constructor - * @extends {ol.proj.Projection} - * @param {Proj4js.Proj} proj4jsProj Proj4js projection. - * @param {olx.Proj4jsProjectionOptions} options Proj4js projection options. - * @private - * @struct + * Set the validity extent for this projection. + * @param {ol.Extent} extent Extent. + * @api */ -ol.Proj4jsProjection_ = function(proj4jsProj, options) { - - var units = /** @type {ol.proj.Units} */ (proj4jsProj.units); - - var config = /** @type {olx.ProjectionOptions} */ ({ - units: units, - axisOrientation: proj4jsProj.axis - }); - goog.object.extend(config, options); - - goog.base(this, config); - - /** - * @private - * @type {Proj4js.Proj} - */ - this.proj4jsProj_ = proj4jsProj; - - /** - * @private - * @type {?ol.TransformFunction} - */ - this.toEPSG4326_ = null; - -}; -goog.inherits(ol.Proj4jsProjection_, ol.proj.Projection); - - -/** - * @inheritDoc - */ -ol.Proj4jsProjection_.prototype.getMetersPerUnit = function() { - var metersPerUnit = this.proj4jsProj_.to_meter; - if (!goog.isDef(metersPerUnit)) { - metersPerUnit = ol.proj.METERS_PER_UNIT[this.units_]; - } - return metersPerUnit; +ol.proj.Projection.prototype.setExtent = function(extent) { + this.extent_ = extent; }; /** - * @inheritDoc + * Get the resolution of the point in degrees. For projections with degrees as + * the unit this will simply return the provided resolution. For other + * projections the point resolution is estimated by transforming the center + * pixel to EPSG:4326, measuring its width and height on the normal sphere, + * and taking the average of the width and height. + * @param {number} resolution Resolution. + * @param {ol.Coordinate} point Point. + * @return {number} Point resolution. */ -ol.Proj4jsProjection_.prototype.getPointResolution = - function(resolution, point) { +ol.proj.Projection.prototype.getPointResolution = function(resolution, point) { if (this.getUnits() == ol.proj.Units.DEGREES) { return resolution; } else { // Estimate point resolution by transforming the center pixel to EPSG:4326, // measuring its width and height on the normal sphere, and taking the // average of the width and height. - if (goog.isNull(this.toEPSG4326_)) { - this.toEPSG4326_ = ol.proj.getTransformFromProjections( - this, ol.proj.getProj4jsProjectionFromCode_({ - code: 'EPSG:4326', - extent: null - })); - } + var toEPSG4326 = ol.proj.getTransformFromProjections( + this, ol.proj.get('EPSG:4326')); var vertices = [ point[0] - resolution / 2, point[1], point[0] + resolution / 2, point[1], point[0], point[1] - resolution / 2, point[0], point[1] + resolution / 2 ]; - vertices = this.toEPSG4326_(vertices, vertices, 2); + vertices = toEPSG4326(vertices, vertices, 2); var width = ol.sphere.NORMAL.haversineDistance( vertices.slice(0, 2), vertices.slice(2, 4)); var height = ol.sphere.NORMAL.haversineDistance( @@ -298,21 +247,6 @@ ol.Proj4jsProjection_.prototype.getPointResolution = }; -/** - * @return {Proj4js.Proj} Proj4js projection. - */ -ol.Proj4jsProjection_.prototype.getProj4jsProj = function() { - return this.proj4jsProj_; -}; - - -/** - * @private - * @type {Object.} - */ -ol.proj.proj4jsProjections_ = {}; - - /** * @private * @type {Object.} @@ -331,17 +265,21 @@ ol.proj.transforms_ = {}; * Registers transformation functions that don't alter coordinates. Those allow * to transform between projections with equal meaning. * - * @param {Array.} projections Projections. + * @param {Array.} projections + * Projections. + * @return {Array.} The added equivalent projections. + * @api */ ol.proj.addEquivalentProjections = function(projections) { - ol.proj.addProjections(projections); - goog.array.forEach(projections, function(source) { - goog.array.forEach(projections, function(destination) { + var addedProjections = ol.proj.addProjections(projections); + goog.array.forEach(addedProjections, function(source) { + goog.array.forEach(addedProjections, function(destination) { if (source !== destination) { ol.proj.addTransform(source, destination, ol.proj.cloneTransform); } }); }); + return addedProjections; }; @@ -369,39 +307,37 @@ ol.proj.addEquivalentTransforms = }; -/** - * @param {ol.Proj4jsProjection_} proj4jsProjection Proj4js projection. - * @private - */ -ol.proj.addProj4jsProjection_ = function(proj4jsProjection) { - var proj4jsProjections = ol.proj.proj4jsProjections_; - var code = proj4jsProjection.getCode(); - goog.asserts.assert(!goog.object.containsKey(proj4jsProjections, code)); - proj4jsProjections[code] = proj4jsProjection; -}; - - /** * Add a Projection object to the list of supported projections. * - * @param {ol.proj.Projection} projection Projection object. + * @param {ol.proj.Projection|olx.ProjectionOptions} projection Projection + * instance or configuration. + * @return {ol.proj.Projection} The added projection. * @api */ ol.proj.addProjection = function(projection) { var projections = ol.proj.projections_; - var code = projection.getCode(); - projections[code] = projection; - ol.proj.addTransform(projection, projection, ol.proj.cloneTransform); + var proj = projection instanceof ol.proj.Projection ? + projection : + new ol.proj.Projection(/** @type {olx.ProjectionOptions} */ (projection)); + var code = proj.getCode(); + projections[code] = proj; + ol.proj.addTransform(proj, proj, ol.proj.cloneTransform); + return proj; }; /** - * @param {Array.} projections Projections. + * @param {Array.} projections + * Projections. + * @return {Array.} The added projections. */ ol.proj.addProjections = function(projections) { + var addedProjections = []; goog.array.forEach(projections, function(projection) { - ol.proj.addProjection(projection); + addedProjections.push(ol.proj.addProjection(projection)); }); + return addedProjections; }; @@ -409,9 +345,6 @@ ol.proj.addProjections = function(projections) { * FIXME empty description for jsdoc */ ol.proj.clearAllProjections = function() { - if (ol.ENABLE_PROJ4JS) { - ol.proj.proj4jsProjections_ = {}; - } ol.proj.projections_ = {}; ol.proj.transforms_ = {}; }; @@ -453,6 +386,62 @@ ol.proj.addTransform = function(source, destination, transformFn) { }; +/** + * Registers coordinate transform functions to convert coordinates between the + * source projection and the destination projection. + * + * @param {ol.proj.ProjectionLike} source Source projection. + * @param {ol.proj.ProjectionLike} destination Destination projection. + * @param {olx.CoordinateTransforms} transforms Forward and inverse transform + * functions. + * @api + */ +ol.proj.addCoordinateTransforms = function(source, destination, transforms) { + var sourceProj = ol.proj.get(source); + var destProj = ol.proj.get(destination); + var forward, inverse; + if (sourceProj === destProj) { + forward = ol.proj.cloneTransform; + inverse = ol.proj.cloneTransform; + } else { + forward = + ol.proj.createTransformFromCoordinateTransform(transforms.forward); + inverse = + ol.proj.createTransformFromCoordinateTransform(transforms.inverse); + } + ol.proj.addTransform(sourceProj, destProj, forward); + ol.proj.addTransform(destProj, sourceProj, inverse); +}; + + +/** + * Creates a {@link ol.TransformFunction} from a simple 2D coordinate transform + * function. + * @param {function(ol.Coordinate): ol.Coordinate} transform Coordinate + * transform. + * @return {ol.TransformFunction} Transform function. + */ +ol.proj.createTransformFromCoordinateTransform = function(transform) { + return /** @type {ol.TransformFunction} */ ( + function(input, opt_output, opt_dimension) { + var length = input.length; + var dimension = goog.isDef(opt_dimension) ? opt_dimension : 2; + var output = goog.isDef(opt_output) ? opt_output : new Array(length); + var point, i, j; + for (i = 0; i < length; i += dimension) { + point = transform([input[i], input[i + 1]]); + output[i] = point[0]; + output[i + 1] = point[1]; + for (j = dimension - 1; j >= 2; --j) { + output[i + j] = input[i + j]; + } + } + return output; + } + ); +}; + + /** * Unregisters the conversion function to convert coordinates from the source * projection to the destination projection. This method is used to clean up @@ -493,16 +482,44 @@ ol.proj.get = function(projectionLike) { projection = projectionLike; } else if (goog.isString(projectionLike)) { var code = projectionLike; - projection = ol.proj.projections_[code]; + var projections = ol.proj.projections_; + projection = projections[code]; if (ol.HAVE_PROJ4JS && !goog.isDef(projection)) { - projection = ol.proj.getProj4jsProjectionFromCode_({ - code: code, - extent: null - }); - } - if (!goog.isDef(projection)) { - goog.asserts.assert(goog.isDef(projection)); - projection = null; + var proj4jsProj; + var def = proj4.defs[code]; + if (goog.isDef(def)) { + proj4jsProj = new proj4.Proj(code); + var units = proj4jsProj.units; + if (!goog.isDef(units)) { + if (goog.isDef(proj4jsProj.to_meter)) { + units = proj4jsProj.to_meter.toString(); + ol.proj.METERS_PER_UNIT[units] = proj4jsProj.to_meter; + } + } + projection = new ol.proj.Projection({ + code: code, + units: units, + axisOrientation: proj4jsProj.axis + }); + ol.proj.addProjection(projection); + var currentCode, currentDef, currentProj, currentProj4jsProj; + for (currentCode in projections) { + currentDef = proj4.defs[currentCode]; + if (goog.isDef(currentDef)) { + currentProj4jsProj = new proj4.Proj(currentCode); + currentProj = ol.proj.get(currentCode); + if (currentDef === def) { + ol.proj.addEquivalentProjections([currentProj, projection]); + } else { + ol.proj.addCoordinateTransforms(currentProj, projection, + proj4(currentProj4jsProj, proj4jsProj)); + } + } + } + } else { + goog.asserts.assert(goog.isDef(projection)); + projection = null; + } } } else { projection = null; @@ -511,32 +528,6 @@ ol.proj.get = function(projectionLike) { }; -/** - * @param {olx.Proj4jsProjectionOptions} options Proj4js projection options. - * @private - * @return {ol.Proj4jsProjection_} Proj4js projection. - */ -ol.proj.getProj4jsProjectionFromCode_ = function(options) { - var code = options.code; - var proj4jsProjections = ol.proj.proj4jsProjections_; - var proj4jsProjection = proj4jsProjections[code]; - if (!goog.isDef(proj4jsProjection)) { - var proj4jsProj = new Proj4js.Proj(code); - var srsCode = proj4jsProj.srsCode; - proj4jsProjection = proj4jsProjections[srsCode]; - if (!goog.isDef(proj4jsProjection)) { - var config = /** @type {olx.Proj4jsProjectionOptions} */ - (goog.object.clone(options)); - config.code = srsCode; - proj4jsProjection = new ol.Proj4jsProjection_(proj4jsProj, config); - proj4jsProjections[srsCode] = proj4jsProjection; - } - proj4jsProjections[code] = proj4jsProjection; - } - return proj4jsProjection; -}; - - /** * Checks if two projections are the same, that is every coordinate in one * projection does represent the same geographic point as the same coordinate in @@ -596,61 +587,6 @@ ol.proj.getTransformFromProjections = goog.object.containsKey(transforms[sourceCode], destinationCode)) { transform = transforms[sourceCode][destinationCode]; } - if (ol.HAVE_PROJ4JS && !goog.isDef(transform)) { - var proj4jsSource; - if (sourceProjection instanceof ol.Proj4jsProjection_) { - proj4jsSource = sourceProjection; - } else { - proj4jsSource = - ol.proj.getProj4jsProjectionFromCode_({ - code: sourceCode, - extent: null - }); - } - var sourceProj4jsProj = proj4jsSource.getProj4jsProj(); - var proj4jsDestination; - if (destinationProjection instanceof ol.Proj4jsProjection_) { - proj4jsDestination = destinationProjection; - } else { - proj4jsDestination = - ol.proj.getProj4jsProjectionFromCode_({ - code: destinationCode, - extent: null - }); - } - var destinationProj4jsProj = proj4jsDestination.getProj4jsProj(); - transform = - /** - * @param {Array.} input Input coordinate values. - * @param {Array.=} opt_output Output array of coordinates. - * @param {number=} opt_dimension Dimension. - * @return {Array.} Output coordinate values. - */ - function(input, opt_output, opt_dimension) { - var length = input.length, - dimension = opt_dimension > 1 ? opt_dimension : 2, - output = opt_output; - if (!goog.isDef(output)) { - if (dimension > 2) { - // preserve values beyond second dimension - output = input.slice(); - } else { - output = new Array(length); - } - } - goog.asserts.assert(output.length % dimension === 0); - var proj4jsPoint; - for (var i = 0; i < length; i += dimension) { - proj4jsPoint = new Proj4js.Point(input[i], input[i + 1]); - proj4jsPoint = Proj4js.transform( - sourceProj4jsProj, destinationProj4jsProj, proj4jsPoint); - output[i] = proj4jsPoint.x; - output[i + 1] = proj4jsPoint.y; - } - return output; - }; - ol.proj.addTransform(sourceProjection, destinationProjection, transform); - } if (!goog.isDef(transform)) { goog.asserts.assert(goog.isDef(transform)); transform = ol.proj.identityTransform; @@ -749,15 +685,3 @@ ol.proj.transformWithProjections = sourceProjection, destinationProjection); return transformFn(point); }; - - -/** - * @param {olx.Proj4jsProjectionOptions} options Proj4js projection options. - * @return {ol.proj.Projection} Proj4js projection. - * @api - */ -ol.proj.configureProj4jsProjection = function(options) { - goog.asserts.assert(!goog.object.containsKey( - ol.proj.proj4jsProjections_, options.code)); - return ol.proj.getProj4jsProjectionFromCode_(options); -}; From b5bdd0d4bb958ee470ce923f65ad3fa0f417bcae Mon Sep 17 00:00:00 2001 From: Andreas Hocevar Date: Tue, 8 Jul 2014 01:08:09 +0200 Subject: [PATCH 04/19] Update tests --- test/spec/ol/format/wfsformat.test.js | 5 +++ test/spec/ol/proj/proj.test.js | 54 +++++---------------------- 2 files changed, 15 insertions(+), 44 deletions(-) diff --git a/test/spec/ol/format/wfsformat.test.js b/test/spec/ol/format/wfsformat.test.js index 87e4873da0..2675999396 100644 --- a/test/spec/ol/format/wfsformat.test.js +++ b/test/spec/ol/format/wfsformat.test.js @@ -6,6 +6,7 @@ describe('ol.format.WFS', function() { var features, feature; before(function(done) { + proj4.defs['urn:x-ogc:def:crs:EPSG:4326'] = proj4.defs('EPSG:4326'); afterLoadText('spec/ol/format/wfs/topp-states-wfs.xml', function(xml) { try { var config = { @@ -54,6 +55,10 @@ describe('ol.format.WFS', function() { describe('when parsing FeatureCollection', function() { var response; before(function(done) { + proj4.defs('EPSG:28992', '+proj=sterea +lat_0=52.15616055555555 ' + + '+lon_0=5.38763888888889 +k=0.9999079 +x_0=155000 +y_0=463000 ' + + '+ellps=bessel +towgs84=565.417,50.3319,465.552,-0.398957,0.343988,' + + '-1.8774,4.0725 +units=m +no_defs'); afterLoadText('spec/ol/format/wfs/boundedBy.xml', function(xml) { try { diff --git a/test/spec/ol/proj/proj.test.js b/test/spec/ol/proj/proj.test.js index 9cceae83d7..ea1107d1f9 100644 --- a/test/spec/ol/proj/proj.test.js +++ b/test/spec/ol/proj/proj.test.js @@ -128,10 +128,10 @@ describe('ol.proj', function() { }); it('allows new Proj4js projections to be defined', function() { - Proj4js.defs['EPSG:21781'] = + proj4.defs('EPSG:21781', '+proj=somerc +lat_0=46.95240555555556 +lon_0=7.439583333333333 ' + '+k_0=1 +x_0=600000 +y_0=200000 +ellps=bessel ' + - '+towgs84=674.374,15.056,405.346,0,0,0,0 +units=m +no_defs'; + '+towgs84=674.374,15.056,405.346,0,0,0,0 +units=m +no_defs'); var point = ol.proj.transform([7.439583333333333, 46.95240555555556], 'EPSG:4326', 'EPSG:21781'); expect(point[0]).to.roughlyEqual(600072.300, 1); @@ -139,17 +139,12 @@ describe('ol.proj', function() { }); it('caches the new Proj4js projections given their srsCode', function() { - Proj4js.defs['EPSG:21781'] = - '+proj=somerc +lat_0=46.95240555555556 +lon_0=7.439583333333333 ' + - '+k_0=1 +x_0=600000 +y_0=200000 +ellps=bessel ' + - '+towgs84=674.374,15.056,405.346,0,0,0,0 +units=m +no_defs'; var code = 'urn:ogc:def:crs:EPSG:21781'; var srsCode = 'EPSG:21781'; + proj4.defs[code] = proj4.defs[srsCode]; var proj = ol.proj.get(code); - expect(ol.proj.proj4jsProjections_.hasOwnProperty(code)).to.be.ok(); - expect(ol.proj.proj4jsProjections_.hasOwnProperty(srsCode)).to.be.ok(); var proj2 = ol.proj.get(srsCode); - expect(proj2).to.be(proj); + expect(ol.proj.equivalent(proj2, proj)).to.be(true); }); it('numerically estimates point scale at the equator', function() { @@ -186,11 +181,9 @@ describe('ol.proj', function() { describe('ol.proj.getTransformFromProjections()', function() { - var sm = ol.proj.get('GOOGLE'); - var gg = ol.proj.get('EPSG:4326'); - it('returns a transform function', function() { - var transform = ol.proj.getTransformFromProjections(sm, gg); + var transform = ol.proj.getTransformFromProjections(ol.proj.get('GOOGLE'), + ol.proj.get('EPSG:4326')); expect(typeof transform).to.be('function'); var output = transform([-12000000, 5000000]); @@ -200,7 +193,8 @@ describe('ol.proj', function() { }); it('works for longer arrays', function() { - var transform = ol.proj.getTransformFromProjections(sm, gg); + var transform = ol.proj.getTransformFromProjections(ol.proj.get('GOOGLE'), + ol.proj.get('EPSG:4326')); expect(typeof transform).to.be('function'); var output = transform([-12000000, 5000000, -12000000, 5000000]); @@ -318,18 +312,10 @@ describe('ol.proj', function() { describe('ol.proj.Projection.prototype.getMetersPerUnit()', function() { beforeEach(function() { - Proj4js.defs['EPSG:26782'] = + proj4.defs('EPSG:26782', '+proj=lcc +lat_1=29.3 +lat_2=30.7 +lat_0=28.66666666666667 ' + '+lon_0=-91.33333333333333 +x_0=609601.2192024384 +y_0=0 ' + - '+ellps=clrk66 +datum=NAD27 +to_meter=0.3048006096012192 +no_defs'; - ol.proj.configureProj4jsProjection({ - code: 'EPSG:26782' - }); - }); - - afterEach(function() { - ol.proj.proj4jsProjections_ = {}; - delete Proj4js.defs['EPSG:26782']; + '+ellps=clrk66 +datum=NAD27 +to_meter=0.3048006096012192 +no_defs'); }); it('returns value in meters', function() { @@ -344,26 +330,6 @@ describe('ol.proj', function() { }); - describe('ol.proj.configureProj4jsProjection()', function() { - - beforeEach(function() { - ol.proj.proj4jsProjections_ = {}; - }); - - it('returns a configured projection', function() { - var extent = [485869.5728, 76443.1884, 837076.5648, 299941.7864]; - var epsg21781 = ol.proj.configureProj4jsProjection({ - code: 'EPSG:21781', - extent: extent - }); - expect(epsg21781.getCode()).to.eql('EPSG:21781'); - expect(epsg21781.getExtent()).to.be(extent); - expect(epsg21781.getUnits()).to.be(ol.proj.Units.METERS); - expect(epsg21781.isGlobal()).to.not.be(); - }); - - }); - }); From dfe92da58deab884d0f41e1358924fcbbaea281a Mon Sep 17 00:00:00 2001 From: Andreas Hocevar Date: Tue, 8 Jul 2014 01:10:29 +0200 Subject: [PATCH 05/19] Update example to show manual proj4js configuration --- examples/wms-custom-proj.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/examples/wms-custom-proj.js b/examples/wms-custom-proj.js index 39ba860d2b..8463e8c49a 100644 --- a/examples/wms-custom-proj.js +++ b/examples/wms-custom-proj.js @@ -8,10 +8,15 @@ goog.require('ol.proj'); goog.require('ol.source.TileWMS'); -var projection = ol.proj.configureProj4jsProjection({ +var proj4Proj = new proj4.Proj('EPSG:21781'); +var projection = ol.proj.addProjection({ code: 'EPSG:21781', - extent: [485869.5728, 76443.1884, 837076.5648, 299941.7864] + extent: [485869.5728, 76443.1884, 837076.5648, 299941.7864], + units: proj4Proj.units }); +// The transform is needed for the ScaleLine control. Otherwise this example +// would also work without proj4js. +ol.proj.addCoordinateTransforms('EPSG:4326', projection, proj4(proj4Proj)); var extent = [420000, 30000, 900000, 350000]; var layers = [ From 0c62469f507b54536ee51d5fc8697b398f6dafbf Mon Sep 17 00:00:00 2001 From: Andreas Hocevar Date: Tue, 8 Jul 2014 01:10:47 +0200 Subject: [PATCH 06/19] Update example to show transparent proj4js integration --- examples/wms-image-custom-proj.html | 2 +- examples/wms-image-custom-proj.js | 14 ++++++++++---- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/examples/wms-image-custom-proj.html b/examples/wms-image-custom-proj.html index 474aa9540a..8c0868f4e9 100644 --- a/examples/wms-image-custom-proj.html +++ b/examples/wms-image-custom-proj.html @@ -37,7 +37,7 @@

Pixelmap 1:1'000'000 with National Parks overlay using the projection EPSG:21781.

See the wms-image-custom-proj.js source to see how this is done.

-
wms, single image, projection
+
wms, single image, proj4js, projection
diff --git a/examples/wms-image-custom-proj.js b/examples/wms-image-custom-proj.js index d7f0b45f0b..1f6ca2fde8 100644 --- a/examples/wms-image-custom-proj.js +++ b/examples/wms-image-custom-proj.js @@ -1,15 +1,16 @@ goog.require('ol.Attribution'); goog.require('ol.Map'); goog.require('ol.View'); +goog.require('ol.control'); +goog.require('ol.control.ScaleLine'); goog.require('ol.layer.Image'); goog.require('ol.proj'); goog.require('ol.source.ImageWMS'); -var projection = ol.proj.configureProj4jsProjection({ - code: 'EPSG:21781', - extent: [485869.5728, 76443.1884, 837076.5648, 299941.7864] -}); +var projection = ol.proj.get('EPSG:21781'); +// The extent is used to determine zoom level 0 +projection.setExtent([485869.5728, 76443.1884, 837076.5648, 299941.7864]); var extent = [420000, 30000, 900000, 350000]; var layers = [ @@ -49,6 +50,11 @@ var layers = [ ]; var map = new ol.Map({ + controls: ol.control.defaults().extend([ + new ol.control.ScaleLine({ + units: 'metric' + }) + ]), layers: layers, renderer: exampleNS.getRendererFromQueryString(), target: 'map', From 8b2277cdda45ab322cb2fc7b8d012d7c3ebdd6ba Mon Sep 17 00:00:00 2001 From: Andreas Hocevar Date: Tue, 8 Jul 2014 15:56:32 +0200 Subject: [PATCH 07/19] Use proj4.defs instead of proj4.Proj, to conform with the proj4js API --- examples/wms-custom-proj.js | 6 ++--- externs/proj4js.js | 32 ++++----------------------- src/ol/proj/proj.js | 17 ++++++-------- test/spec/ol/format/wfsformat.test.js | 2 +- 4 files changed, 15 insertions(+), 42 deletions(-) diff --git a/examples/wms-custom-proj.js b/examples/wms-custom-proj.js index 8463e8c49a..cea7a442ee 100644 --- a/examples/wms-custom-proj.js +++ b/examples/wms-custom-proj.js @@ -8,15 +8,15 @@ goog.require('ol.proj'); goog.require('ol.source.TileWMS'); -var proj4Proj = new proj4.Proj('EPSG:21781'); +var proj4Def = proj4.defs['EPSG:21781']; var projection = ol.proj.addProjection({ code: 'EPSG:21781', extent: [485869.5728, 76443.1884, 837076.5648, 299941.7864], - units: proj4Proj.units + units: proj4Def.units }); // The transform is needed for the ScaleLine control. Otherwise this example // would also work without proj4js. -ol.proj.addCoordinateTransforms('EPSG:4326', projection, proj4(proj4Proj)); +ol.proj.addCoordinateTransforms('EPSG:4326', projection, proj4('EPSG:21781')); var extent = [420000, 30000, 900000, 350000]; var layers = [ diff --git a/externs/proj4js.js b/externs/proj4js.js index d8e42e1d72..2544c32a84 100644 --- a/externs/proj4js.js +++ b/externs/proj4js.js @@ -11,32 +11,8 @@ var proj4 = function() {}; /** - * @type {Object.} + * @typedef {Object.>} */ -proj4.defs; - - - -/** - * @constructor - * @param {Object|string} proj - */ -proj4.Proj = function(proj) {}; - - -/** - * @type {string} - */ -proj4.Proj.prototype.axis; - - -/** - * @type {string} - */ -proj4.Proj.prototype.units; - - -/** - * @type {number} - */ -proj4.Proj.prototype.to_meter; +proj4.defs; \ No newline at end of file diff --git a/src/ol/proj/proj.js b/src/ol/proj/proj.js index 20d2397c50..28d62d7efb 100644 --- a/src/ol/proj/proj.js +++ b/src/ol/proj/proj.js @@ -485,34 +485,31 @@ ol.proj.get = function(projectionLike) { var projections = ol.proj.projections_; projection = projections[code]; if (ol.HAVE_PROJ4JS && !goog.isDef(projection)) { - var proj4jsProj; var def = proj4.defs[code]; if (goog.isDef(def)) { - proj4jsProj = new proj4.Proj(code); - var units = proj4jsProj.units; + var units = def.units; if (!goog.isDef(units)) { - if (goog.isDef(proj4jsProj.to_meter)) { - units = proj4jsProj.to_meter.toString(); - ol.proj.METERS_PER_UNIT[units] = proj4jsProj.to_meter; + if (goog.isDef(def.to_meter)) { + units = def.to_meter.toString(); + ol.proj.METERS_PER_UNIT[units] = def.to_meter; } } projection = new ol.proj.Projection({ code: code, units: units, - axisOrientation: proj4jsProj.axis + axisOrientation: def.axis }); ol.proj.addProjection(projection); - var currentCode, currentDef, currentProj, currentProj4jsProj; + var currentCode, currentDef, currentProj; for (currentCode in projections) { currentDef = proj4.defs[currentCode]; if (goog.isDef(currentDef)) { - currentProj4jsProj = new proj4.Proj(currentCode); currentProj = ol.proj.get(currentCode); if (currentDef === def) { ol.proj.addEquivalentProjections([currentProj, projection]); } else { ol.proj.addCoordinateTransforms(currentProj, projection, - proj4(currentProj4jsProj, proj4jsProj)); + proj4(currentCode, code)); } } } diff --git a/test/spec/ol/format/wfsformat.test.js b/test/spec/ol/format/wfsformat.test.js index 2675999396..a20aeee715 100644 --- a/test/spec/ol/format/wfsformat.test.js +++ b/test/spec/ol/format/wfsformat.test.js @@ -6,7 +6,7 @@ describe('ol.format.WFS', function() { var features, feature; before(function(done) { - proj4.defs['urn:x-ogc:def:crs:EPSG:4326'] = proj4.defs('EPSG:4326'); + proj4.defs['urn:x-ogc:def:crs:EPSG:4326'] = proj4.defs['EPSG:4326']; afterLoadText('spec/ol/format/wfs/topp-states-wfs.xml', function(xml) { try { var config = { From 88ab1ac61a6d5299c6539626a2cba7f600209ab1 Mon Sep 17 00:00:00 2001 From: Andreas Hocevar Date: Tue, 8 Jul 2014 16:31:18 +0200 Subject: [PATCH 08/19] Doc changes suggested by @probins --- examples/wms-custom-proj.js | 10 +++++++--- examples/wms-image-custom-proj.js | 11 +++++++---- externs/olx.js | 6 ++++-- src/ol/proj/proj.js | 3 ++- 4 files changed, 20 insertions(+), 10 deletions(-) diff --git a/examples/wms-custom-proj.js b/examples/wms-custom-proj.js index cea7a442ee..cb796551f4 100644 --- a/examples/wms-custom-proj.js +++ b/examples/wms-custom-proj.js @@ -8,14 +8,18 @@ goog.require('ol.proj'); goog.require('ol.source.TileWMS'); -var proj4Def = proj4.defs['EPSG:21781']; +// EPSG:21781 is known to Proj4js because its definition was loaded in the html. var projection = ol.proj.addProjection({ code: 'EPSG:21781', + // The extent is used to determine zoom level 0. Recommended values for a + // projection's validity extent can be found at http://epsg.io/. extent: [485869.5728, 76443.1884, 837076.5648, 299941.7864], - units: proj4Def.units + // Use data from proj4js to configure the projection's units. + units: proj4.defs['EPSG:21781'].units }); +// Proj4js provides transform functions between its configured projections. // The transform is needed for the ScaleLine control. Otherwise this example -// would also work without proj4js. +// would also work without transform functions. ol.proj.addCoordinateTransforms('EPSG:4326', projection, proj4('EPSG:21781')); var extent = [420000, 30000, 900000, 350000]; diff --git a/examples/wms-image-custom-proj.js b/examples/wms-image-custom-proj.js index 1f6ca2fde8..d57bc93675 100644 --- a/examples/wms-image-custom-proj.js +++ b/examples/wms-image-custom-proj.js @@ -8,8 +8,13 @@ goog.require('ol.proj'); goog.require('ol.source.ImageWMS'); +// Transparent Proj4js support: ol.proj.get() creates and returns a projection +// known to Proj4js if it is unknown to OpenLayers, and registers functions to +// transform between all registered projections. +// EPSG:21781 is known to Proj4js because its definition was loaded in the html. var projection = ol.proj.get('EPSG:21781'); -// The extent is used to determine zoom level 0 +// The extent is used to determine zoom level 0. Recommended values for a +// projection's validity extent can be found at http://epsg.io/. projection.setExtent([485869.5728, 76443.1884, 837076.5648, 299941.7864]); var extent = [420000, 30000, 900000, 350000]; @@ -51,9 +56,7 @@ var layers = [ var map = new ol.Map({ controls: ol.control.defaults().extend([ - new ol.control.ScaleLine({ - units: 'metric' - }) + new ol.control.ScaleLine() ]), layers: layers, renderer: exampleNS.getRendererFromQueryString(), diff --git a/externs/olx.js b/externs/olx.js index af32ea0812..33cf67a020 100644 --- a/externs/olx.js +++ b/externs/olx.js @@ -284,7 +284,8 @@ olx.CoordinateTransforms; /** - * The forward transform function that takes a {@link ol.Coordinate} as argument + * The forward transform function (that is, from the source projection to the + * target projection) that takes a {@link ol.Coordinate} as argument * and returns the transformed {@link ol.Coordinate}. * @type {function(ol.Coordinate): ol.Coordinate} */ @@ -292,7 +293,8 @@ olx.CoordinateTransforms.prototype.forward; /** - * The inverse transform function that takes a {@link ol.Coordinate} as argument + * The inverse transform function (that is, from the target projection to the + * source projection) that takes a {@link ol.Coordinate} as argument * and returns the transformed {@link ol.Coordinate}. * @type {function(ol.Coordinate): ol.Coordinate} */ diff --git a/src/ol/proj/proj.js b/src/ol/proj/proj.js index 28d62d7efb..385b1736e2 100644 --- a/src/ol/proj/proj.js +++ b/src/ol/proj/proj.js @@ -62,7 +62,8 @@ ol.proj.METERS_PER_UNIT[ol.proj.Units.METERS] = 1; * Class for coordinate transforms between coordinate systems. By default, * OpenLayers ships with the ability to transform coordinates between * geographic (EPSG:4326) and web or spherical mercator (EPSG:3857) - * coordinate reference systems. + * coordinate reference systems. Any transform functions can be added with + * {@link ol.proj.addCoordinateTransforms}. * * Additional transforms may be added by using the {@link http://proj4js.org/} * library. If the proj4js library is loaded, transforms will work between any From 20e903f8d9de816fd270742273e8a1324094a6fd Mon Sep 17 00:00:00 2001 From: Andreas Hocevar Date: Tue, 8 Jul 2014 16:31:34 +0200 Subject: [PATCH 09/19] Add proj4 to package.json --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 6f5a267482..1f7364b9b5 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ "mocha-phantomjs": "~3.5.0", "nomnom": "~1.6.2", "phantomjs": "~1.9.7-5", + "proj4": "~2.1.4", "sinon": "~1.10.2", "temp": "~0.7.0", "walk": "~2.3.3" From a22d7e4d2213553e8e1bf07e35c731f5238af1b9 Mon Sep 17 00:00:00 2001 From: Andreas Hocevar Date: Tue, 8 Jul 2014 20:04:33 +0200 Subject: [PATCH 10/19] Allow Proj4js to be loaded after OpenLayers --- src/ol/proj/proj.js | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/ol/proj/proj.js b/src/ol/proj/proj.js index 385b1736e2..03689ec86a 100644 --- a/src/ol/proj/proj.js +++ b/src/ol/proj/proj.js @@ -14,14 +14,6 @@ goog.require('ol.extent'); goog.require('ol.sphere.NORMAL'); -/** - * Have Proj4js. - * @const - * @type {boolean} - */ -ol.HAVE_PROJ4JS = ol.ENABLE_PROJ4JS && typeof proj4 == 'function'; - - /** * A projection as {@link ol.proj.Projection}, SRS identifier string or * undefined. @@ -485,7 +477,8 @@ ol.proj.get = function(projectionLike) { var code = projectionLike; var projections = ol.proj.projections_; projection = projections[code]; - if (ol.HAVE_PROJ4JS && !goog.isDef(projection)) { + if (ol.ENABLE_PROJ4JS && !goog.isDef(projection) && + goog.isFunction(proj4)) { var def = proj4.defs[code]; if (goog.isDef(def)) { var units = def.units; From 90c745006d53ebca3e01d26e701c36e748a4b6aa Mon Sep 17 00:00:00 2001 From: Andreas Hocevar Date: Tue, 8 Jul 2014 22:33:21 +0200 Subject: [PATCH 11/19] Update to use the documented Proj4js 2.2.x API --- examples/wms-custom-proj.html | 2 +- examples/wms-custom-proj.js | 2 +- examples/wms-image-custom-proj.html | 2 +- externs/proj4js.js | 7 ++++--- package.json | 2 +- src/ol/proj/proj.js | 4 ++-- test/spec/ol/format/wfsformat.test.js | 2 +- test/spec/ol/proj/proj.test.js | 2 +- 8 files changed, 12 insertions(+), 11 deletions(-) diff --git a/examples/wms-custom-proj.html b/examples/wms-custom-proj.html index 3251b437e0..6f5c66e51e 100644 --- a/examples/wms-custom-proj.html +++ b/examples/wms-custom-proj.html @@ -44,7 +44,7 @@ - + diff --git a/examples/wms-custom-proj.js b/examples/wms-custom-proj.js index cb796551f4..4288518051 100644 --- a/examples/wms-custom-proj.js +++ b/examples/wms-custom-proj.js @@ -15,7 +15,7 @@ var projection = ol.proj.addProjection({ // projection's validity extent can be found at http://epsg.io/. extent: [485869.5728, 76443.1884, 837076.5648, 299941.7864], // Use data from proj4js to configure the projection's units. - units: proj4.defs['EPSG:21781'].units + units: proj4.defs('EPSG:21781').units }); // Proj4js provides transform functions between its configured projections. // The transform is needed for the ScaleLine control. Otherwise this example diff --git a/examples/wms-image-custom-proj.html b/examples/wms-image-custom-proj.html index 8c0868f4e9..73be411eac 100644 --- a/examples/wms-image-custom-proj.html +++ b/examples/wms-image-custom-proj.html @@ -45,7 +45,7 @@ - + diff --git a/externs/proj4js.js b/externs/proj4js.js index 2544c32a84..bcca8c150e 100644 --- a/externs/proj4js.js +++ b/externs/proj4js.js @@ -11,8 +11,9 @@ var proj4 = function() {}; /** - * @typedef {Object.>} */ -proj4.defs; \ No newline at end of file +proj4.defs = function(name, opt_def) {}; diff --git a/package.json b/package.json index 1f7364b9b5..dbf6d6f482 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,7 @@ "mocha-phantomjs": "~3.5.0", "nomnom": "~1.6.2", "phantomjs": "~1.9.7-5", - "proj4": "~2.1.4", + "proj4": "~2.2.1", "sinon": "~1.10.2", "temp": "~0.7.0", "walk": "~2.3.3" diff --git a/src/ol/proj/proj.js b/src/ol/proj/proj.js index 03689ec86a..9578d350f3 100644 --- a/src/ol/proj/proj.js +++ b/src/ol/proj/proj.js @@ -479,7 +479,7 @@ ol.proj.get = function(projectionLike) { projection = projections[code]; if (ol.ENABLE_PROJ4JS && !goog.isDef(projection) && goog.isFunction(proj4)) { - var def = proj4.defs[code]; + var def = proj4.defs(code); if (goog.isDef(def)) { var units = def.units; if (!goog.isDef(units)) { @@ -496,7 +496,7 @@ ol.proj.get = function(projectionLike) { ol.proj.addProjection(projection); var currentCode, currentDef, currentProj; for (currentCode in projections) { - currentDef = proj4.defs[currentCode]; + currentDef = proj4.defs(currentCode); if (goog.isDef(currentDef)) { currentProj = ol.proj.get(currentCode); if (currentDef === def) { diff --git a/test/spec/ol/format/wfsformat.test.js b/test/spec/ol/format/wfsformat.test.js index a20aeee715..411842bf2f 100644 --- a/test/spec/ol/format/wfsformat.test.js +++ b/test/spec/ol/format/wfsformat.test.js @@ -6,7 +6,7 @@ describe('ol.format.WFS', function() { var features, feature; before(function(done) { - proj4.defs['urn:x-ogc:def:crs:EPSG:4326'] = proj4.defs['EPSG:4326']; + proj4.defs('urn:x-ogc:def:crs:EPSG:4326', proj4.defs('EPSG:4326')); afterLoadText('spec/ol/format/wfs/topp-states-wfs.xml', function(xml) { try { var config = { diff --git a/test/spec/ol/proj/proj.test.js b/test/spec/ol/proj/proj.test.js index ea1107d1f9..32ce4449c9 100644 --- a/test/spec/ol/proj/proj.test.js +++ b/test/spec/ol/proj/proj.test.js @@ -141,7 +141,7 @@ describe('ol.proj', function() { it('caches the new Proj4js projections given their srsCode', function() { var code = 'urn:ogc:def:crs:EPSG:21781'; var srsCode = 'EPSG:21781'; - proj4.defs[code] = proj4.defs[srsCode]; + proj4.defs(code, proj4.defs(srsCode)); var proj = ol.proj.get(code); var proj2 = ol.proj.get(srsCode); expect(ol.proj.equivalent(proj2, proj)).to.be(true); From 0a01f8ef7e19806055d9f54897f25478fce3b5d9 Mon Sep 17 00:00:00 2001 From: Andreas Hocevar Date: Wed, 9 Jul 2014 13:11:57 +0200 Subject: [PATCH 12/19] Simplify ol.proj.addCoordinateTransforms Equivalent projections do not need to be handled here, and the forward and inverse functions can be function arguments instead of being nested in an object literal. --- examples/wms-custom-proj.js | 4 +++- externs/olx.js | 27 --------------------------- externs/proj4js.js | 7 +++++-- src/ol/proj/proj.js | 34 +++++++++++++++++----------------- 4 files changed, 25 insertions(+), 47 deletions(-) diff --git a/examples/wms-custom-proj.js b/examples/wms-custom-proj.js index 4288518051..087be33acb 100644 --- a/examples/wms-custom-proj.js +++ b/examples/wms-custom-proj.js @@ -20,7 +20,9 @@ var projection = ol.proj.addProjection({ // Proj4js provides transform functions between its configured projections. // The transform is needed for the ScaleLine control. Otherwise this example // would also work without transform functions. -ol.proj.addCoordinateTransforms('EPSG:4326', projection, proj4('EPSG:21781')); +var transform = proj4('EPSG:21781'); +ol.proj.addCoordinateTransforms('EPSG:4326', projection, transform.forward, + transform.inverse); var extent = [420000, 30000, 900000, 350000]; var layers = [ diff --git a/externs/olx.js b/externs/olx.js index 33cf67a020..59f641f951 100644 --- a/externs/olx.js +++ b/externs/olx.js @@ -274,33 +274,6 @@ olx.OverlayOptions.prototype.stopEvent; olx.OverlayOptions.prototype.insertFirst; -/** - * Object literal with forward and inverse coordinate transforms. - * @typedef {{forward: function(ol.Coordinate): ol.Coordinate, - * inverse: function(ol.Coordinate): ol.Coordinate}} - * @api - */ -olx.CoordinateTransforms; - - -/** - * The forward transform function (that is, from the source projection to the - * target projection) that takes a {@link ol.Coordinate} as argument - * and returns the transformed {@link ol.Coordinate}. - * @type {function(ol.Coordinate): ol.Coordinate} - */ -olx.CoordinateTransforms.prototype.forward; - - -/** - * The inverse transform function (that is, from the target projection to the - * source projection) that takes a {@link ol.Coordinate} as argument - * and returns the transformed {@link ol.Coordinate}. - * @type {function(ol.Coordinate): ol.Coordinate} - */ -olx.CoordinateTransforms.prototype.inverse; - - /** * Object literal with config options for the projection. * @typedef {{code: string, diff --git a/externs/proj4js.js b/externs/proj4js.js index bcca8c150e..aca6cfd8e2 100644 --- a/externs/proj4js.js +++ b/externs/proj4js.js @@ -5,9 +5,12 @@ /** - * @type {Function} + * @param {...*} var_args + * @return {undefined|Array.|Object.<{ + * forward: function(Array.): Array., + * inverse: function(Array.): Array.}>} */ -var proj4 = function() {}; +var proj4 = function(var_args) {}; /** diff --git a/src/ol/proj/proj.js b/src/ol/proj/proj.js index 9578d350f3..62b3c585ec 100644 --- a/src/ol/proj/proj.js +++ b/src/ol/proj/proj.js @@ -385,25 +385,24 @@ ol.proj.addTransform = function(source, destination, transformFn) { * * @param {ol.proj.ProjectionLike} source Source projection. * @param {ol.proj.ProjectionLike} destination Destination projection. - * @param {olx.CoordinateTransforms} transforms Forward and inverse transform - * functions. + * @param {function(ol.Coordinate): ol.Coordinate} forward The forward transform + * function (that is, from the source projection to the destination + * projection) that takes a {@link ol.Coordinate} as argument and returns + * the transformed {@link ol.Coordinate}. + * @param {function(ol.Coordinate): ol.Coordinate} inverse The inverse transform + * function (that is, from the destination projection to the source + * projection) that takes a {@link ol.Coordinate} as argument and returns + * the transformed {@link ol.Coordinate}. * @api */ -ol.proj.addCoordinateTransforms = function(source, destination, transforms) { +ol.proj.addCoordinateTransforms = + function(source, destination, forward, inverse) { var sourceProj = ol.proj.get(source); var destProj = ol.proj.get(destination); - var forward, inverse; - if (sourceProj === destProj) { - forward = ol.proj.cloneTransform; - inverse = ol.proj.cloneTransform; - } else { - forward = - ol.proj.createTransformFromCoordinateTransform(transforms.forward); - inverse = - ol.proj.createTransformFromCoordinateTransform(transforms.inverse); - } - ol.proj.addTransform(sourceProj, destProj, forward); - ol.proj.addTransform(destProj, sourceProj, inverse); + ol.proj.addTransform(sourceProj, destProj, + ol.proj.createTransformFromCoordinateTransform(forward)); + ol.proj.addTransform(destProj, sourceProj, + ol.proj.createTransformFromCoordinateTransform(inverse)); }; @@ -494,7 +493,7 @@ ol.proj.get = function(projectionLike) { axisOrientation: def.axis }); ol.proj.addProjection(projection); - var currentCode, currentDef, currentProj; + var currentCode, currentDef, currentProj, proj4Transform; for (currentCode in projections) { currentDef = proj4.defs(currentCode); if (goog.isDef(currentDef)) { @@ -502,8 +501,9 @@ ol.proj.get = function(projectionLike) { if (currentDef === def) { ol.proj.addEquivalentProjections([currentProj, projection]); } else { + proj4Transform = proj4(currentCode, code); ol.proj.addCoordinateTransforms(currentProj, projection, - proj4(currentCode, code)); + proj4Transform.forward, proj4Transform.inverse); } } } From fc3ed93080ea5a2a3522b502c66bd669b157062d Mon Sep 17 00:00:00 2001 From: Andreas Hocevar Date: Wed, 9 Jul 2014 14:49:28 +0200 Subject: [PATCH 13/19] Use proj4.js from node_modules/ instead of copying it to build/ --- build.py | 13 ++----------- test/index.html | 2 +- 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/build.py b/build.py index ff6b9a4ded..b24075599f 100755 --- a/build.py +++ b/build.py @@ -128,8 +128,6 @@ SRC = [path if path.endswith('.js') if path not in SHADER_SRC] -PROJ4JS = 'build/proj4js/dist/proj4.js' - def report_sizes(t): stringio = StringIO() @@ -346,7 +344,7 @@ def examples_star_combined_js(name, match): return Target(name, action=action, dependencies=dependencies) -@target('serve', PROJ4JS, 'examples') +@target('serve', 'examples') def serve(t): t.run('node', 'tasks/serve.js') @@ -669,14 +667,7 @@ def check_examples(t): t.run('%(PHANTOMJS)s', 'bin/check-example.js', example) -@target(PROJ4JS) -def proj4js(t): - contents = open('node_modules/proj4/dist/proj4.js').read() - with open(t.name, 'wb') as f: - f.write(contents) - - -@target('test', PROJ4JS, phony=True) +@target('test', phony=True) def test(t): t.run('node', 'tasks/test.js') diff --git a/test/index.html b/test/index.html index ae9d85feaa..e8400cbaef 100644 --- a/test/index.html +++ b/test/index.html @@ -13,6 +13,7 @@ + - From 4cf838382041a13d04414042699415d20518ab19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Lemoine?= Date: Wed, 9 Jul 2014 16:33:45 +0200 Subject: [PATCH 14/19] Avoid a type-cast --- src/ol/proj/proj.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/ol/proj/proj.js b/src/ol/proj/proj.js index 62b3c585ec..cf43b5d9c2 100644 --- a/src/ol/proj/proj.js +++ b/src/ol/proj/proj.js @@ -414,7 +414,13 @@ ol.proj.addCoordinateTransforms = * @return {ol.TransformFunction} Transform function. */ ol.proj.createTransformFromCoordinateTransform = function(transform) { - return /** @type {ol.TransformFunction} */ ( + return ( + /** + * @param {Array.} input Input. + * @param {Array.=} opt_output Output. + * @param {number=} opt_dimension Dimension. + * @return {Array.} Output. + */ function(input, opt_output, opt_dimension) { var length = input.length; var dimension = goog.isDef(opt_dimension) ? opt_dimension : 2; @@ -429,8 +435,7 @@ ol.proj.createTransformFromCoordinateTransform = function(transform) { } } return output; - } - ); + }); }; From 8f1fdde26efa3d70c5a15a4c7c5ae6ea5935dc7e Mon Sep 17 00:00:00 2001 From: Andreas Hocevar Date: Wed, 9 Jul 2014 17:38:16 +0200 Subject: [PATCH 15/19] Show both Proj4js and custom transform functions in examples --- examples/wms-custom-proj.html | 159 +++++++++++++++++++++++++++- examples/wms-custom-proj.js | 31 ++++-- examples/wms-image-custom-proj.html | 4 +- examples/wms-image-custom-proj.js | 2 +- 4 files changed, 177 insertions(+), 19 deletions(-) diff --git a/examples/wms-custom-proj.html b/examples/wms-custom-proj.html index 6f5c66e51e..efecf3a827 100644 --- a/examples/wms-custom-proj.html +++ b/examples/wms-custom-proj.html @@ -8,7 +8,7 @@ - Tiled WMS with Proj4js projection example + Tiled WMS with custom projection example @@ -31,21 +31,170 @@
-

Tiled WMS with Proj4js projection example

+

Tiled WMS with custom projection example

Example of two tiled WMS layers (Pixelmap 1:1'000'000 and national parks) using the projection EPSG:21781.

See the wms-custom-proj.js source to see how this is done.

-
wms, tile, tilelayer, proj4js, projection
+
wms, tile, tilelayer, projection
+ + - - diff --git a/examples/wms-custom-proj.js b/examples/wms-custom-proj.js index 087be33acb..930df1a29b 100644 --- a/examples/wms-custom-proj.js +++ b/examples/wms-custom-proj.js @@ -5,24 +5,33 @@ goog.require('ol.control'); goog.require('ol.control.ScaleLine'); goog.require('ol.layer.Tile'); goog.require('ol.proj'); +goog.require('ol.proj.Projection'); goog.require('ol.source.TileWMS'); -// EPSG:21781 is known to Proj4js because its definition was loaded in the html. -var projection = ol.proj.addProjection({ +var projection = new ol.proj.Projection({ code: 'EPSG:21781', // The extent is used to determine zoom level 0. Recommended values for a // projection's validity extent can be found at http://epsg.io/. extent: [485869.5728, 76443.1884, 837076.5648, 299941.7864], - // Use data from proj4js to configure the projection's units. - units: proj4.defs('EPSG:21781').units + units: 'm' }); -// Proj4js provides transform functions between its configured projections. -// The transform is needed for the ScaleLine control. Otherwise this example -// would also work without transform functions. -var transform = proj4('EPSG:21781'); -ol.proj.addCoordinateTransforms('EPSG:4326', projection, transform.forward, - transform.inverse); +ol.proj.addProjection(projection); +// WGStoCHx, WGStoCHy, CHtoWGSlng and CHtoWGSlat are defined in a script block +// in the html. +ol.proj.addCoordinateTransforms('EPSG:4326', projection, + function(coordinate) { + return [ + WGStoCHy(coordinate[1], coordinate[0]), + WGStoCHx(coordinate[1], coordinate[0]) + ]; + }, + function(coordinate) { + return [ + CHtoWGSlng(coordinate[0], coordinate[1]), + CHtoWGSlat(coordinate[0], coordinate[1]) + ]; + }); var extent = [420000, 30000, 900000, 350000]; var layers = [ @@ -72,7 +81,7 @@ var map = new ol.Map({ target: 'map', view: new ol.View({ projection: projection, - center: [660000, 190000], + center: ol.proj.transform([8.23, 46.86], 'EPSG:4326', 'EPSG:21781'), extent: extent, zoom: 2 }) diff --git a/examples/wms-image-custom-proj.html b/examples/wms-image-custom-proj.html index 73be411eac..bbdd94039e 100644 --- a/examples/wms-image-custom-proj.html +++ b/examples/wms-image-custom-proj.html @@ -8,7 +8,7 @@ - Single image WMS with custom projection example + Single image WMS with Proj4js projection example @@ -31,7 +31,7 @@
-

Single image WMS with custom projection example

+

Single image WMS with Proj4js projection example

Example of two single image WMS layers.

Pixelmap 1:1'000'000 with National Parks overlay using the projection EPSG:21781.

diff --git a/examples/wms-image-custom-proj.js b/examples/wms-image-custom-proj.js index d57bc93675..05292d72ae 100644 --- a/examples/wms-image-custom-proj.js +++ b/examples/wms-image-custom-proj.js @@ -63,7 +63,7 @@ var map = new ol.Map({ target: 'map', view: new ol.View({ projection: projection, - center: [660000, 190000], + center: ol.proj.transform([8.23, 46.86], 'EPSG:4326', 'EPSG:21781'), extent: extent, zoom: 2 }) From 1bb5705b55c0a82744ff5aead186bfe755c1b27f Mon Sep 17 00:00:00 2001 From: Andreas Hocevar Date: Wed, 9 Jul 2014 18:11:22 +0200 Subject: [PATCH 16/19] Clean up after testing --- test/spec/ol/proj/proj.test.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/test/spec/ol/proj/proj.test.js b/test/spec/ol/proj/proj.test.js index 32ce4449c9..07efbcca59 100644 --- a/test/spec/ol/proj/proj.test.js +++ b/test/spec/ol/proj/proj.test.js @@ -136,15 +136,22 @@ describe('ol.proj', function() { 'EPSG:4326', 'EPSG:21781'); expect(point[0]).to.roughlyEqual(600072.300, 1); expect(point[1]).to.roughlyEqual(200146.976, 1); + delete proj4.defs['EPSG:21781']; }); it('caches the new Proj4js projections given their srsCode', function() { + proj4.defs('EPSG:21781', + '+proj=somerc +lat_0=46.95240555555556 +lon_0=7.439583333333333 ' + + '+k_0=1 +x_0=600000 +y_0=200000 +ellps=bessel ' + + '+towgs84=674.374,15.056,405.346,0,0,0,0 +units=m +no_defs'); var code = 'urn:ogc:def:crs:EPSG:21781'; var srsCode = 'EPSG:21781'; proj4.defs(code, proj4.defs(srsCode)); var proj = ol.proj.get(code); var proj2 = ol.proj.get(srsCode); expect(ol.proj.equivalent(proj2, proj)).to.be(true); + delete proj4.defs[code]; + delete proj4.defs[srsCode]; }); it('numerically estimates point scale at the equator', function() { @@ -318,6 +325,10 @@ describe('ol.proj', function() { '+ellps=clrk66 +datum=NAD27 +to_meter=0.3048006096012192 +no_defs'); }); + afterEach(function() { + delete proj4.defs['EPSG:26782']; + }); + it('returns value in meters', function() { var epsg4326 = ol.proj.get('EPSG:4326'); expect(epsg4326.getMetersPerUnit()).to.eql(111194.87428468118); From 1ae82b054c8b14e85eddd9ba4e77f13138519276 Mon Sep 17 00:00:00 2001 From: Andreas Hocevar Date: Wed, 9 Jul 2014 18:12:07 +0200 Subject: [PATCH 17/19] Revert to only accept ol.proj.Projection as argument --- src/ol/proj/proj.js | 30 ++++++++---------------------- 1 file changed, 8 insertions(+), 22 deletions(-) diff --git a/src/ol/proj/proj.js b/src/ol/proj/proj.js index cf43b5d9c2..bbf004ad04 100644 --- a/src/ol/proj/proj.js +++ b/src/ol/proj/proj.js @@ -258,21 +258,18 @@ ol.proj.transforms_ = {}; * Registers transformation functions that don't alter coordinates. Those allow * to transform between projections with equal meaning. * - * @param {Array.} projections - * Projections. - * @return {Array.} The added equivalent projections. + * @param {Array.} projections Projections. * @api */ ol.proj.addEquivalentProjections = function(projections) { - var addedProjections = ol.proj.addProjections(projections); - goog.array.forEach(addedProjections, function(source) { - goog.array.forEach(addedProjections, function(destination) { + ol.proj.addProjections(projections); + goog.array.forEach(projections, function(source) { + goog.array.forEach(projections, function(destination) { if (source !== destination) { ol.proj.addTransform(source, destination, ol.proj.cloneTransform); } }); }); - return addedProjections; }; @@ -303,34 +300,23 @@ ol.proj.addEquivalentTransforms = /** * Add a Projection object to the list of supported projections. * - * @param {ol.proj.Projection|olx.ProjectionOptions} projection Projection - * instance or configuration. - * @return {ol.proj.Projection} The added projection. + * @param {ol.proj.Projection} projection Projection instance. * @api */ ol.proj.addProjection = function(projection) { - var projections = ol.proj.projections_; - var proj = projection instanceof ol.proj.Projection ? - projection : - new ol.proj.Projection(/** @type {olx.ProjectionOptions} */ (projection)); - var code = proj.getCode(); - projections[code] = proj; - ol.proj.addTransform(proj, proj, ol.proj.cloneTransform); - return proj; + ol.proj.projections_[projection.getCode()] = projection; + ol.proj.addTransform(projection, projection, ol.proj.cloneTransform); }; /** - * @param {Array.} projections - * Projections. - * @return {Array.} The added projections. + * @param {Array.} projections Projections. */ ol.proj.addProjections = function(projections) { var addedProjections = []; goog.array.forEach(projections, function(projection) { addedProjections.push(ol.proj.addProjection(projection)); }); - return addedProjections; }; From 193adf4401acdd395e180f4e3d8fddcadffd77e2 Mon Sep 17 00:00:00 2001 From: Andreas Hocevar Date: Wed, 9 Jul 2014 21:24:42 +0200 Subject: [PATCH 18/19] Move Swiss transform functions to the .js file --- examples/wms-custom-proj.html | 152 --------------------------------- examples/wms-custom-proj.js | 155 +++++++++++++++++++++++++++++++++- 2 files changed, 153 insertions(+), 154 deletions(-) diff --git a/examples/wms-custom-proj.html b/examples/wms-custom-proj.html index efecf3a827..45fe8f8fec 100644 --- a/examples/wms-custom-proj.html +++ b/examples/wms-custom-proj.html @@ -42,158 +42,6 @@
- - diff --git a/examples/wms-custom-proj.js b/examples/wms-custom-proj.js index 930df1a29b..1956f3426e 100644 --- a/examples/wms-custom-proj.js +++ b/examples/wms-custom-proj.js @@ -9,6 +9,7 @@ goog.require('ol.proj.Projection'); goog.require('ol.source.TileWMS'); + var projection = new ol.proj.Projection({ code: 'EPSG:21781', // The extent is used to determine zoom level 0. Recommended values for a @@ -17,8 +18,6 @@ var projection = new ol.proj.Projection({ units: 'm' }); ol.proj.addProjection(projection); -// WGStoCHx, WGStoCHy, CHtoWGSlng and CHtoWGSlat are defined in a script block -// in the html. ol.proj.addCoordinateTransforms('EPSG:4326', projection, function(coordinate) { return [ @@ -86,3 +85,155 @@ var map = new ol.Map({ zoom: 2 }) }); + + + +/* + * Swiss projection transform functions downloaded from + * http://www.swisstopo.admin.ch/internet/swisstopo/en/home/products/software/products/skripts.html + */ + +// Convert WGS lat/long (° dec) to CH y +function WGStoCHy(lat, lng) { + + // Converts degrees dec to sex + lat = DECtoSEX(lat); + lng = DECtoSEX(lng); + + // Converts degrees to seconds (sex) + lat = DEGtoSEC(lat); + lng = DEGtoSEC(lng); + + // Axiliary values (% Bern) + var lat_aux = (lat - 169028.66) / 10000; + var lng_aux = (lng - 26782.5) / 10000; + + // Process Y + var y = 600072.37 + + 211455.93 * lng_aux - + 10938.51 * lng_aux * lat_aux - + 0.36 * lng_aux * Math.pow(lat_aux, 2) - + 44.54 * Math.pow(lng_aux, 3); + + return y; +} + +// Convert WGS lat/long (° dec) to CH x +function WGStoCHx(lat, lng) { + + // Converts degrees dec to sex + lat = DECtoSEX(lat); + lng = DECtoSEX(lng); + + // Converts degrees to seconds (sex) + lat = DEGtoSEC(lat); + lng = DEGtoSEC(lng); + + // Axiliary values (% Bern) + var lat_aux = (lat - 169028.66) / 10000; + var lng_aux = (lng - 26782.5) / 10000; + + // Process X + var x = 200147.07 + + 308807.95 * lat_aux + + 3745.25 * Math.pow(lng_aux, 2) + + 76.63 * Math.pow(lat_aux, 2) - + 194.56 * Math.pow(lng_aux, 2) * lat_aux + + 119.79 * Math.pow(lat_aux, 3); + + return x; + +} + + +// Convert CH y/x to WGS lat +function CHtoWGSlat(y, x) { + + // Converts militar to civil and to unit = 1000km + // Axiliary values (% Bern) + var y_aux = (y - 600000) / 1000000; + var x_aux = (x - 200000) / 1000000; + + // Process lat + var lat = 16.9023892 + + 3.238272 * x_aux - + 0.270978 * Math.pow(y_aux, 2) - + 0.002528 * Math.pow(x_aux, 2) - + 0.0447 * Math.pow(y_aux, 2) * x_aux - + 0.0140 * Math.pow(x_aux, 3); + + // Unit 10000" to 1 " and converts seconds to degrees (dec) + lat = lat * 100 / 36; + + return lat; + +} + +// Convert CH y/x to WGS long +function CHtoWGSlng(y, x) { + + // Converts militar to civil and to unit = 1000km + // Axiliary values (% Bern) + var y_aux = (y - 600000) / 1000000; + var x_aux = (x - 200000) / 1000000; + + // Process long + var lng = 2.6779094 + + 4.728982 * y_aux + + 0.791484 * y_aux * x_aux + + 0.1306 * y_aux * Math.pow(x_aux, 2) - + 0.0436 * Math.pow(y_aux, 3); + + // Unit 10000" to 1 " and converts seconds to degrees (dec) + lng = lng * 100 / 36; + + return lng; + +} + + +// Convert SEX DMS angle to DEC +function SEXtoDEC(angle) { + + // Extract DMS + var deg = parseInt(angle, 10); + var min = parseInt((angle - deg) * 100, 10); + var sec = (((angle - deg) * 100) - min) * 100; + + // Result in degrees sex (dd.mmss) + return deg + (sec / 60 + min) / 60; + +} + +// Convert DEC angle to SEX DMS +function DECtoSEX(angle) { + + // Extract DMS + var deg = parseInt(angle, 10); + var min = parseInt((angle - deg) * 60, 10); + var sec = (((angle - deg) * 60) - min) * 60; + + // Result in degrees sex (dd.mmss) + return deg + min / 100 + sec / 10000; + +} + +// Convert Degrees angle to seconds +function DEGtoSEC(angle) { + + // Extract DMS + var deg = parseInt(angle, 10); + var min = parseInt((angle - deg) * 100, 10); + var sec = (((angle - deg) * 100) - min) * 100; + + // Avoid rounding problems with seconds=0 + var parts = String(angle).split('.'); + if (parts.length == 2 && parts[1].length == 2) { + min = Number(parts[1]); + sec = 0; + } + + // Result in degrees sex (dd.mmss) + return sec + min * 60 + deg * 3600; + +} From 7789bff3dafba227228083a950125db3d5ef03d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Lemoine?= Date: Thu, 10 Jul 2014 11:43:55 +0200 Subject: [PATCH 19/19] Add explanations to wms-custom-proj example --- examples/wms-custom-proj.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/examples/wms-custom-proj.js b/examples/wms-custom-proj.js index 1956f3426e..e3b5f2920b 100644 --- a/examples/wms-custom-proj.js +++ b/examples/wms-custom-proj.js @@ -10,6 +10,10 @@ goog.require('ol.source.TileWMS'); +// By default OpenLayers does not know about the EPSG:21781 (Swiss) projection. +// So we create a projection instance for EPSG:21781 and pass it to +// ol.proj.addProjection to make it available to the library. + var projection = new ol.proj.Projection({ code: 'EPSG:21781', // The extent is used to determine zoom level 0. Recommended values for a @@ -18,6 +22,11 @@ var projection = new ol.proj.Projection({ units: 'm' }); ol.proj.addProjection(projection); + +// We also declare EPSG:21781/EPSG:4326 transform functions. These functions +// are necessary for the ScaleLine control and when calling ol.proj.transform +// for setting the view's initial center (see below). + ol.proj.addCoordinateTransforms('EPSG:4326', projection, function(coordinate) { return [