Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: replace @turf/turf with vanilla TS implementation #382

Closed
Closed
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
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@
"@radix-ui/react-tabs": "^1.1.0",
"@radix-ui/react-toast": "^1.2.1",
"@radix-ui/react-tooltip": "^1.1.1",
"@turf/turf": "^6.5.0",
"base64-js": "^1.5.1",
"class-validator": "^0.14.1",
"class-variance-authority": "^0.7.0",
Expand Down
1,286 changes: 0 additions & 1,286 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

5 changes: 3 additions & 2 deletions src/components/Form/FormWrapper.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Label } from "@components/UI/Label.tsx";
import type { JSX } from "react";

export interface FieldWrapperProps {
label: string;
Expand All @@ -17,7 +18,7 @@ export const FieldWrapper = ({
validationText,
}: FieldWrapperProps): JSX.Element => (
<div className="pt-6 sm:pt-5">
<div role="group" aria-labelledby="label-notifications">
<fieldset aria-labelledby="label-notifications">
<div className="sm:grid sm:grid-cols-3 sm:items-baseline sm:gap-4">
<Label>{label}</Label>
<div className="sm:col-span-2">
Expand All @@ -32,6 +33,6 @@ export const FieldWrapper = ({
</div>
</div>
</div>
</div>
</fieldset>
</div>
);
15 changes: 6 additions & 9 deletions src/components/generic/Table/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -74,15 +74,12 @@ export const Table = ({ headings, rows }: TableProps): JSX.Element => {
>
<div className="flex gap-2">
{heading.title}
{sortColumn === heading.title && (
<>
{sortOrder === "asc" ? (
<ChevronUpIcon size={16} />
) : (
<ChevronDownIcon size={16} />
)}
</>
)}
{sortColumn === heading.title &&
(sortOrder === "asc" ? (
<ChevronUpIcon size={16} />
) : (
<ChevronDownIcon size={16} />
))}
</div>
</th>
))}
Expand Down
109 changes: 109 additions & 0 deletions src/core/utils/maps.ts
Original file line number Diff line number Diff line change
@@ -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 };
1 change: 0 additions & 1 deletion src/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,5 @@
}

img {
-drag: none;
-webkit-user-drag: none;
}
4 changes: 2 additions & 2 deletions src/pages/Map.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,17 @@ import { SidebarSection } from "@components/UI/Sidebar/SidebarSection.tsx";
import { SidebarButton } from "@components/UI/Sidebar/sidebarButton.tsx";
import { useAppStore } from "@core/stores/appStore.ts";
import { useDevice } from "@core/stores/deviceStore.ts";
import { bbox, lineString } from "@core/utils/maps";
import { Hashicon } from "@emeraldpay/hashicon-react";
import type { Protobuf } from "@meshtastic/js";
import { numberToHexUnpadded } from "@noble/curves/abstract/utils";
import { bbox, lineString } from "@turf/turf";
import {
BoxSelectIcon,
MapPinIcon,
ZoomInIcon,
ZoomOutIcon,
} 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 MapGl from "react-map-gl/maplibre";

Expand Down
Loading