Browse Source

refactor: replace @turf/turf with vanilla TS implementation

pull/382/head
Dan Ditomaso 1 year ago
parent
commit
22be476560
  1. 1
      package.json
  2. 1286
      pnpm-lock.yaml
  3. 109
      src/core/utils/maps.ts
  4. 4
      src/pages/Map.tsx

1
package.json

@ -40,7 +40,6 @@
"@radix-ui/react-tabs": "^1.1.0", "@radix-ui/react-tabs": "^1.1.0",
"@radix-ui/react-toast": "^1.2.1", "@radix-ui/react-toast": "^1.2.1",
"@radix-ui/react-tooltip": "^1.1.1", "@radix-ui/react-tooltip": "^1.1.1",
"@turf/turf": "^6.5.0",
"base64-js": "^1.5.1", "base64-js": "^1.5.1",
"class-transformer": "^0.5.1", "class-transformer": "^0.5.1",
"class-validator": "^0.14.1", "class-validator": "^0.14.1",

1286
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 }

4
src/pages/Map.tsx

@ -10,14 +10,14 @@ import { useDevice } from "@core/stores/deviceStore.ts";
import { Hashicon } from "@emeraldpay/hashicon-react"; import { Hashicon } from "@emeraldpay/hashicon-react";
import type { Protobuf } from "@meshtastic/js"; import type { Protobuf } from "@meshtastic/js";
import { numberToHexUnpadded } from "@noble/curves/abstract/utils"; import { numberToHexUnpadded } from "@noble/curves/abstract/utils";
import { bbox, lineString } from "@turf/turf"; import { bbox, lineString } from "@core/utils/maps";
import { import {
BoxSelectIcon, BoxSelectIcon,
MapPinIcon, MapPinIcon,
ZoomInIcon, ZoomInIcon,
ZoomOutIcon, ZoomOutIcon,
} from "lucide-react"; } from "lucide-react";
import { useCallback, useEffect, useState } from "react"; import { type JSX, useCallback, useEffect, useState } from "react";
import { AttributionControl, Marker, Popup, useMap } from "react-map-gl"; import { AttributionControl, Marker, Popup, useMap } from "react-map-gl";
import MapGl from "react-map-gl/maplibre"; import MapGl from "react-map-gl/maplibre";

Loading…
Cancel
Save