mirror of
https://github.com/gpxstudio/gpx.studio.git
synced 2026-03-13 16:22:59 +00:00
Compare commits
6 Commits
bfd0d90abc
...
maplibre
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c9ca75e2e8 | ||
|
|
091f6a3ed0 | ||
|
|
d6c9fb1025 | ||
|
|
88abd72a41 | ||
|
|
1137e851ce | ||
|
|
b8c1500aad |
@@ -31,13 +31,13 @@
|
|||||||
|
|
||||||
<Card.Root
|
<Card.Root
|
||||||
class="h-full {orientation === 'vertical'
|
class="h-full {orientation === 'vertical'
|
||||||
? 'min-w-40 sm:min-w-44 text-sm sm:text-base'
|
? 'min-w-40 sm:min-w-44'
|
||||||
: 'w-full'} border-none shadow-none p-0"
|
: 'w-full h-10'} border-none shadow-none p-0 text-sm sm:text-base"
|
||||||
>
|
>
|
||||||
<Card.Content
|
<Card.Content
|
||||||
class="h-full flex {orientation === 'vertical'
|
class="h-full flex {orientation === 'vertical'
|
||||||
? 'flex-col justify-center'
|
? 'flex-col justify-center'
|
||||||
: 'flex-row w-full justify-between'} gap-4 p-0"
|
: 'flex-row w-full justify-evenly'} gap-4 p-0"
|
||||||
>
|
>
|
||||||
<Tooltip label={i18n._('quantities.distance')}>
|
<Tooltip label={i18n._('quantities.distance')}>
|
||||||
<span class="flex flex-row items-center">
|
<span class="flex flex-row items-center">
|
||||||
|
|||||||
@@ -64,7 +64,7 @@
|
|||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="h-full grow min-w-0 relative py-2">
|
<div class="h-full grow min-w-0 min-h-0 relative">
|
||||||
<canvas bind:this={overlay} class="w-full h-full absolute pointer-events-none"></canvas>
|
<canvas bind:this={overlay} class="w-full h-full absolute pointer-events-none"></canvas>
|
||||||
<canvas bind:this={canvas} class="w-full h-full absolute"></canvas>
|
<canvas bind:this={canvas} class="w-full h-full absolute"></canvas>
|
||||||
{#if showControls}
|
{#if showControls}
|
||||||
|
|||||||
@@ -5,6 +5,16 @@
|
|||||||
|
|
||||||
map.onLoad((map_) => {
|
map.onLoad((map_) => {
|
||||||
map_.on('contextmenu', (e) => {
|
map_.on('contextmenu', (e) => {
|
||||||
|
if (
|
||||||
|
map_.queryRenderedFeatures(e.point, {
|
||||||
|
layers: map_
|
||||||
|
.getLayersOrder()
|
||||||
|
.filter((layerId) => layerId.startsWith('routing-controls')),
|
||||||
|
}).length
|
||||||
|
) {
|
||||||
|
// Clicked on routing control, ignoring
|
||||||
|
return;
|
||||||
|
}
|
||||||
trackpointPopup?.setItem({
|
trackpointPopup?.setItem({
|
||||||
item: new TrackPoint({
|
item: new TrackPoint({
|
||||||
attributes: {
|
attributes: {
|
||||||
|
|||||||
@@ -129,12 +129,21 @@
|
|||||||
@apply relative;
|
@apply relative;
|
||||||
@apply top-0;
|
@apply top-0;
|
||||||
@apply left-0;
|
@apply left-0;
|
||||||
@apply my-2;
|
|
||||||
@apply w-[29px];
|
@apply w-[29px];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
div :global(.maplibregl-ctrl-geocoder--icon-loading) {
|
||||||
|
@apply -mt-1;
|
||||||
|
@apply mb-0;
|
||||||
|
}
|
||||||
|
|
||||||
|
div :global(.maplibregl-ctrl-geocoder--icon-close) {
|
||||||
|
@apply my-0;
|
||||||
|
}
|
||||||
|
|
||||||
div :global(.maplibregl-ctrl-geocoder--input) {
|
div :global(.maplibregl-ctrl-geocoder--input) {
|
||||||
@apply relative;
|
@apply relative;
|
||||||
|
@apply h-8;
|
||||||
@apply w-64;
|
@apply w-64;
|
||||||
@apply py-0;
|
@apply py-0;
|
||||||
@apply pl-2;
|
@apply pl-2;
|
||||||
|
|||||||
@@ -287,6 +287,7 @@ export class GPXLayer {
|
|||||||
_map.addSource(this.fileId + '-waypoints', {
|
_map.addSource(this.fileId + '-waypoints', {
|
||||||
type: 'geojson',
|
type: 'geojson',
|
||||||
data: this.currentWaypointData,
|
data: this.currentWaypointData,
|
||||||
|
promoteId: 'waypointIndex',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -645,7 +646,17 @@ export class GPXLayer {
|
|||||||
| GeoJSONSource
|
| GeoJSONSource
|
||||||
| undefined;
|
| undefined;
|
||||||
if (waypointSource) {
|
if (waypointSource) {
|
||||||
waypointSource.setData(this.currentWaypointData!);
|
waypointSource.updateData({
|
||||||
|
update: [
|
||||||
|
{
|
||||||
|
id: this.draggedWaypointIndex,
|
||||||
|
newGeometry: {
|
||||||
|
type: 'Point',
|
||||||
|
coordinates: [e.lngLat.lng, e.lngLat.lat],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -50,17 +50,20 @@ export class StartEndMarkers {
|
|||||||
const slicedStatistics = get(slicedGPXStatistics);
|
const slicedStatistics = get(slicedGPXStatistics);
|
||||||
const hovered = get(hoveredPoint);
|
const hovered = get(hoveredPoint);
|
||||||
const hidden = get(allHidden);
|
const hidden = get(allHidden);
|
||||||
if (statistics.global.length > 0 && tool !== Tool.ROUTING && !hidden) {
|
if (!hidden) {
|
||||||
|
const data: GeoJSON.FeatureCollection = {
|
||||||
|
type: 'FeatureCollection',
|
||||||
|
features: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
if (statistics.global.length > 0 && tool !== Tool.ROUTING) {
|
||||||
const start = statistics
|
const start = statistics
|
||||||
.getTrackPoint(slicedStatistics?.[1] ?? 0)!
|
.getTrackPoint(slicedStatistics?.[1] ?? 0)!
|
||||||
.trkpt.getCoordinates();
|
.trkpt.getCoordinates();
|
||||||
const end = statistics
|
const end = statistics
|
||||||
.getTrackPoint(slicedStatistics?.[2] ?? statistics.global.length - 1)!
|
.getTrackPoint(slicedStatistics?.[2] ?? statistics.global.length - 1)!
|
||||||
.trkpt.getCoordinates();
|
.trkpt.getCoordinates();
|
||||||
const data: GeoJSON.FeatureCollection = {
|
data.features.push({
|
||||||
type: 'FeatureCollection',
|
|
||||||
features: [
|
|
||||||
{
|
|
||||||
type: 'Feature',
|
type: 'Feature',
|
||||||
geometry: {
|
geometry: {
|
||||||
type: 'Point',
|
type: 'Point',
|
||||||
@@ -69,8 +72,8 @@ export class StartEndMarkers {
|
|||||||
properties: {
|
properties: {
|
||||||
icon: 'start-marker',
|
icon: 'start-marker',
|
||||||
},
|
},
|
||||||
},
|
});
|
||||||
{
|
data.features.push({
|
||||||
type: 'Feature',
|
type: 'Feature',
|
||||||
geometry: {
|
geometry: {
|
||||||
type: 'Point',
|
type: 'Point',
|
||||||
@@ -79,9 +82,8 @@ export class StartEndMarkers {
|
|||||||
properties: {
|
properties: {
|
||||||
icon: 'end-marker',
|
icon: 'end-marker',
|
||||||
},
|
},
|
||||||
},
|
});
|
||||||
],
|
}
|
||||||
};
|
|
||||||
|
|
||||||
if (hovered) {
|
if (hovered) {
|
||||||
data.features.push({
|
data.features.push({
|
||||||
|
|||||||
@@ -142,21 +142,7 @@ export class MapLayerEventManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _handleMouseMove(e: maplibregl.MapMouseEvent) {
|
private _handleMouseMove(e: maplibregl.MapMouseEvent) {
|
||||||
const layerIds = this._filterLayersContainingCoordinate(
|
const featuresByLayer = this._getRenderedFeaturesByLayer(e);
|
||||||
Object.keys(this._listeners),
|
|
||||||
e.lngLat
|
|
||||||
);
|
|
||||||
const features =
|
|
||||||
layerIds.length > 0
|
|
||||||
? this._map.queryRenderedFeatures(e.point, { layers: layerIds })
|
|
||||||
: [];
|
|
||||||
const featuresByLayer: Record<string, maplibregl.MapGeoJSONFeature[]> = {};
|
|
||||||
features.forEach((f) => {
|
|
||||||
if (!featuresByLayer[f.layer.id]) {
|
|
||||||
featuresByLayer[f.layer.id] = [];
|
|
||||||
}
|
|
||||||
featuresByLayer[f.layer.id].push(f);
|
|
||||||
});
|
|
||||||
Object.keys(this._listeners).forEach((layerId) => {
|
Object.keys(this._listeners).forEach((layerId) => {
|
||||||
const features = featuresByLayer[layerId] || [];
|
const features = featuresByLayer[layerId] || [];
|
||||||
const listener = this._listeners[layerId];
|
const listener = this._listeners[layerId];
|
||||||
@@ -183,7 +169,6 @@ export class MapLayerEventManager {
|
|||||||
listener.mouseleaves.forEach((l) => l(event));
|
listener.mouseleaves.forEach((l) => l(event));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
listener.features = features;
|
|
||||||
}
|
}
|
||||||
if (features.length > 0 && listener.mousemoves.length > 0) {
|
if (features.length > 0 && listener.mousemoves.length > 0) {
|
||||||
const event = new maplibregl.MapMouseEvent('mousemove', e.target, e.originalEvent, {
|
const event = new maplibregl.MapMouseEvent('mousemove', e.target, e.originalEvent, {
|
||||||
@@ -191,15 +176,19 @@ export class MapLayerEventManager {
|
|||||||
});
|
});
|
||||||
listener.mousemoves.forEach((l) => l(event));
|
listener.mousemoves.forEach((l) => l(event));
|
||||||
}
|
}
|
||||||
|
listener.features = features;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private _handleMouseClick(type: string, e: maplibregl.MapMouseEvent) {
|
private _handleMouseClick(type: string, e: maplibregl.MapMouseEvent) {
|
||||||
Object.values(this._listeners).forEach((listener) => {
|
const featuresByLayer = this._getRenderedFeaturesByLayer(e);
|
||||||
if (listener.features.length > 0) {
|
Object.keys(this._listeners).forEach((layerId) => {
|
||||||
|
const features = featuresByLayer[layerId] || [];
|
||||||
|
const listener = this._listeners[layerId];
|
||||||
|
if (features.length > 0) {
|
||||||
if (type === 'click' && listener.clicks.length > 0) {
|
if (type === 'click' && listener.clicks.length > 0) {
|
||||||
const event = new maplibregl.MapMouseEvent('click', e.target, e.originalEvent, {
|
const event = new maplibregl.MapMouseEvent('click', e.target, e.originalEvent, {
|
||||||
features: listener.features,
|
features: features,
|
||||||
});
|
});
|
||||||
listener.clicks.forEach((l) => l(event));
|
listener.clicks.forEach((l) => l(event));
|
||||||
} else if (type === 'contextmenu' && listener.contextmenus.length > 0) {
|
} else if (type === 'contextmenu' && listener.contextmenus.length > 0) {
|
||||||
@@ -208,7 +197,7 @@ export class MapLayerEventManager {
|
|||||||
e.target,
|
e.target,
|
||||||
e.originalEvent,
|
e.originalEvent,
|
||||||
{
|
{
|
||||||
features: listener.features,
|
features: features,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
listener.contextmenus.forEach((l) => l(event));
|
listener.contextmenus.forEach((l) => l(event));
|
||||||
@@ -218,7 +207,7 @@ export class MapLayerEventManager {
|
|||||||
e.target,
|
e.target,
|
||||||
e.originalEvent,
|
e.originalEvent,
|
||||||
{
|
{
|
||||||
features: listener.features,
|
features: features,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
listener.mousedowns.forEach((l) => l(event));
|
listener.mousedowns.forEach((l) => l(event));
|
||||||
@@ -228,21 +217,7 @@ export class MapLayerEventManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _handleTouchStart(e: maplibregl.MapTouchEvent) {
|
private _handleTouchStart(e: maplibregl.MapTouchEvent) {
|
||||||
const layerIds = this._filterLayersContainingCoordinate(
|
const featuresByLayer = this._getRenderedFeaturesByLayer(e);
|
||||||
Object.keys(this._listeners).filter(
|
|
||||||
(layerId) => this._listeners[layerId].touchstarts.length > 0
|
|
||||||
),
|
|
||||||
e.lngLat
|
|
||||||
);
|
|
||||||
if (layerIds.length === 0) return;
|
|
||||||
const features = this._map.queryRenderedFeatures(e.points[0], { layers: layerIds });
|
|
||||||
const featuresByLayer: Record<string, maplibregl.MapGeoJSONFeature[]> = {};
|
|
||||||
features.forEach((f) => {
|
|
||||||
if (!featuresByLayer[f.layer.id]) {
|
|
||||||
featuresByLayer[f.layer.id] = [];
|
|
||||||
}
|
|
||||||
featuresByLayer[f.layer.id].push(f);
|
|
||||||
});
|
|
||||||
Object.keys(this._listeners).forEach((layerId) => {
|
Object.keys(this._listeners).forEach((layerId) => {
|
||||||
const features = featuresByLayer[layerId] || [];
|
const features = featuresByLayer[layerId] || [];
|
||||||
const listener = this._listeners[layerId];
|
const listener = this._listeners[layerId];
|
||||||
@@ -258,19 +233,49 @@ export class MapLayerEventManager {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private _filterLayersContainingCoordinate(
|
private _getBounds(point: maplibregl.Point) {
|
||||||
|
const delta = 30;
|
||||||
|
return new maplibregl.LngLatBounds(
|
||||||
|
this._map.unproject([point.x - delta, point.y + delta]),
|
||||||
|
this._map.unproject([point.x + delta, point.y - delta])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private _filterLayersIntersectingBounds(
|
||||||
layerIds: string[],
|
layerIds: string[],
|
||||||
lngLat: maplibregl.LngLat
|
bounds: maplibregl.LngLatBounds
|
||||||
): string[] {
|
): string[] {
|
||||||
let result = layerIds.filter((layerId) => {
|
let result = layerIds.filter((layerId) => {
|
||||||
if (!this._map.getLayer(layerId)) return false;
|
if (!this._map.getLayer(layerId)) return false;
|
||||||
const fileId = layerId.replace('-waypoints', '');
|
const fileId = layerId.replace('-waypoints', '');
|
||||||
if (fileId === layerId) {
|
if (fileId === layerId) {
|
||||||
return fileStateCollection.getStatistics(fileId)?.inBBox(lngLat) ?? true;
|
return fileStateCollection.getStatistics(fileId)?.intersectsBBox(bounds) ?? true;
|
||||||
} else {
|
} else {
|
||||||
return fileStateCollection.getStatistics(fileId)?.inWaypointBBox(lngLat) ?? true;
|
return (
|
||||||
|
fileStateCollection.getStatistics(fileId)?.intersectsWaypointBBox(bounds) ??
|
||||||
|
true
|
||||||
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _getRenderedFeaturesByLayer(e: maplibregl.MapMouseEvent | maplibregl.MapTouchEvent) {
|
||||||
|
const layerIds = this._filterLayersIntersectingBounds(
|
||||||
|
Object.keys(this._listeners),
|
||||||
|
this._getBounds(e.point)
|
||||||
|
);
|
||||||
|
const features =
|
||||||
|
layerIds.length > 0
|
||||||
|
? this._map.queryRenderedFeatures(e.point, { layers: layerIds })
|
||||||
|
: [];
|
||||||
|
const featuresByLayer: Record<string, maplibregl.MapGeoJSONFeature[]> = {};
|
||||||
|
features.forEach((f) => {
|
||||||
|
if (!featuresByLayer[f.layer.id]) {
|
||||||
|
featuresByLayer[f.layer.id] = [];
|
||||||
|
}
|
||||||
|
featuresByLayer[f.layer.id].push(f);
|
||||||
|
});
|
||||||
|
return featuresByLayer;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ export const ANCHOR_LAYER_KEY = {
|
|||||||
interactions: 'interactions-end',
|
interactions: 'interactions-end',
|
||||||
overpass: 'overpass-end',
|
overpass: 'overpass-end',
|
||||||
waypoints: 'waypoints-end',
|
waypoints: 'waypoints-end',
|
||||||
|
routingControls: 'routing-controls-end',
|
||||||
};
|
};
|
||||||
const anchorLayers: maplibregl.LayerSpecification[] = Object.values(ANCHOR_LAYER_KEY).map((id) => ({
|
const anchorLayers: maplibregl.LayerSpecification[] = Object.values(ANCHOR_LAYER_KEY).map((id) => ({
|
||||||
id: id,
|
id: id,
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -2,15 +2,21 @@ import { ramerDouglasPeucker, type GPXFile, type TrackSegment } from 'gpx';
|
|||||||
|
|
||||||
const earthRadius = 6371008.8;
|
const earthRadius = 6371008.8;
|
||||||
|
|
||||||
|
export const MIN_ANCHOR_ZOOM = 0;
|
||||||
|
export const MAX_ANCHOR_ZOOM = 22;
|
||||||
|
|
||||||
export function getZoomLevelForDistance(latitude: number, distance?: number): number {
|
export function getZoomLevelForDistance(latitude: number, distance?: number): number {
|
||||||
if (distance === undefined) {
|
if (distance === undefined) {
|
||||||
return 0;
|
return MIN_ANCHOR_ZOOM;
|
||||||
}
|
}
|
||||||
|
|
||||||
const rad = Math.PI / 180;
|
const rad = Math.PI / 180;
|
||||||
const lat = latitude * rad;
|
const lat = latitude * rad;
|
||||||
|
|
||||||
return Math.min(22, Math.max(0, Math.log2((earthRadius * Math.cos(lat)) / distance)));
|
return Math.min(
|
||||||
|
MAX_ANCHOR_ZOOM,
|
||||||
|
Math.max(MIN_ANCHOR_ZOOM, Math.round(Math.log2((earthRadius * Math.cos(lat)) / distance)))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function updateAnchorPoints(file: GPXFile) {
|
export function updateAnchorPoints(file: GPXFile) {
|
||||||
|
|||||||
@@ -1,2 +0,0 @@
|
|||||||
MapTiler is the company that provides some of the beautiful maps on this website.
|
|
||||||
This partnership allows **gpx.studio** to benefit from MapTiler tools at discounted prices, greatly contributing to the financial viability of the project and enabling us to offer the best possible user experience.
|
|
||||||
@@ -7,7 +7,8 @@ export enum MapCursorState {
|
|||||||
TOOL_WITH_CROSSHAIR,
|
TOOL_WITH_CROSSHAIR,
|
||||||
WAYPOINT_HOVER,
|
WAYPOINT_HOVER,
|
||||||
WAYPOINT_DRAGGING,
|
WAYPOINT_DRAGGING,
|
||||||
TRACKPOINT_DRAGGING,
|
ANCHOR_HOVER,
|
||||||
|
ANCHOR_DRAGGING,
|
||||||
SCISSORS,
|
SCISSORS,
|
||||||
SPLIT_CONTROL,
|
SPLIT_CONTROL,
|
||||||
MAPILLARY_HOVER,
|
MAPILLARY_HOVER,
|
||||||
@@ -20,7 +21,8 @@ const cursorStyles = {
|
|||||||
[MapCursorState.LAYER_HOVER]: 'pointer',
|
[MapCursorState.LAYER_HOVER]: 'pointer',
|
||||||
[MapCursorState.WAYPOINT_HOVER]: 'pointer',
|
[MapCursorState.WAYPOINT_HOVER]: 'pointer',
|
||||||
[MapCursorState.WAYPOINT_DRAGGING]: 'grabbing',
|
[MapCursorState.WAYPOINT_DRAGGING]: 'grabbing',
|
||||||
[MapCursorState.TRACKPOINT_DRAGGING]: 'grabbing',
|
[MapCursorState.ANCHOR_HOVER]: 'pointer',
|
||||||
|
[MapCursorState.ANCHOR_DRAGGING]: 'grabbing',
|
||||||
[MapCursorState.TOOL_WITH_CROSSHAIR]: 'crosshair',
|
[MapCursorState.TOOL_WITH_CROSSHAIR]: 'crosshair',
|
||||||
[MapCursorState.SCISSORS]: scissorsCursor,
|
[MapCursorState.SCISSORS]: scissorsCursor,
|
||||||
[MapCursorState.SPLIT_CONTROL]: 'pointer',
|
[MapCursorState.SPLIT_CONTROL]: 'pointer',
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ export class GPXStatisticsTree {
|
|||||||
return statistics;
|
return statistics;
|
||||||
}
|
}
|
||||||
|
|
||||||
inBBox(coordinates: { lat: number; lng: number }): boolean {
|
intersectsBBox(bounds: maplibregl.LngLatBounds): boolean {
|
||||||
for (let key in this.statistics) {
|
for (let key in this.statistics) {
|
||||||
const stats = this.statistics[key];
|
const stats = this.statistics[key];
|
||||||
if (stats instanceof GPXStatistics) {
|
if (stats instanceof GPXStatistics) {
|
||||||
@@ -57,18 +57,18 @@ export class GPXStatisticsTree {
|
|||||||
stats.global.bounds.southWest,
|
stats.global.bounds.southWest,
|
||||||
stats.global.bounds.northEast
|
stats.global.bounds.northEast
|
||||||
);
|
);
|
||||||
if (!bbox.isEmpty() && bbox.contains(coordinates)) {
|
if (!bbox.isEmpty() && bbox.intersects(bounds)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else if (stats.inBBox(coordinates)) {
|
} else if (stats.intersectsBBox(bounds)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
inWaypointBBox(coordinates: { lat: number; lng: number }): boolean {
|
intersectsWaypointBBox(bounds: maplibregl.LngLatBounds): boolean {
|
||||||
return !this.wptBounds.isEmpty() && this.wptBounds.contains(coordinates);
|
return !this.wptBounds.isEmpty() && this.wptBounds.intersects(bounds);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export type GPXFileWithStatistics = { file: GPXFile; statistics: GPXStatisticsTree };
|
export type GPXFileWithStatistics = { file: GPXFile; statistics: GPXStatisticsTree };
|
||||||
|
|||||||
@@ -197,9 +197,9 @@ export function getElevation(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function loadSVGIcon(map: maplibregl.Map, id: string, svg: string) {
|
export function loadSVGIcon(map: maplibregl.Map, id: string, svg: string, size: number = 100) {
|
||||||
if (!map.hasImage(id)) {
|
if (!map.hasImage(id)) {
|
||||||
let icon = new Image(100, 100);
|
let icon = new Image(size, size);
|
||||||
icon.onload = () => {
|
icon.onload = () => {
|
||||||
if (!map.hasImage(id)) {
|
if (!map.hasImage(id)) {
|
||||||
map.addImage(id, icon);
|
map.addImage(id, icon);
|
||||||
|
|||||||
@@ -29,7 +29,6 @@
|
|||||||
data: {
|
data: {
|
||||||
fundingModule: Promise<any>;
|
fundingModule: Promise<any>;
|
||||||
translationModule: Promise<any>;
|
translationModule: Promise<any>;
|
||||||
maptilerModule: Promise<any>;
|
|
||||||
};
|
};
|
||||||
} = $props();
|
} = $props();
|
||||||
|
|
||||||
@@ -272,23 +271,4 @@
|
|||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="px-12 md:px-24 flex flex-col items-center">
|
|
||||||
<div
|
|
||||||
class="max-w-4xl flex flex-col lg:flex-row items-center justify-center gap-x-12 gap-y-6 p-6 border rounded-2xl shadow-xl bg-secondary"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="shrink-0 flex flex-col sm:flex-row lg:flex-col items-center gap-x-4 gap-y-2"
|
|
||||||
>
|
|
||||||
<div class="text-lg font-semibold text-muted-foreground">
|
|
||||||
❤️ {i18n._('homepage.supported_by')}
|
|
||||||
</div>
|
|
||||||
<a href="https://www.maptiler.com/" target="_blank">
|
|
||||||
<Logo company="maptiler" class="w-60" />
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
{#await data.maptilerModule then maptilerModule}
|
|
||||||
<DocsContainer module={maptilerModule.default} />
|
|
||||||
{/await}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -9,6 +9,5 @@ export async function load({ params }) {
|
|||||||
return {
|
return {
|
||||||
fundingModule: getModule(language, 'funding'),
|
fundingModule: getModule(language, 'funding'),
|
||||||
translationModule: getModule(language, 'translation'),
|
translationModule: getModule(language, 'translation'),
|
||||||
maptilerModule: getModule(language, 'maptiler'),
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,6 +30,11 @@
|
|||||||
elevationFill,
|
elevationFill,
|
||||||
} = settings;
|
} = settings;
|
||||||
|
|
||||||
|
let bottomPanelWidth: number | undefined = $state();
|
||||||
|
let bottomPanelOrientation = $derived(
|
||||||
|
bottomPanelWidth && bottomPanelWidth >= 540 && $elevationProfile ? 'horizontal' : 'vertical'
|
||||||
|
);
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
settings.connectToDatabase(db);
|
settings.connectToDatabase(db);
|
||||||
fileStateCollection.connectToDatabase(db).then(() => {
|
fileStateCollection.connectToDatabase(db).then(() => {
|
||||||
@@ -127,14 +132,17 @@
|
|||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
<div
|
<div
|
||||||
class="{$elevationProfile ? '' : 'h-10'} flex flex-row gap-2 px-2 sm:px-4"
|
bind:offsetWidth={bottomPanelWidth}
|
||||||
|
class="flex {bottomPanelOrientation == 'vertical'
|
||||||
|
? 'flex-col'
|
||||||
|
: 'flex-row py-2'} gap-1 px-2"
|
||||||
style={$elevationProfile ? `height: ${$bottomPanelSize}px` : ''}
|
style={$elevationProfile ? `height: ${$bottomPanelSize}px` : ''}
|
||||||
>
|
>
|
||||||
<GPXStatistics
|
<GPXStatistics
|
||||||
{gpxStatistics}
|
{gpxStatistics}
|
||||||
{slicedGPXStatistics}
|
{slicedGPXStatistics}
|
||||||
panelSize={$bottomPanelSize}
|
panelSize={$bottomPanelSize}
|
||||||
orientation={$elevationProfile ? 'vertical' : 'horizontal'}
|
orientation={bottomPanelOrientation == 'horizontal' ? 'vertical' : 'horizontal'}
|
||||||
/>
|
/>
|
||||||
{#if $elevationProfile}
|
{#if $elevationProfile}
|
||||||
<ElevationProfile
|
<ElevationProfile
|
||||||
|
|||||||
Reference in New Issue
Block a user