A simple helper utility for re-projecting geojson data with Proj4. Includes type definitions for typescript.
Add it to your project with:
npm i reproj-helper
This utility acts as a simple wrapper around the Proj4 library, allowing you to pass in valid GeoJSON FeatureCollection
, Feature
, GeometryCollection
, and individual Geometry
types. All underlying coordinates will be projected to the supplied projection via Proj4.
It's also been extended to include some spatial utility functions and format conversions.
The ReProjector class is pre-initialized with several additional projections (that I commonly wind up using at work!),including:
- Proj4 Defaults (obviously)
- BC Albers
- UTM Zones 7 through 15
- Pseudo Mercator (EPSG:3857)
- Canada Atlas Lambert
- Yukon Albers
- Alberta 10-TM Forest
The ReProjector sets the default From
projection to BC Albers, and the default To
projection to WGS84.
You can add definitions manually by calling addDefinition('Code', 'A definition string')
with the code you want to use, and an appropriate definition string.
You can also call addDefinitionFromEpsgIo('Code')
which will attempt to find the supplied epsg code on epsg.io and load it for you.
Yes, the project()
function is asynchronous, just in case you're dealing with large features and want to do other things while it grinds away. It will return a Promise<Feature|Geometry|Null>. Null will be returned if projection fails (an error is also logged on the console).
Usage is very straightforward:
Create a ReProjector object. Set the Feature
to project, and if you don't want to use the defaults, set the From
projection via its code, and the to
projection via its code.
The projector will not alter the supplied feature. Instead, it clones the feature and will return you the modified clone.
const projector = new ReProjector()
// Method one
projector.feature({...some feature...})
projector.from('EPSG:CODE')
projector.to('EPSG:CODE')
const projectedJson = await projector.project()
// Method two
const projectedJson = await projector.feature({...some feature...}).from('EPSG:CODE').to('EPSG:CODE').project()
// Method three
const projectedJson = await ReProjector.instance().feature({...some feature...}).from('EPSG:CODE').to('EPSG:CODE').project()
// Add a def
projector.addDefinition('Some Code', 'A definition string')
// Add a def by searching epsg.io
projector.addDefinitionFromEpsgIo('EPSG:2154')
Pretty simple! Use the static initializer if you're running a one-off projection, and instantiate an object if you'll be doing a bunch.
Note: You can also check if a definition exists already in proj4 by calling:
const projector = new ReProjector()
doesExists = projector.definitionIsRegistered('SomeCode')
// or
doesExist = ReProjector.instance().definitionIsRegistered('SomeCode')
That way you can avoid calling epsg.io unnecessarily.
Yeah, there's a few helper methods also included in the spatial-utils
static class
These include:
- Find your UTM zone by longitude
- Find your UTM letter code by latitude
- Convert Decimal Degrees to a DMS String
- Haversine distance
- Line length (in meters)
- Polygon Perimeter (in meters)
- Polygon Area (in meters squared)
- Coordinate precision reducer
- Destination point calculation
- Mid Point calculation
- Bearing calculation
- Spatial Transformations (See the
SpatialTransformers
class) - Basic converter for WKT (See the
FormatConverter
class)
There's a simple format converter for converting WKT to GeoJSON, or vice versa. Currently it does not support POLYHEDRALSURFACE Z
.
Note that TRIANGLE
will convert to a GeoJSON Polygon
, and TIN
will convert to a GeoJSON MultiPolygon
. When converting these back to WKT, you may have to manually set the type from POLYGON
or MULTIPOLYGON
back to TRIANGLE
and TIN
respectively, or, when calling the .toWkt()
function, pass in a value of true
: .toWkt(true)
to tell the converter to use zCoordConversion
. This will convert POLYGONS to TRIANGLES if the value is true, and the polygon has a z coordinate.
Converting other formats is also planned for a future update.
Similar to the ReProjector
described above:
const converter = new FormatConverter()
const sourceWkt = 'POINT (0 0)'
const json = converter.fromWkt(sourceWkt).toGeoJson()
// Or, the other way around
const sourceJson = {
type: 'Point',
coordinates: [0, 0]
}
const wkt = converter.fromGeoJson(sourceWkt).toWkt()
You can supply FeatureCollection
, GeometryCollection
, Feature
or Geometry
. FeatureCollections will convert to a WKT GEOMETRYCOLLECTION
. Converting to GeoJSON will result in Feature
objects being returned. Converting WKT GEOMETRYCOLLECTION
will result in a Feature
GeoJSON, with a geometry type of GeometryCollection
There's an addition to the spatial utils class called SpatialTransformers
. This utility class contains functions that generate new features or modified versions of features from supplied input geometry. These functions include
- Find and/or Remove interior rings from a polygon
- Bounding Box of Features and FeatureCollections
- Create a centroid for a feature
- Reduce precision for a feature
- Explode features (extract all vertices)
- Convex Hull creator
- Circle creator
Should be pretty familiar by now. This is a static class, so no need to instantiate:
const sourceWkt = 'POLYGON ((35 10, 45 45, 15 40, 10 20, 35 10), (20 30, 35 35, 30 20, 20 30))'
const json = converter.fromWkt(sourceWkt).toGeoJson() as Feature
const interiorRings = SpatialTransformers.findInteriorRings(json)
const modifiedFeature = SpatialTransformers.removeInteriorRings(json)
const bbox = SpatialTransformers.boundingBox(json)
// etc. etc. etc.
New in 1.3.0 is an additional package called SpatialValidation that includes a number of functions for spatial boolean tests. These include
- doesIntersect
- isDisjoint
- doesContain
- isWithin
- doesOverlap
- doesTouch
- pointInPolygon
- PointOnLine
- pointEquals
- lineEquals
- polygonEquals
- lineTopogrphicallyEquals
- polygonTopographicallyEquals
SpatialValidator.doesIntersect(geom1, geom2)
SpatialValidator.polygonTopographicallyEquals(geom1, geom2)
For more info on proj4js, click that link. To find projection definitions, check out epsg.io