Skip to content
Merged
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
7 changes: 6 additions & 1 deletion src/components/Header.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@

export interface Props {
file: File | undefined;
trimSliderOpen: boolean;
}
</script>

<script lang="ts">
let { file = $bindable() }: Props = $props();
let { file = $bindable(), trimSliderOpen = $bindable() }: Props = $props();

const closeRide = () => (file = undefined);
const toggleTrimSlider = () => (trimSliderOpen = !trimSliderOpen);
</script>

<div class="fixed z-[9000] h-[calc(var(--header-height)+1000px)] top-[-1000px] left-0 right-0 bg-slate-950">
Expand All @@ -30,6 +32,9 @@
</h1>
{#if file}
<Button data-testid="close-ride-button" onclick={closeRide}>close ride</Button>
<div class="hidden wide:block">
<Button onclick={toggleTrimSlider}>trim</Button>
</div>
{/if}
<Button onclick={() => (settings.open = true)}>configure</Button>
</header>
37 changes: 30 additions & 7 deletions src/components/Map.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,18 @@
gpsPoints,
gpsGaps,
pointsOfInterest,
trimStart,
trimEnd,
}: Props = $props();

let node = $state<HTMLDivElement | undefined>();
let travelledPolyline = $state<SegmentedPolyline | null>(null);
let basePolyline = $state<SegmentedPolyline | null>(null);
let segmentModalOpen = $state(false);
let hiddenRideSegments = $state<Set<number>>(new Set());
let polylineSegments = $derived(computeSegmentedLines(gpsGaps, gpsPoints.length, hiddenRideSegments));
let polylineSegments = $derived(
computeSegmentedLines(gpsGaps, gpsPoints.length, hiddenRideSegments, trimStart, trimEnd),
);
let rideSegments = $derived<Set<number>>(new Set(polylineSegments.map((s) => s.segmentIdx)));

$effect(() => {
Expand Down Expand Up @@ -90,11 +94,18 @@
}
});

// ensure this is updated each time the visible rows change
// ensure this is updated each time the visible rows or trim range change
visibleRows;

basePolyline = getBaseLine(gpsPoints, gpsGaps, hiddenRideSegments).addTo(map!);
travelledPolyline = getTravelledLine(gpsPoints, gpsGaps, selectedRowIndex, hiddenRideSegments).addTo(map!);
basePolyline = getBaseLine(gpsPoints, gpsGaps, hiddenRideSegments, trimStart, trimEnd).addTo(map!);
travelledPolyline = getTravelledLine(
gpsPoints,
gpsGaps,
selectedRowIndex,
hiddenRideSegments,
trimStart,
trimEnd,
).addTo(map!);
});

function setVisibleIndices() {
Expand All @@ -107,6 +118,11 @@
? new Array(gpsPoints.length).fill(true)
: gpsPoints.map((point) => bounds.contains(point));

// apply trim range
for (let i = 0; i < newVisiblePoints.length; i++) {
if (i < trimStart || i > trimEnd) newVisiblePoints[i] = false;
}

// hide hidden segments
for (const { start, end, segmentIdx } of polylineSegments) {
if (hiddenRideSegments.has(segmentIdx)) {
Expand Down Expand Up @@ -188,9 +204,16 @@
attribution: '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>',
}).addTo(map);

// create lines
basePolyline = getBaseLine(gpsPoints, gpsGaps, hiddenRideSegments).addTo(map);
travelledPolyline = getTravelledLine(gpsPoints, gpsGaps, selectedRowIndex, hiddenRideSegments).addTo(map);
// create lines (respect trim range)
basePolyline = getBaseLine(gpsPoints, gpsGaps, hiddenRideSegments, trimStart, trimEnd).addTo(map);
travelledPolyline = getTravelledLine(
gpsPoints,
gpsGaps,
selectedRowIndex,
hiddenRideSegments,
trimStart,
trimEnd,
).addTo(map);

// fit ride in map
const polylineBounds = basePolyline.getBounds();
Expand Down
58 changes: 48 additions & 10 deletions src/components/Map.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ export interface Props {
gpsPoints: LatLngExpression[];
gpsGaps: GpsGap[];
pointsOfInterest: PointOfInterest[];
trimStart: number;
trimEnd: number;
}

export { riderSvg };
Expand Down Expand Up @@ -141,16 +143,32 @@ export interface PolylineSegment {
segmentIdx: number;
}

export function computeSegmentedLines(gpsGaps: GpsGap[], maxLength: number, hiddenSegmentIndices: Set<number>) {
export function computeSegmentedLines(
gpsGaps: GpsGap[],
maxLength: number,
hiddenSegmentIndices: Set<number>,
trimStart = 0,
trimEnd = maxLength - 1,
) {
const result: PolylineSegment[] = [];
const trimEndExclusive = trimEnd + 1;
for (let segmentIdx = 0, i = 0; i < gpsGaps.length; ++i) {
const { secondsElapsed, index: start } = gpsGaps[i]!;
if (secondsElapsed > CHARGE_THRESHOLD_SECONDS) segmentIdx++;

const segStart = start;
const segEnd = gpsGaps[i + 1]?.index ?? maxLength;

// clip to trim range
const clippedStart = Math.max(segStart, trimStart);
const clippedEnd = Math.min(segEnd, trimEndExclusive);

if (clippedStart >= clippedEnd) continue;

if (!hiddenSegmentIndices.has(segmentIdx)) {
result.push({
start,
end: gpsGaps[i + 1]?.index ?? maxLength,
start: clippedStart,
end: clippedEnd,
segmentIdx,
});
}
Expand All @@ -163,9 +181,17 @@ export function getBaseLine(
gpsPoints: LatLngExpression[],
gpsGaps: GpsGap[],
hiddenSegmentIndices: Set<number>,
trimStart = 0,
trimEnd = gpsPoints.length - 1,
): SegmentedPolyline {
const values: { points: LatLngExpression[]; options: PolylineOptions }[] = [];
for (const { start, end, segmentIdx } of computeSegmentedLines(gpsGaps, gpsPoints.length, hiddenSegmentIndices)) {
for (const { start, end, segmentIdx } of computeSegmentedLines(
gpsGaps,
gpsPoints.length,
hiddenSegmentIndices,
trimStart,
trimEnd,
)) {
values.push({
points: gpsPoints.slice(start, end),
options: MapLineOptions[MapLine.Base](segmentIdx),
Expand All @@ -180,15 +206,27 @@ export function getTravelledLine(
gpsGaps: GpsGap[],
limit: number,
hiddenSegmentIndices: Set<number>,
trimStart = 0,
trimEnd = gpsPoints.length - 1,
): SegmentedPolyline {
const values: { points: LatLngExpression[]; options: PolylineOptions }[] = [];
for (const { start, end, segmentIdx } of computeSegmentedLines(gpsGaps, gpsPoints.length, hiddenSegmentIndices)) {
values.push({
points: gpsPoints.slice(start, Math.min(limit, end)),
options: MapLineOptions[MapLine.Travelled](segmentIdx),
});
for (const { start, end, segmentIdx } of computeSegmentedLines(
gpsGaps,
gpsPoints.length,
hiddenSegmentIndices,
trimStart,
trimEnd,
)) {
// ensure we don't include points past the selected index
const sliceEnd = Math.min(limit, end);
if (start < sliceEnd) {
values.push({
points: gpsPoints.slice(start, sliceEnd),
options: MapLineOptions[MapLine.Travelled](segmentIdx),
});
}

if (limit === end) {
if (limit <= end) {
break;
}
}
Expand Down
Loading
Loading