From 25c1c30e060e60256387555766a47515663c1230 Mon Sep 17 00:00:00 2001 From: Jonathan Beezley Date: Wed, 20 Apr 2016 10:17:32 -0400 Subject: [PATCH] Expose methods to define new proj4 definitions --- src/transform.js | 50 +++++++++++++++++++++++- tests/cases/transform.js | 83 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 131 insertions(+), 2 deletions(-) diff --git a/src/transform.js b/src/transform.js index 79f7f0f5aa..af2bf69c32 100644 --- a/src/transform.js +++ b/src/transform.js @@ -1,3 +1,5 @@ +var proj4 = require('proj4'); + ////////////////////////////////////////////////////////////////////////////// /** * This purpose of this class is to provide a generic interface for computing @@ -28,8 +30,6 @@ var transform = function (options) { return new transform(options); } - var proj4 = require('proj4'); - var m_this = this, m_proj, // The raw proj4js object m_source, // The source projection @@ -157,6 +157,52 @@ var transform = function (options) { return this; }; +/** + * Contains a reference to `proj4.defs`. The functions serves two + * purposes. + * + * 1. It is a key value mapping of all loaded projection definitions + * 2. It is a function that will add additional definitions. + * + * See: + * http://proj4js.org/ + */ +transform.defs = proj4.defs; + +/** + * Look up a projection definition from epsg.io + * For the moment, we only handle `EPSG` codes. + * + * @param {string} projection A projection alias (e.g. EPSG:4326) + * @returns {promise} Resolves with the proj4 definition + */ +transform.lookup = function (projection) { + var $ = require('jquery'); + var code, defer = new $.Deferred(), parts; + + if (proj4.defs.hasOwnProperty(projection)) { + return defer.resolve(proj4.defs[projection]); + } + + parts = projection.split(':'); + if (parts.length !== 2 || parts[0].toUpperCase() !== 'EPSG') { + return defer.reject('Invalid projection code').promise(); + } + code = parts[1]; + + return $.ajax({ + url: 'http://epsg.io/?q=' + code + '&format=json' + }).then(function (data) { + var result = (data.results || [])[0]; + if (!result || !result.proj4) { + return defer.reject(data).promise(); + } + + proj4.defs(projection, result.proj4); + return $.when(proj4.defs[projection]); + }); +}; + /** * Transform an array of coordinates from one projection into another. The * transformation may occur in place (modifying the input coordinate array), diff --git a/tests/cases/transform.js b/tests/cases/transform.js index 4460cc62d4..f66f6fb0fb 100644 --- a/tests/cases/transform.js +++ b/tests/cases/transform.js @@ -92,4 +92,87 @@ describe('geo.transform', function () { [{x: 1669792, y: -19971868}, {x: 1669792, y: -19971868}] ] ); + + describe('defs', function () { + var server; + + beforeEach(function () { + server = sinon.fakeServer.create(); + }); + + afterEach(function () { + server.restore(); + }); + + it('predefined definitions', function () { + expect(geo.transform.defs.hasOwnProperty('EPSG:4326')).toBe(true); + expect(geo.transform.defs.hasOwnProperty('EPSG:3857')).toBe(true); + }); + + it('custom definition', function () { + geo.transform.defs('my projection', '+proj=longlat +datum=WGS84 +no_defs'); + expect(geo.transform.defs.hasOwnProperty('my projection')).toBe(true); + var p = geo.transform({source: 'EPSG:4326', target: 'my projection'}); + + expect(p.forward({x: 10, y: -10, z: 0})).toEqual({x: 10, y: -10, z: 0}); + }); + + it('lookup', function () { + var spy = sinon.spy(), request; + geo.transform.lookup('EPSG:5000').then(spy); + + request = server.requests[0]; + expect(request.url).toMatch(/\?q=5000/); + request.respond(200, {'Content-Type': 'application/json'}, JSON.stringify({ + status: 'ok', + number_result: 1, + results: [{ + code: '5000', + kind: 'CRS-PROJCRS', + bbox: [ + 85.06, + 180.0, + 85.06, + 180.0 + ], + unit: 'degree', + proj4: '+proj=longlat +datum=WGS84 +no_defs', + name: 'WGS 84', + area: 'World', + default_trans: 0, + trans: [], + accuracy: '' + }] + })); + + expect(spy.calledOnce).toBe(true); + expect(geo.transform.defs.hasOwnProperty('EPSG:5000')).toBe(true); + + geo.transform.lookup('EPSG:5000'); + expect(server.requests.length).toBe(1); + }); + + it('invalid projection code', function () { + var spy = sinon.spy(), request; + geo.transform.lookup('EPSG:5001').fail(spy); + + request = server.requests[0]; + request.respond(200, {'Content-Type': 'application/json'}, JSON.stringify({ + status: 'ok', + number_result: 0, + results: [] + })); + + expect(spy.calledOnce).toBe(true); + expect(geo.transform.defs.hasOwnProperty('EPSG:5001')).toBe(false); + }); + + it('unknown projection type', function () { + var spy = sinon.spy(); + geo.transform.lookup('unknown:5002').fail(spy); + + expect(spy.calledOnce).toBe(true); + expect(geo.transform.defs.hasOwnProperty('unknown:5002')).toBe(false); + }); + }); });