JavaScript library to transform coordinates from one coordinate system to another, including datum transformations

Overview

PROJ4JS Build Status

Proj4js is a JavaScript library to transform point coordinates from one coordinate system to another, including datum transformations. Originally a port of PROJ (then known as PROJ.4) and GCTCP C (Archive) it is a part of the MetaCRS group of projects.

Installing

Depending on your preferences

npm install proj4
bower install proj4
component install proj4js/proj4js

or just manually grab the file proj4.js from the latest release's dist/ folder.

If you do not want to download anything, Proj4js is also hosted on cdnjs for direct use in your browser applications.

Using

The basic signature is:

proj4(fromProjection[, toProjection, coordinates])

Projections can be proj or wkt strings.

Coordinates may an object of the form {x:x,y:y} or an array of the form [x,y].

When all 3 arguments are given, the result is that the coordinates are transformed from projection1 to projection 2. And returned in the same format that they were given in.

var firstProjection = 'PROJCS["NAD83 / Massachusetts Mainland",GEOGCS["NAD83",DATUM["North_American_Datum_1983",SPHEROID["GRS 1980",6378137,298.257222101,AUTHORITY["EPSG","7019"]],AUTHORITY["EPSG","6269"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.01745329251994328,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4269"]],UNIT["metre",1,AUTHORITY["EPSG","9001"]],PROJECTION["Lambert_Conformal_Conic_2SP"],PARAMETER["standard_parallel_1",42.68333333333333],PARAMETER["standard_parallel_2",41.71666666666667],PARAMETER["latitude_of_origin",41],PARAMETER["central_meridian",-71.5],PARAMETER["false_easting",200000],PARAMETER["false_northing",750000],AUTHORITY["EPSG","26986"],AXIS["X",EAST],AXIS["Y",NORTH]]';
var secondProjection = "+proj=gnom +lat_0=90 +lon_0=0 +x_0=6300000 +y_0=6300000 +ellps=WGS84 +datum=WGS84 +units=m +no_defs";
//I'm not going to redefine those two in latter examples.
proj4(firstProjection,secondProjection,[2,5]);
// [-2690666.2977344505, 3662659.885459918]

If only 1 projection is given then it is assumed that it is being projected from WGS84 (fromProjection is WGS84).

proj4(firstProjection,[-71,41]);
// [242075.00535055372, 750123.32090043]

If no coordinates are given an object with two methods is returned, its methods are forward which projects from the first projection to the second and inverse which projects from the second to the first.

proj4(firstProjection,secondProjection).forward([2,5]);
// [-2690666.2977344505, 3662659.885459918]
proj4(secondProjection,firstProjection).inverse([2,5]);
// [-2690666.2977344505, 3662659.885459918]

And as above if only one projection is given, it's assumed to be coming from wgs84:

proj4(firstProjection).forward([-71,41]);
// [242075.00535055372, 750123.32090043]
proj4(firstProjection).inverse([242075.00535055372, 750123.32090043]);
//[-71, 40.99999999999986]
//the floating points to answer your question

Named Projections

If you prefer to define a projection as a string and reference it that way, you may use the proj4.defs method which can be called 2 ways, with a name and projection:

proj4.defs('WGS84', "+title=WGS 84 (long/lat) +proj=longlat +ellps=WGS84 +datum=WGS84 +units=degrees");

or with an array

proj4.defs([
  [
    'EPSG:4326',
    '+title=WGS 84 (long/lat) +proj=longlat +ellps=WGS84 +datum=WGS84 +units=degrees'],
  [
    'EPSG:4269',
    '+title=NAD83 (long/lat) +proj=longlat +a=6378137.0 +b=6356752.31414036 +ellps=GRS80 +datum=NAD83 +units=degrees'
  ]
]);

you can then do

proj4('EPSG:4326');

instead of writing out the whole proj definition, by default proj4 has the following projections predefined:

  • 'EPSG:4326', which has the following alias
    • 'WGS84'
  • 'EPSG:4269'
  • 'EPSG:3857', which has the following aliases
    • 'EPSG:3785'
    • 'GOOGLE'
    • 'EPSG:900913'
    • 'EPSG:102113'

Defined projections can also be accessed through the proj4.defs function (proj4.defs('EPSG:4326')).

proj4.defs can also be used to define a named alias:

proj4.defs('urn:x-ogc:def:crs:EPSG:4326', proj4.defs('EPSG:4326'));

Grid Based Datum Adjustments

To use +nadgrids= in a proj definition, first read your NTv2 .gsb file (e.g. from https://github.com/OSGeo/proj-datumgrid) into an ArrayBuffer, then pass it to proj4.nadgrid. E.g:

const buffer = fs.readFileSync('ntv2.gsb').buffer
proj4.nadgrid('key', buffer);

then use the given key in your definition, e.g. +nadgrids=@key,null. See Grid Based Datum Adjustments.

TypeScript

TypeScript implementation was added to the DefinitelyTyped repository.

$ npm install --save @types/proj4

Developing

To set up build tools make sure you have node and grunt-cli installed and then run npm install.

To do the complete build and browser tests run:

node_modules/.bin/grunt

To run node tests run:

npm test

To run node tests with coverage run:

npm test --coverage

To create a build with only default projections (latlon and Mercator) run:

node_modules/.bin/grunt build

To create a build with only custom projections include a comma separated list of projections codes (the file name in 'lib/projections' without the '.js') after a colon, e.g.:

node_modules/.bin/grunt build:tmerc
#includes transverse Mercator
node_modules/.bin/grunt build:lcc
#includes lambert conformal conic
node_modules/.bin/grunt build:omerc,moll
#includes oblique Mercator and Mollweide
Comments
  • browserify

    browserify

    I take back more or less everything I said about paths in #48 @sheppard was write especially when it comes to browserify compatibility and speaking of which it turns out that building with browserify instead of with requirejs is like 1000% simpler. What do people think of this? we could even go one farther and just strait up use browserify.

    opened by calvinmetcalf 48
  • Fix tmerc / utm projection calculations

    Fix tmerc / utm projection calculations

    Reason of doing this is because calculation results for proj4js and cs2cs differed by a large margin and it meant that there is an issue in the tmerc projection calculations.

    More details here https://github.com/proj4js/proj4js/issues/187

    Hugely inspired by mapshaper-proj and how tmerc projection is calculated there https://github.com/mbloch/mapshaper-proj/blob/master/src/projections/tmerc.js

    • Added common function to adjust zone, called adjust_zone
    • Fixed tmerc / utm projection calculations that were not accurate enough
    • Adjusted test data for the more precise calculations
    opened by theashyster 22
  • An included Typescript definitions file

    An included Typescript definitions file

    As stated in Typescript documentation [1], it's favourable to have the definitions file alongside the source.

    As far I know, definition files on Definitely Typed aren't versioned and it's easy to end up using a version of an NPM package that doesn't match its definitions on DT -- I've been there :)

    The file here is based on the work done by @DenisCarriere and I'd be glad to hear your opinion on such a setup.

    [1] http://www.typescriptlang.org/docs/handbook/declaration-files/publishing.html

    opened by pierremarc 18
  • Projection in feet returned in metres

    Projection in feet returned in metres

    If I perform a projection where the source is in metres, and the target is in 'us-ft' the result appears to be returned in metres. Is this expected behaviour and I need to convert back to feet manually, or is there something I am missing in my call?

    proj4(proj4.defs['EPSG:3857'], proj4.defs('EPSG:3735')).forward([pnt.x, pnt.y]);
    
    opened by tr3vorm 17
  • Instability for UTM projection

    Instability for UTM projection

    When repeatedly projecting and unprojecting a coordinate in UTM projection, proj4 seems to be surprisingly unstable on northern latitudes, about an order of magnitude more unstable than cs2cs.

    I've run the following test program:

    var proj4 = require('proj4'),
        proj = proj4(proj4.WGS84, process.argv[2]),
        ll = [31, 70],
        p0 = proj.forward(ll);
    
    for (var i = 0; i < 10; i++) {
        p = proj.forward(ll);
        ll = proj.inverse(p);
    }
    
    var dx = p[0] - p0[0],
        dy = p[1] - p0[1];
    
    console.log(Math.sqrt(dx*dx + dy*dy));
    

    Running this with EPSG:32633 (+proj=utm +zone=33 +datum=WGS84 +units=m +no_defs), results in a difference of 364 meters.

    Doing the same thing with cs2cs (https://gist.github.com/perliedman/44ea458607fba4f121314628c9cee978) gives a difference of 23 meters.

    Is this difference expected? It causes trouble for some Leaflet users (https://github.com/Leaflet/Leaflet/issues/4480), since Leaflet internally will sometimes need to project and unproject the same coordinate.

    opened by perliedman 15
  • Increase accuracy with omerc projection

    Increase accuracy with omerc projection

    NOTE:

    This implementation is based off of the mapshaper-proj implementation of omerc, which is based directly off of the proj4 implementation of omerc. I attempted to match the structure of proj4js as best as possible.

    Also, one test I added is failing. The test data I have added is coming from proj4, so it should be correct. It could indicate that there is more work to be done for this implementation.

    This issue is mentioned in #308 , #313 , #301 , #273 , #308 , #173, and #146.

    Problem:

    The omerc projection is returning inaccurate values. As mentioned in #308, it appears as though the implementation is ignoring the +gamma value. Additionally, whenever the alpha values are +/-90, the transformed coordinates were inaccurate.

    Solution:

    I had found this implementation of omerc that appeared to be producing more accurate results than the proj4js implementation of omerc. There are several things in the mapshaper-proj implementation that are dependant on that library's infrastructure, so I tried to work around that as best as possible.

    I would love to get a second set of eyes on this code to verify that this fix is actually helping.

    There is currently a failing test that I have added. 12 tests are failing with this implementation, 32 are failing with the previous one.

    I'll continue to investigate why this test is failing, and update this PR as soon as I figure it out.

    Thanks!

    opened by dulldrums 14
  • Only latitude, not longitude coordinates converted on some datum transformations

    Only latitude, not longitude coordinates converted on some datum transformations

    I have found that on some datum transformations, only the latitude coordinate (decimal degrees) is transformed, not the longitude one. For example, from WGS84 > NAD27, with input 43.8 (lat) and -98.7 (lon), I get 43.802139... and -98.7 I have compared this against other tools such as GeoTrans and it doesn't seem to be correct. Furthermore, I have tried with many different "from" datums, and they all just transform the latitude coordinate. I'd appreciate any help that anyone can offer.

    opened by roryslatter 14
  • Add etmerc projection to proj4js and use it for utm

    Add etmerc projection to proj4js and use it for utm

    Reason of doing this is because calculation results for proj4js and cs2cs 4.9.3 (that now uses etmerc) differs and it means that it can be improved using the etmerc projection. Suggestion by @mbloch on the original issue #187

    Hugely inspired by mapshaper-proj and how etmerc projection is calculated there https://github.com/mbloch/mapshaper-proj/blob/master/src/projections/etmerc.js

    Using etmerc gives UTM a really great precision and is a generally suggested change, proj.4 starting from version 4.9.3 has also switched for UTM to use etmerc.

    Here is the comparison sheet between proj4js with etmerc, mapshaper-proj using etmerc and proj.4 using etmerc (c library) https://docs.google.com/spreadsheets/d/1W6tqCLL54q1rSfXKQOHmqQ-7jxnptbXyDFlrVX3mkH4/edit?usp=sharing

    Ping @calvinmetcalf

    opened by theashyster 13
  • Adding support for nadgrids

    Adding support for nadgrids

    I've added basic support for nadgrids and NTv2 grid files. I'm a projection novice, so this relied heavily on the patch linked to in the original issue: https://github.com/proj4js/proj4js/issues/62. The patch showed me where to apply the grid shifts and provided the algorithm for looking up the correct shift, though I've tried to clean up the code a little, removed some parts I didn't see how they were contributing (though happy to be corrected on those parts) and made some changes where the logic wasn't right (and it broke the tests). On top of this I implemented a basic NTv2 file reader.

    Since there are many different ways a consumer of the API might want to load the binary NTv2 file, my implementation doesn't attempt to read in the binary, but expects the caller to provide a pre-loaded ArrayBuffer with the contents of their NTv2 file. My thinking is that trying to support all the ways that people will need to access the file would quickly get out of hand (e.g. in node, in the browser, fetch vs XMLHttpRequest, auth headers, etc, etc). So I've exposed a new function in the index: nadgrid(key, buffer) which will parse the ArrayBuffer and associate it with the given key. The user will then specify the key in the proj4 string, e.g. +nadgrids=@key,null.

    I originally tested this using the Ordnance Survey NTv2 file, which also provides a set of test points, which was great for building confidence in the implementation. However, there's no license specified with those files, so I've replaced those tests with some that are based on a downsampled ntv2 grid that I found in the OSGeo/proj repo. Again, trying to load a binary file across different browsers, node etc is a pain, so in the end I base64 encoded the file to make it easier to load into the tests. If anyone can think of a nicer way of doing this, I'm more than happy to change it.

    opened by geoffsmith 12
  • Wrong convertion results from WGS84 (4326) to ITM (2039)

    Wrong convertion results from WGS84 (4326) to ITM (2039)

    There is wrong results when I am converting from WGS84 (4326) to ITM (2039). EPSG:2039 definition is taken as is from epsg.io

    The input in ESPG:4326 is: Lat: 32.547015 Lon: 35.503194

    The result in EPSG:2039 is: X=247511.40 Y=717010.46

    But it should be X=247518.21 Y=717016.77

    opened by pavelbl18 12
  • Projection from/to the same CRS gives large Z difference since 2.3.16

    Projection from/to the same CRS gives large Z difference since 2.3.16

    Example using EPSG:7415 (Amersfoort RD New + NAP), tested in PhantomJS

    Head:

    const proj4 = require('./dist/proj4.js');
    proj4.defs('RD', '+proj=sterea +lat_0=52.15616055555555 +lon_0=5.38763888888889 +k=0.999908 +x_0=155000 +y_0=463000 +ellps=bessel +units=m +towgs84=565.2369,50.0087,465.658,-0.406857330322398,0.350732676542563,-1.8703473836068,4.0812 +no_defs');
    

    Using 2.3.16 or 2.3.17:

    proj4('RD', 'RD', [100000, 437000, 10]);
    // {
    //    "0": 100000.00006519399,
    //    "1": 437000.00057943614,
    //    "2": -43.74852570705116
    // }
    

    Must be a regression, because 2.3.15 gives these results:

    proj4('RD', 'RD', [100000, 437000, 10]);
    // {
    //    "0": 100000.00009487881,
    //    "1": 436999.9997790383,
    //    "2": 10.000132272019982
    // }
    

    Now, ideally proj4(a, a, b) should probably recognize that the "from" and "to" CRS are the same and just return b, but even without this check, I don't think such large changes in Z are acceptable. What's going on here?

    opened by bartvanandel 12
  • Custom CRS give the result different from original PROJ4 command line.

    Custom CRS give the result different from original PROJ4 command line.

    I 'm following up thisissue from Proj4Dart that derived from Proj4js. They provided me with some snipped code for testing in javascript as the following:

    var script = document.createElement("script");
    var scriptPath = "https://cdnjs.cloudflare.com/ajax/libs/proj4js/2.8.0/proj4.js";
    script.setAttribute("src", scriptPath);
    document.head.appendChild(script);
    
    script.onload = function() {
        proj4.defs('projSrc', '+proj=utm +zone=47 +datum=WGS84 +units=m +no_defs');
        proj4.defs('projDst', '+proj=tmerc +lat_0=0.0 +lon_0=102.25 +k_0=1.0 +x_0=500000 +y_0=0 +a=6378297.0 +b=6356911.77779 +towgs84=0.0,0.0,0.0,0,0,0,0 +units=m +no_defs type=crs');
        var result = proj4('projSrc', 'projDst').forward([834934.4417, 1657193.5292]);
        console.log(result);
    }
    

    Output: [485333.96880976285, 1655549.4642448917]

    Please note the Proj4 string of 'projDst' is a custom CRS of my country. I also tested this custom CRS with PROJ4 command line:

    $echo 834934.4417 1657193.5292 | cs2cs +proj=utm +zone=47 +datum=WGS84 +units=m +no_defs +to +proj=tmerc +lat_0=0.0 +lon_0=102.25 +k_0=1.0 +x_0=500000 +y_0=0 +a=6378297.0 +b=6356911.77779 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs -f "%.4f"
    

    Output: 485333.9690 1655549.7316 0.0000 So it is a big different about 27 cm. in Northing. Please check is it a bug of Proj4js?

    opened by pbrobo 0
  • Add a

    Add a "return" statement to this callback

    Hello, i use the proj4-src.js file in my project and i found some issue with 'defs' function.

    When i add the new project by 'proj4.defs("A1", "+proj=A1")' command, i getting the correct object when i run the 'proj4.defs("A1")' command. It's okey, but when i have two names of projects 'proj4.defs("A1") and ''proj4.defs("A2")', I use this 'proj4.defs(["A1","A2"])' to get the projects array  i will get next '[undefined, undefined]' data.

    I want to get this '[{projName: 'A1'}, {projName: 'A2'}]' data.

    And i found resolution to this problem. When i run this function with one agrument and this argument is array we return names map, but in the function in the map function you are not use return action.

    The next image shows how i fixed this problem: bandicam 2022-05-17 18-09-00-981

    Please consider this issue and fix in your project.

    opened by Oleksiy99 0
  • Using dynamic imports to create a slimmer core library

    Using dynamic imports to create a slimmer core library

    I was looking at some package size things recently and it struck me that proj4 might be a good candidate for using dynamic imports now that they are more widely supported.

    Rather than having to package all the projections bundled into the core package the majority could be loaded on demand only when requested by the user.

    I had a bit of a poke through the codebase and I think the main change would probably be introducing a promise-based entry point.

    I'm not sure how much this would reduce the bundle size by but I thought I'd float the idea and see if there was interest before doing any further explorations.

    opened by rowanwins 1
  • LCC names missing

    LCC names missing

    this two names are missing from lcc names. I have a probleme when I load a proj with project "Lambert Conic Conformal (2SP)" "Lambert Conic Conformal (1SP)", "Lambert Conic Conformal (2SP)",

    opened by romaintriboutsamsys 0
  • Support for PROJJSON

    Support for PROJJSON

    PROJ has introduced PROJJSON: https://proj.org/specifications/projjson.html STAC is also embracing PROJJSON for example, e.g. here: https://github.com/stac-extensions/projection/blob/main/README.md#projprojjson

    So for proj.defs, I think it would be nice to have PROJJSON support for the cases where WKT is not published in the metadata.

    PROJJSON says it's a simple encoding of WKT2, so I'm wondering whether WKT2 is supported here? Then it could be as simple as writing a simple JSON to WKT2 transformation that could take place.

    I may work on a PR if you think this would have a chance of getting accepted and WKT2 support is available here.

    opened by m-mohr 8
Releases(2.8.0)
An open-source JavaScript library for world-class 3D globes and maps :earth_americas:

CesiumJS is a JavaScript library for creating 3D globes and 2D maps in a web browser without a plugin. It uses WebGL for hardware-accelerated graphics

Cesium 9.7k Dec 26, 2022
Polymaps is a free JavaScript library for making dynamic, interactive maps in modern web browsers.

Polymaps Polymaps is a free JavaScript library for making dynamic, interactive maps in modern web browsers. See http://polymaps.org for more details.

Urban Airship 1.6k Dec 23, 2022
An open-source JavaScript library for world-class 3D globes and maps :earth_americas:

CesiumJS is a JavaScript library for creating 3D globes and 2D maps in a web browser without a plugin. It uses WebGL for hardware-accelerated graphics

Cesium 9.7k Jan 3, 2023
The NASA WorldWind Javascript SDK (WebWW) includes the library and examples for creating geo-browser web applications and for embedding a 3D globe in HTML5 web pages.

Web WorldWind New versions of WorldWind released Web WorldWind 0.10.0 and WorldWind Java 2.2.0 are now available on GitHub. The new version of Web Wor

NASA WorldWind 770 Jan 1, 2023
geotiff.js is a small library to parse TIFF files for visualization or analysis. It is written in pure JavaScript, and is usable in both the browser and node.js applications.

geotiff.js Read (geospatial) metadata and raw array data from a wide variety of different (Geo)TIFF files types. Features Currently available function

geotiff.js 649 Dec 21, 2022
The smallest, simplest and fastest JavaScript pixel-level image comparison library

pixelmatch The smallest, simplest and fastest JavaScript pixel-level image comparison library, originally created to compare screenshots in tests. Fea

Mapbox 5.1k Jan 8, 2023
jQuery Vector Map Library

This project is a heavily modified version of jVectorMap as it was in April of 2012. I chose to start fresh rather than fork their project as my inten

10 Best Design 1.8k Dec 28, 2022
jQuery Vector Map Library

This project is a heavily modified version of jVectorMap as it was in April of 2012. I chose to start fresh rather than fork their project as my inten

10 Best Design 1.8k Dec 28, 2022
A very fast geospatial point clustering library for browsers and Node.

supercluster A very fast JavaScript library for geospatial point clustering for browsers and Node. <script src="https://unpkg.com/[email protected]/d

Mapbox 1.6k Jan 7, 2023
A Node.js map tile library for PostGIS and torque.js, with CartoCSS styling

Windshaft A Node.js map tile library for PostGIS and torque.js, with CartoCSS styling. Can render arbitrary SQL queries Generates image and UTFGrid in

CARTO 306 Dec 22, 2022
AngularJS directive to embed an interact with maps managed by Leaflet library

Angular Leaflet Why the fork? While we are grateful for all the original work at tombatossals/angular-leaflet-directive. We need to be able to operate

AngularUI 313 Nov 10, 2022
Super Low-Level Raster Reprojection and Resampling Library

geowarp Super Low-Level Raster Reprojection and Resampling Library install npm install -S geowarp usage const geowarp = require("geowarp"); const proj

Daniel J. Dufour 27 Nov 9, 2022
A library that makes Image Map Area responsive

A library that makes Image Map Area responsive

elenh 1 Jan 21, 2022
Waypoints is a library that makes it easy to execute a function whenever you scroll to an element.

Waypoints Waypoints is a library that makes it easy to execute a function whenever you scroll to an element. var waypoint = new Waypoint({ element:

Caleb Troughton 10.3k Jan 4, 2023
UNMAINTAINED Open source JavaScript renderer for Kartograph SVG maps

This project is not maintained anymore. Here are a few reasons why I stopped working on kartograph.js: there's no need to support non-SVG browsers any

null 1.5k Dec 11, 2022
Mapbox JavaScript API, a Leaflet Plugin

mapbox.js A Mapbox plugin for Leaflet, a lightweight JavaScript library for traditional raster maps. For the state-of-the-art Mapbox vector maps libra

Mapbox 1.9k Dec 23, 2022
JavaScript WebGL 3D map rendering engine

VTS Browser JS is a powerful JavaScript 3D map rendering engine with a very small footprint (about 163 kB of gziped JS code). It provides almost all f

Melown Technologies, SE 203 Dec 7, 2022
Blazing Fast JavaScript Raster Processing Engine

Geoblaze A blazing fast javascript raster processing engine Geoblaze is a geospatial raster processing engine written purely in javascript. Powered by

GeoTIFF 125 Dec 20, 2022
JavaScript Topology Suite

JSTS JSTS is an ECMAScript library of spatial predicates and functions for processing geometry conforming to the Simple Features Specification for SQL

Björn Harrtell 1.3k Jan 4, 2023