Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions packages/turf-projection/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,20 @@ var addToMap = [pt, converted];

Returns **[GeoJSON][1]** Projected GeoJSON

## project

Projects GeoJSON or Position objects using an arbitrary projection function

### Parameters

* `geojson` **[GeoJSON][1]** GeoJSON or Position object
* `projection` **[string][5]** A function that implements the projection
* `options` **[Object][3]?** Optional parameters (optional, default `{}`)

* `options.mutate` **[boolean][4]** allows GeoJSON input to be mutated (significant performance increase if true) (optional, default `false`)

Returns **[GeoJSON][1]** Converted GeoJSON in the same shape as the original

[1]: https://tools.ietf.org/html/rfc7946#section-3

[2]: https://developer.mozilla.org/docs/Web/API/Position
Expand All @@ -56,6 +70,8 @@ Returns **[GeoJSON][1]** Projected GeoJSON

[4]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean

[5]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String

<!-- This file is automatically generated. Please don't edit it directly. If you find an error, edit the source file of the module in question (likely index.js or index.ts), and re-run "yarn docs" from the root of the turf project. -->

---
Expand Down
67 changes: 35 additions & 32 deletions packages/turf-projection/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Position } from "geojson";
import type { Position, GeoJSON } from "geojson";
import { coordEach } from "@turf/meta";
import { AllGeoJSON, isNumber } from "@turf/helpers";
import { type AllGeoJSON, isNumber } from "@turf/helpers";
import { clone } from "@turf/clone";

/**
Expand All @@ -22,7 +22,11 @@ function toMercator<G = AllGeoJSON | Position>(
geojson: G,
options: { mutate?: boolean } = {}
): G {
return convert(geojson, "mercator", options);
return project(
geojson as GeoJSON | Position,
convertToMercator,
options
) as G;
}

/**
Expand All @@ -44,47 +48,46 @@ function toWgs84<G = AllGeoJSON | Position>(
geojson: G,
options: { mutate?: boolean } = {}
): G {
return convert(geojson, "wgs84", options);
return project(
geojson as AllGeoJSON | Position,
convertToWgs84,
options
) as G;
}

/**
* Converts a GeoJSON coordinates to the defined `projection`
* Projects GeoJSON or Position objects using an arbitrary projection function
*
* @private
* @param {GeoJSON} geojson GeoJSON Feature or Geometry
* @param {string} projection defines the projection system to convert the coordinates to
* @param {GeoJSON} geojson GeoJSON or Position object
* @param {string} projection A function that implements the projection
* @param {Object} [options] Optional parameters
* @param {boolean} [options.mutate=false] allows GeoJSON input to be mutated (significant performance increase if true)
* @returns {GeoJSON} Converted GeoJSON
* @returns {GeoJSON} Converted GeoJSON in the same shape as the original
*/
function convert(
geojson: any,
projection: string,
function project<G extends GeoJSON | Position>(
geojson: G,
projection: (input: number[]) => number[],
options: { mutate?: boolean } = {}
): any {
// Optional parameters
options = options || {};
var mutate = options.mutate;
): G {
const mutate = options?.mutate ?? false;

// Validation
if (!geojson) throw new Error("geojson is required");
if (!geojson) {
throw new Error("geojson is required");
}

// Handle Position
if (Array.isArray(geojson) && isNumber(geojson[0]))
geojson =
projection === "mercator"
? convertToMercator(geojson)
: convertToWgs84(geojson);
// Handle GeoJSON
else {
if (Array.isArray(geojson) && isNumber(geojson[0])) {
// Handle Position
geojson = projection(geojson) as G;
} else {
// Handle GeoJSON
// Handle possible data mutation
if (mutate !== true) geojson = clone(geojson);
if (mutate !== true) {
geojson = clone(geojson as GeoJSON) as G;
}

coordEach(geojson, function (coord) {
var newCoord =
projection === "mercator"
? convertToMercator(coord)
: convertToWgs84(coord);
coordEach(geojson as GeoJSON, function (coord) {
var newCoord = projection(coord);
coord[0] = newCoord[0];
coord[1] = newCoord[1];
});
Expand Down Expand Up @@ -154,4 +157,4 @@ function sign(x: number) {
return x < 0 ? -1 : x > 0 ? 1 : 0;
}

export { toMercator, toWgs84 };
export { toMercator, toWgs84, project };
34 changes: 33 additions & 1 deletion packages/turf-projection/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ import { clone } from "@turf/clone";
import { point } from "@turf/helpers";
import { truncate } from "@turf/truncate";
import { coordEach } from "@turf/meta";
import { toMercator, toWgs84 } from "./index.js";
import { toMercator, toWgs84, project } from "./index.js";
import { FeatureCollection, Point } from "geojson";

const __dirname = path.dirname(fileURLToPath(import.meta.url));

Expand Down Expand Up @@ -129,3 +130,34 @@ test("projection -- handle Position", (t) => {
t.deepEqual(coord, wgs84, "coord equal same as wgs84");
t.end();
});

test("projection - proj4 usage", (t) => {
const input: FeatureCollection<Point> = {
type: "FeatureCollection",
features: [
{
type: "Feature",
geometry: {
type: "Point",
coordinates: [0, 0],
},
properties: {},
},
],
};

// proj4 projection usage example
const projected = project(
input,
(input) => {
return proj4("WGS84", "EPSG:3857", input);
},
{ mutate: true }
);

t.deepEqual(
projected.features[0].geometry.coordinates,
[0, -7.081154551613622e-10]
);
t.end();
});
Loading