starts transition to maplibre

This commit is contained in:
Christian Beutel
2024-11-26 00:19:41 +01:00
parent b9ae01846b
commit b6b409e855
21 changed files with 2143 additions and 34 deletions

View File

@@ -1,5 +1,4 @@
import { page } from "$app/stores";
import { currentUser } from "$lib/stores/user_store";
import { get } from "svelte/store";
export function formatTimeHHMM(minutes?: number) {

View File

@@ -0,0 +1,216 @@
import type { BBox, Feature, FeatureCollection, GeoJSON, GeoJsonObject, GeometryCollection, Position } from "geojson";
export function bbox(
geojson: GeoJSON,
): BBox {
if (geojson.bbox != null) {
return geojson.bbox;
}
const result: BBox = [Infinity, Infinity, -Infinity, -Infinity];
let startPoint: Position, endPoint: Position;
coordEach(geojson, (coord) => {
startPoint ??= [coord[0], coord[1]];
endPoint = coord;
if (result[0] > coord[0]) {
result[0] = coord[0];
}
if (result[1] > coord[1]) {
result[1] = coord[1];
}
if (result[2] < coord[0]) {
result[2] = coord[0];
}
if (result[3] < coord[1]) {
result[3] = coord[1];
}
});
return result;
}
export function findStartAndEndPoints(geojson: GeoJsonObject): Position[] {
const startEndPoints: Position[] = [];
(geojson as FeatureCollection).features.forEach((feature) => {
const geometry = feature.geometry;
if (geometry.type === "LineString") {
const coords = geometry.coordinates as number[][];
const start: [number, number] = [coords[0][0], coords[0][1]]; // First point
const end: [number, number] = [
coords[coords.length - 1][0],
coords[coords.length - 1][1],
]; // Last point
startEndPoints.push(start);
startEndPoints.push(end)
} else if (geometry.type === "MultiLineString") {
const coords = geometry.coordinates as number[][][];
const start: [number, number] = [
coords[0][0][0],
coords[0][0][1],
]; // First point of the first line
const lastLine = coords[coords.length - 1];
const end: [number, number] = [
lastLine[lastLine.length - 1][0],
lastLine[lastLine.length - 1][1],
]; // Last point of the last line
startEndPoints.push(start);
startEndPoints.push(end)
} else {
console.warn(
`Geometry type ${geometry.type} is not supported for start/end point extraction.`
);
}
});
return startEndPoints;
}
function coordEach(geojson: GeoJSON, callback: (
currentCoord: number[],
coordIndex: number,
featureIndex: number,
multiFeatureIndex: number,
geometryIndex: number
) => void | false,
excludeWrapCoord?: boolean,) {
// Handles null Geometry -- Skips this GeoJSON
if (geojson === null) return;
var j,
k,
l,
geometry,
stopG,
coords,
geometryMaybeCollection,
wrapShrink = 0,
coordIndex = 0,
isGeometryCollection,
type = geojson.type,
isFeatureCollection = type === "FeatureCollection",
isFeature = type === "Feature",
stop = isFeatureCollection ? (geojson as FeatureCollection).features.length : 1;
for (var featureIndex = 0; featureIndex < stop; featureIndex++) {
geometryMaybeCollection = isFeatureCollection
? (geojson as FeatureCollection).features[featureIndex].geometry
: isFeature
? (geojson as Feature).geometry
: geojson;
isGeometryCollection = geometryMaybeCollection
? geometryMaybeCollection.type === "GeometryCollection"
: false;
stopG = isGeometryCollection
? (geometryMaybeCollection as GeometryCollection).geometries.length
: 1;
for (var geomIndex = 0; geomIndex < stopG; geomIndex++) {
var multiFeatureIndex = 0;
var geometryIndex = 0;
geometry = isGeometryCollection
? (geometryMaybeCollection as GeometryCollection).geometries[geomIndex]
: geometryMaybeCollection;
// Handles null Geometry -- Skips this geometry
if (geometry === null) continue;
coords = (geometry as any).coordinates;
var geomType = geometry.type;
wrapShrink =
excludeWrapCoord &&
(geomType === "Polygon" || geomType === "MultiPolygon")
? 1
: 0;
switch (geomType) {
case null:
break;
case "Point":
if (
callback(
coords,
coordIndex,
featureIndex,
multiFeatureIndex,
geometryIndex
) === false
)
return false;
coordIndex++;
multiFeatureIndex++;
break;
case "LineString":
case "MultiPoint":
for (j = 0; j < coords.length; j++) {
if (
callback(
coords[j],
coordIndex,
featureIndex,
multiFeatureIndex,
geometryIndex
) === false
)
return false;
coordIndex++;
if (geomType === "MultiPoint") multiFeatureIndex++;
}
if (geomType === "LineString") multiFeatureIndex++;
break;
case "Polygon":
case "MultiLineString":
for (j = 0; j < coords.length; j++) {
for (k = 0; k < coords[j].length - wrapShrink; k++) {
if (
callback(
coords[j][k],
coordIndex,
featureIndex,
multiFeatureIndex,
geometryIndex
) === false
)
return false;
coordIndex++;
}
if (geomType === "MultiLineString") multiFeatureIndex++;
if (geomType === "Polygon") geometryIndex++;
}
if (geomType === "Polygon") multiFeatureIndex++;
break;
case "MultiPolygon":
for (j = 0; j < coords.length; j++) {
geometryIndex = 0;
for (k = 0; k < coords[j].length; k++) {
for (l = 0; l < coords[j][k].length - wrapShrink; l++) {
if (
callback(
coords[j][k][l],
coordIndex,
featureIndex,
multiFeatureIndex,
geometryIndex
) === false
)
return false;
coordIndex++;
}
geometryIndex++;
}
multiFeatureIndex++;
}
break;
case "GeometryCollection":
for (j = 0; j < (geometry as GeometryCollection).geometries.length; j++)
if (
coordEach((geometry as GeometryCollection).geometries[j], callback, excludeWrapCoord) ===
false
)
return false;
break;
default:
throw new Error("Unknown Geometry Type");
}
}
}
}

View File

@@ -2,21 +2,22 @@ import GPX from "$lib/models/gpx/gpx";
import { Trail } from "$lib/models/trail";
import { Waypoint } from "$lib/models/waypoint";
import { currentUser } from "$lib/stores/user_store";
import { kml, tcx } from "$lib/vendor/toGeoJSON/toGeoJSON";
import { gpx, kml, tcx } from "$lib/vendor/toGeoJSON/toGeoJSON";
import cryptoRandomString from "crypto-random-string";
import { get } from "svelte/store";
//@ts-ignore
import EasyFit from "$lib/vendor/easy-fit/easy-fit"
import { browser } from "$app/environment";
import Track from "$lib/models/gpx/track";
import TrackSegment from "$lib/models/gpx/track-segment";
import GPXWaypoint from "$lib/models/gpx/waypoint";
import { browser } from "$app/environment";
import * as xmldom from 'xmldom'
import type { Feature, FeatureCollection, GeoJsonProperties, Position } from 'geojson';
import EasyFit from "$lib/vendor/easy-fit/easy-fit";
import type { GeoJSON, Feature, FeatureCollection, GeoJsonProperties, Position } from 'geojson';
import * as xmldom from 'xmldom';
import { bbox } from "./geojson_util";
export async function gpx2trail(gpxString: string, fallbackName?: string) {
const gpx = await GPX.parse(gpxString);
if (gpx instanceof Error) {
@@ -281,4 +282,13 @@ export function isFITFile(buffer: ArrayBuffer) {
}
return true;
}
export function toGeoJson(gpxData: string) {
const parser = browser ? new DOMParser() : new xmldom.DOMParser();
const geojson = gpx(
parser.parseFromString(gpxData, "text/xml"),
) as GeoJSON;
geojson.bbox = bbox(geojson)
return geojson
}

View File

@@ -0,0 +1,44 @@
import type { Waypoint } from "$lib/models/waypoint";
import M from "maplibre-gl";
export class FontawesomeMarker extends M.Marker {
constructor(options: { icon: string, fontSize?: string, width?: number, backgroundColor?: string, fontColor?: string }, markerOptions?: M.MarkerOptions) {
const element = document.createElement('div')
element.className = `cursor-pointer flex items-center justify-center w-${options.width ?? 7} aspect-square bg-${options.backgroundColor ?? "gray-500"} rounded-full text-${options.fontSize ?? "normal"}`
super({ element: element, ...markerOptions });
const {
icon,
} = options
const iconElementString = `<i class="text-${options.fontColor ?? "white"} ${icon}"></i>`
this._element.insertAdjacentHTML('beforeend', iconElementString)
}
}
export function createMarkerFromWaypoint(waypoint: Waypoint, onDragEnd?: (marker: M.Marker) => void): FontawesomeMarker {
const marker = new FontawesomeMarker({
icon: `fa fa-${waypoint.icon}`,
}, {
draggable: onDragEnd != null,
color: "#6b7280"
})
const popup = new M.Popup({ offset: 25, closeButton: false }).setHTML(
"<b>" +
waypoint.name +
"</b>" +
(waypoint.description && waypoint.description.length > 0
? "<br>" + waypoint.description
: ""),
);
marker
.setLngLat([waypoint.lon, waypoint.lat])
.setPopup(popup)
if (onDragEnd) {
marker.on("dragend", () => onDragEnd(marker));
}
return marker;
}