mirror of
https://github.com/seanmorley15/AdventureLog.git
synced 2025-07-29 09:49:38 +02:00
feat: Implement chronological itinerary path visualization with GeoJSON for adventures, transportation, and lodging
This commit is contained in:
parent
1dc8e10758
commit
876c5e83b4
1 changed files with 167 additions and 28 deletions
|
@ -136,6 +136,66 @@
|
||||||
|
|
||||||
let adventures: Adventure[] = [];
|
let adventures: Adventure[] = [];
|
||||||
|
|
||||||
|
// Add this after your existing MapLibre markers
|
||||||
|
|
||||||
|
// Add this after your existing MapLibre markers
|
||||||
|
|
||||||
|
// Create line data from orderedItems
|
||||||
|
$: lineData = createLineData(orderedItems);
|
||||||
|
|
||||||
|
// Function to create GeoJSON line data from ordered items
|
||||||
|
function createLineData(
|
||||||
|
items: Array<{
|
||||||
|
item: Adventure | Transportation | Lodging | Note | Checklist;
|
||||||
|
start: string;
|
||||||
|
end: string;
|
||||||
|
}>
|
||||||
|
) {
|
||||||
|
if (items.length < 2) return null;
|
||||||
|
|
||||||
|
const coordinates: [number, number][] = [];
|
||||||
|
|
||||||
|
// Extract coordinates from each item
|
||||||
|
for (const orderItem of items) {
|
||||||
|
const item = orderItem.item;
|
||||||
|
|
||||||
|
if (
|
||||||
|
'origin_longitude' in item &&
|
||||||
|
'origin_latitude' in item &&
|
||||||
|
'destination_longitude' in item &&
|
||||||
|
'destination_latitude' in item &&
|
||||||
|
item.origin_longitude &&
|
||||||
|
item.origin_latitude &&
|
||||||
|
item.destination_longitude &&
|
||||||
|
item.destination_latitude
|
||||||
|
) {
|
||||||
|
// For Transportation, add both origin and destination points
|
||||||
|
coordinates.push([item.origin_longitude, item.origin_latitude]);
|
||||||
|
coordinates.push([item.destination_longitude, item.destination_latitude]);
|
||||||
|
} else if ('longitude' in item && 'latitude' in item && item.longitude && item.latitude) {
|
||||||
|
// Handle Adventure and Lodging types
|
||||||
|
coordinates.push([item.longitude, item.latitude]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only create line data if we have at least 2 coordinates
|
||||||
|
if (coordinates.length >= 2) {
|
||||||
|
return {
|
||||||
|
type: 'Feature' as const,
|
||||||
|
properties: {
|
||||||
|
name: 'Itinerary Path',
|
||||||
|
description: 'Path connecting chronological items'
|
||||||
|
},
|
||||||
|
geometry: {
|
||||||
|
type: 'LineString' as const,
|
||||||
|
coordinates: coordinates
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
let numVisited: number = 0;
|
let numVisited: number = 0;
|
||||||
let numAdventures: number = 0;
|
let numAdventures: number = 0;
|
||||||
|
|
||||||
|
@ -169,6 +229,63 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let orderedItems: Array<{
|
||||||
|
item: Adventure | Transportation | Lodging;
|
||||||
|
type: 'adventure' | 'transportation' | 'lodging';
|
||||||
|
start: string; // ISO date string
|
||||||
|
end: string; // ISO date string
|
||||||
|
}> = [];
|
||||||
|
|
||||||
|
$: {
|
||||||
|
// Reset ordered items
|
||||||
|
orderedItems = [];
|
||||||
|
|
||||||
|
// Add Adventures (using visit dates)
|
||||||
|
adventures.forEach((adventure) => {
|
||||||
|
adventure.visits.forEach((visit) => {
|
||||||
|
orderedItems.push({
|
||||||
|
item: adventure,
|
||||||
|
start: visit.start_date,
|
||||||
|
end: visit.end_date,
|
||||||
|
type: 'adventure'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add Transportation
|
||||||
|
transportations.forEach((transport) => {
|
||||||
|
if (transport.date) {
|
||||||
|
// Only add if date exists
|
||||||
|
orderedItems.push({
|
||||||
|
item: transport,
|
||||||
|
start: transport.date,
|
||||||
|
end: transport.end_date || transport.date, // Use end_date if available, otherwise use date,
|
||||||
|
type: 'transportation'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add Lodging
|
||||||
|
lodging.forEach((lodging) => {
|
||||||
|
if (lodging.check_in) {
|
||||||
|
// Only add if check_in exists
|
||||||
|
orderedItems.push({
|
||||||
|
item: lodging,
|
||||||
|
start: lodging.check_in,
|
||||||
|
end: lodging.check_out || lodging.check_in, // Use check_out if available, otherwise use check_in,
|
||||||
|
type: 'lodging'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Sort all items chronologically by start date
|
||||||
|
orderedItems.sort((a, b) => {
|
||||||
|
const dateA = new Date(a.start).getTime();
|
||||||
|
const dateB = new Date(b.start).getTime();
|
||||||
|
return dateA - dateB;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
$: {
|
$: {
|
||||||
numAdventures = adventures.length;
|
numAdventures = adventures.length;
|
||||||
numVisited = adventures.filter((adventure) => adventure.is_visited).length;
|
numVisited = adventures.filter((adventure) => adventure.is_visited).length;
|
||||||
|
@ -994,6 +1111,19 @@
|
||||||
</Marker>
|
</Marker>
|
||||||
{/if}
|
{/if}
|
||||||
{/each}
|
{/each}
|
||||||
|
{#if lineData}
|
||||||
|
<GeoJSON data={lineData}>
|
||||||
|
<LineLayer
|
||||||
|
layout={{ 'line-cap': 'round', 'line-join': 'round' }}
|
||||||
|
paint={{
|
||||||
|
'line-width': 4,
|
||||||
|
'line-color': '#0088CC', // Blue line to distinguish from transportation lines
|
||||||
|
'line-opacity': 0.8,
|
||||||
|
'line-dasharray': [2, 1] // Dashed line to differentiate from direct transportation lines
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</GeoJSON>
|
||||||
|
{/if}
|
||||||
{#each transportations as transportation}
|
{#each transportations as transportation}
|
||||||
{#if transportation.origin_latitude && transportation.origin_longitude && transportation.destination_latitude && transportation.destination_longitude}
|
{#if transportation.origin_latitude && transportation.origin_longitude && transportation.destination_latitude && transportation.destination_longitude}
|
||||||
<!-- Origin Marker -->
|
<!-- Origin Marker -->
|
||||||
|
@ -1035,34 +1165,6 @@
|
||||||
</p>
|
</p>
|
||||||
</Popup>
|
</Popup>
|
||||||
</Marker>
|
</Marker>
|
||||||
|
|
||||||
<!-- Line connecting origin and destination -->
|
|
||||||
<GeoJSON
|
|
||||||
data={{
|
|
||||||
type: 'Feature',
|
|
||||||
properties: {
|
|
||||||
name: transportation.name,
|
|
||||||
type: transportation.type
|
|
||||||
},
|
|
||||||
geometry: {
|
|
||||||
type: 'LineString',
|
|
||||||
coordinates: [
|
|
||||||
[transportation.origin_longitude, transportation.origin_latitude],
|
|
||||||
[transportation.destination_longitude, transportation.destination_latitude]
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<LineLayer
|
|
||||||
layout={{ 'line-cap': 'round', 'line-join': 'round' }}
|
|
||||||
paint={{
|
|
||||||
'line-width': 3,
|
|
||||||
'line-color': '#898989', // customize your line color here
|
|
||||||
'line-opacity': 0.8
|
|
||||||
// 'line-dasharray': [5, 2]
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</GeoJSON>
|
|
||||||
{/if}
|
{/if}
|
||||||
{/each}
|
{/each}
|
||||||
|
|
||||||
|
@ -1286,6 +1388,43 @@
|
||||||
{/if}
|
{/if}
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
|
{#each orderedItems as orderedItem}
|
||||||
|
<p>{orderedItem.type}</p>
|
||||||
|
{#if orderedItem.type === 'adventure'}
|
||||||
|
{#if orderedItem.item && 'images' in orderedItem.item}
|
||||||
|
<AdventureCard
|
||||||
|
user={data.user}
|
||||||
|
on:edit={editAdventure}
|
||||||
|
on:delete={deleteAdventure}
|
||||||
|
adventure={orderedItem.item}
|
||||||
|
{collection}
|
||||||
|
/>
|
||||||
|
{/if}
|
||||||
|
{/if}
|
||||||
|
{#if orderedItem.type === 'transportation' && orderedItem.item && 'origin_latitude' in orderedItem.item}
|
||||||
|
<TransportationCard
|
||||||
|
transportation={orderedItem.item}
|
||||||
|
user={data?.user}
|
||||||
|
on:delete={(event) => {
|
||||||
|
transportations = transportations.filter((t) => t.id != event.detail);
|
||||||
|
}}
|
||||||
|
on:edit={editTransportation}
|
||||||
|
{collection}
|
||||||
|
/>
|
||||||
|
{/if}
|
||||||
|
{#if orderedItem.type === 'lodging' && orderedItem.item && 'reservation_number' in orderedItem.item}
|
||||||
|
<LodgingCard
|
||||||
|
lodging={orderedItem.item}
|
||||||
|
user={data?.user}
|
||||||
|
on:delete={(event) => {
|
||||||
|
lodging = lodging.filter((t) => t.id != event.detail);
|
||||||
|
}}
|
||||||
|
on:edit={editLodging}
|
||||||
|
{collection}
|
||||||
|
/>
|
||||||
|
{/if}
|
||||||
|
{/each}
|
||||||
|
|
||||||
<svelte:head>
|
<svelte:head>
|
||||||
<title
|
<title
|
||||||
>{data.props.adventure && data.props.adventure.name
|
>{data.props.adventure && data.props.adventure.name
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue