Browse Source

refactor: replace @turf/turf with vanilla TS implementation

pull/388/head
Dan Ditomaso 1 year ago
parent
commit
6d5d566ca8
  1. 1
      package.json
  2. 1698
      pnpm-lock.yaml
  3. 109
      src/core/utils/maps.ts
  4. 2
      src/pages/Map.tsx

1
package.json

@ -43,7 +43,6 @@
"@radix-ui/react-tabs": "^1.1.2",
"@radix-ui/react-toast": "^1.2.5",
"@radix-ui/react-tooltip": "^1.1.7",
"@turf/turf": "^7.2.0",
"base64-js": "^1.5.1",
"class-validator": "^0.14.1",
"class-variance-authority": "^0.7.1",

1698
pnpm-lock.yaml

File diff suppressed because it is too large

109
src/core/utils/maps.ts

@ -0,0 +1,109 @@
type Position = [number, number];
type BBox = [number, number, number, number];
interface GeoJSONGeometry {
type: string;
coordinates: Position | Position[] | Position[][] | Position[][][];
}
interface Feature<G extends GeoJSONGeometry> {
type: "Feature";
geometry: G;
properties: Record<string, unknown>;
}
interface LineStringGeometry {
type: "LineString";
coordinates: Position[];
}
function lineString(coordinates: Position[]): Feature<LineStringGeometry> {
if (!coordinates || coordinates.length < 2) {
throw new Error("coordinates must contain at least 2 positions");
}
for (const [index, coord] of coordinates.entries()) {
if (!Array.isArray(coord) || coord.length !== 2) {
throw new Error(`Invalid position at index ${index}`);
}
if (!coord.every((n) => typeof n === "number")) {
throw new Error(`Position must contain numbers at index ${index}`);
}
}
return {
type: "Feature",
properties: {},
geometry: {
type: "LineString",
coordinates,
},
};
}
function bbox(geojson: Feature<GeoJSONGeometry> | GeoJSONGeometry): BBox {
if (!geojson) {
throw new Error("geojson is required");
}
const coords = getAllCoordinates(geojson);
if (coords.length === 0) {
throw new Error("No coordinates found in geojson");
}
const [west, south, east, north] = coords.reduce(
([minX, minY, maxX, maxY], [x, y]) => [
Math.min(minX, x),
Math.min(minY, y),
Math.max(maxX, x),
Math.max(maxY, y),
],
[
Number.POSITIVE_INFINITY,
Number.POSITIVE_INFINITY,
Number.NEGATIVE_INFINITY,
Number.NEGATIVE_INFINITY,
],
);
return [west, south, east, north];
}
function getAllCoordinates(
geojson: Feature<GeoJSONGeometry> | GeoJSONGeometry,
): Position[] {
const geometry =
"type" in geojson && geojson.type === "Feature" && "geometry" in geojson
? geojson.geometry
: geojson;
const coords: Position[] = [];
switch (geometry.type) {
case "Point":
coords.push(geometry.coordinates as Position);
break;
case "LineString":
case "MultiPoint":
coords.push(...(geometry.coordinates as Position[]));
break;
case "Polygon":
case "MultiLineString":
for (const line of geometry.coordinates as Position[][]) {
coords.push(...line);
}
break;
case "MultiPolygon":
for (const poly of geometry.coordinates as Position[][][]) {
for (const line of poly) {
coords.push(...line);
}
}
break;
default:
throw new Error(`Unsupported geometry type: ${geometry.type}`);
}
return coords;
}
export { bbox, lineString }

2
src/pages/Map.tsx

@ -10,7 +10,7 @@ import { useAppStore } from "@core/stores/appStore.ts";
import { useDevice } from "@core/stores/deviceStore.ts";
import type { Protobuf } from "@meshtastic/js";
import { numberToHexUnpadded } from "@noble/curves/abstract/utils";
import { bbox, lineString } from "@turf/turf";
import { bbox, lineString } from "@core/utils/maps";
import {
BoxSelectIcon,
MapPinIcon,

Loading…
Cancel
Save