move crosshair on trail hover
This commit is contained in:
@@ -97,7 +97,7 @@
|
||||
!drawing &&
|
||||
fitBounds !== "off" &&
|
||||
data.some((d) => d.bbox !== undefined)
|
||||
) {
|
||||
) {
|
||||
focusTrail(trails[activeTrail]);
|
||||
}
|
||||
} else if (activeTrail === null && trails.length) {
|
||||
@@ -179,13 +179,13 @@
|
||||
return r;
|
||||
}
|
||||
|
||||
function initMap(mapLoaded: boolean) {
|
||||
function initMap(mapLoaded: boolean) {
|
||||
if (!map) {
|
||||
return;
|
||||
}
|
||||
|
||||
refreshElevationProfile();
|
||||
if (showElevation) {
|
||||
if (showElevation && data.length) {
|
||||
epc?.showProfile();
|
||||
}
|
||||
|
||||
@@ -201,22 +201,24 @@
|
||||
removeTrailLayer(layerId);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
if (
|
||||
!drawing &&
|
||||
fitBounds !== "off" &&
|
||||
data.some((d) => d.bbox !== undefined)
|
||||
) {
|
||||
) {
|
||||
if (activeTrail !== null && mapLoaded) {
|
||||
focusTrail(trails[activeTrail]);
|
||||
} else {
|
||||
flyToBounds();
|
||||
}
|
||||
} else if(drawing && activeTrail !== null && mapLoaded) {
|
||||
addCaretLayer(trails[activeTrail]?.id)
|
||||
}
|
||||
}
|
||||
|
||||
export function refreshElevationProfile() {
|
||||
if (activeTrail !== null && data[activeTrail]) {
|
||||
export function refreshElevationProfile() {
|
||||
if (activeTrail !== null && data[activeTrail]) {
|
||||
epc?.setData(data[activeTrail]!, waypoints);
|
||||
}
|
||||
}
|
||||
@@ -283,6 +285,7 @@
|
||||
map?.off("mouseleave", id, layers[id].listener.onLeave!);
|
||||
map?.off("mouseup", id, layers[id].listener.onMouseUp!);
|
||||
map?.off("mousemove", id, layers[id].listener.onMouseMove!);
|
||||
map?.off("mousedown", id, layers[id].listener.onMouseDown!);
|
||||
|
||||
delete layers[id];
|
||||
}
|
||||
@@ -347,10 +350,9 @@
|
||||
highlightTrail(id, trails[activeTrail ?? -1]?.id == id);
|
||||
layers[id].listener.onLeave = (e) => unHighlightTrail(id);
|
||||
layers[id].listener.onMouseUp = (e) => {
|
||||
activeTrail = trails.indexOf(trail);
|
||||
activeTrail = trails.findIndex(t => t.id == trail.id);
|
||||
};
|
||||
layers[id].listener.onMouseMove =
|
||||
moveElevationMarkerToCursorPosition;
|
||||
layers[id].listener.onMouseMove = moveCrosshairToCursorPosition;
|
||||
layers[id].listener.onMouseDown = (e) => handDragStart(e, id);
|
||||
|
||||
map.on("mouseenter", id, layers[id].listener.onEnter);
|
||||
@@ -365,6 +367,11 @@
|
||||
}
|
||||
}
|
||||
|
||||
function moveCrosshairToCursorPosition(e: M.MapMouseEvent) {
|
||||
epc?.moveCrosshair(e.lngLat.lat, e.lngLat.lng);
|
||||
moveElevationMarkerToCursorPosition(e);
|
||||
}
|
||||
|
||||
function moveElevationMarkerToCursorPosition(e: M.MapMouseEvent) {
|
||||
elevationMarker.setLngLat(e.lngLat);
|
||||
}
|
||||
@@ -394,6 +401,7 @@
|
||||
|
||||
function handleDragEnd(e: M.MapMouseEvent) {
|
||||
map?.off("mousemove", moveElevationMarkerToCursorPosition);
|
||||
epc?.hideCrosshair();
|
||||
dispatch("segmentDragEnd", { segment: draggingSegment, event: e });
|
||||
draggingSegment = null;
|
||||
}
|
||||
@@ -405,7 +413,7 @@
|
||||
if (map.getLayer("direction-carets")) {
|
||||
removeCaretLayer();
|
||||
}
|
||||
|
||||
|
||||
map.addLayer({
|
||||
id: "direction-carets",
|
||||
type: "symbol",
|
||||
@@ -459,27 +467,26 @@
|
||||
return;
|
||||
}
|
||||
elevationMarker.setOpacity("0");
|
||||
epc?.hideCrosshair();
|
||||
hoveringTrail = false;
|
||||
map?.setPaintProperty(id, "line-width", 5);
|
||||
// map?.setPaintProperty(id, "line-color", "#648ad5");
|
||||
}
|
||||
|
||||
function focusTrail(trail: Trail) {
|
||||
|
||||
activeTrail = trails.findIndex(t => t.id == trail.id);
|
||||
activeTrail = trails.findIndex((t) => t.id == trail.id);
|
||||
if (activeTrail < 0) {
|
||||
activeTrail = null;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
const currentlyFocussedTrail = trails[activeTrail];
|
||||
if (currentlyFocussedTrail && currentlyFocussedTrail != trail) {
|
||||
unFocusTrail(currentlyFocussedTrail);
|
||||
}
|
||||
dispatch("select", trail);
|
||||
|
||||
|
||||
try {
|
||||
highlightTrail(trail.id!);
|
||||
refreshElevationProfile();
|
||||
if (showElevation) {
|
||||
epc?.showProfile();
|
||||
@@ -488,7 +495,7 @@
|
||||
addCaretLayer(trail.id!);
|
||||
flyToBounds();
|
||||
} catch (e) {
|
||||
console.warn(e)
|
||||
console.warn(e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -743,7 +750,11 @@
|
||||
elevationMarker.setOpacity("0");
|
||||
},
|
||||
onMove: (data) => {
|
||||
elevationMarker.setLngLat(data.position as M.LngLatLike);
|
||||
if (!hoveringTrail) {
|
||||
elevationMarker.setLngLat(
|
||||
data.position as M.LngLatLike,
|
||||
);
|
||||
}
|
||||
},
|
||||
});
|
||||
map.addControl(epc);
|
||||
|
||||
@@ -2,7 +2,7 @@ import { type ControlPosition, type IControl } from "maplibre-gl";
|
||||
import * as M from "maplibre-gl";
|
||||
import { ElevationProfile, type ElevationProfileOptions } from "./elevationprofile";
|
||||
// @ts-ignore
|
||||
import type { GeoJsonObject } from "geojson";
|
||||
import type { GeoJsonObject, Position } from "geojson";
|
||||
import type { Waypoint } from "$lib/models/waypoint";
|
||||
|
||||
/**
|
||||
@@ -189,6 +189,30 @@ export class ElevationProfileControl implements IControl {
|
||||
this.isProfileShown = false;
|
||||
}
|
||||
|
||||
moveCrosshair(lat: number, lon: number) {
|
||||
if (!this.elevationProfileChart) {
|
||||
return;
|
||||
}
|
||||
const chart = this.elevationProfileChart.chart
|
||||
const point = this.elevationProfileChart.getChartCoordinatesFromPosition(lat, lon)
|
||||
if (point == null) {
|
||||
return;
|
||||
}
|
||||
const rectangle = chart.canvas.getBoundingClientRect();
|
||||
|
||||
const mouseMoveEvent = new MouseEvent('mousemove', {
|
||||
clientX: rectangle.left + point[0],
|
||||
clientY: rectangle.top + point[1]
|
||||
});
|
||||
|
||||
chart.canvas.dispatchEvent(mouseMoveEvent);
|
||||
}
|
||||
|
||||
hideCrosshair() {
|
||||
const mouseOutEvent = new MouseEvent('mouseout');
|
||||
return this.elevationProfileChart?.chart.canvas.dispatchEvent(mouseOutEvent);
|
||||
}
|
||||
|
||||
onRemove(): void {
|
||||
// remove button
|
||||
if (this.buttonContainer?.parentNode) {
|
||||
|
||||
@@ -358,7 +358,7 @@ const elevationProfileDefaultOptions: ElevationProfileOptions = {
|
||||
export class ElevationProfile {
|
||||
private canvas: HTMLCanvasElement;
|
||||
private settings: ElevationProfileOptions;
|
||||
private chart: Chart<"line", Array<number>, number>;
|
||||
public chart: Chart<"line", Array<number>, number>;
|
||||
private elevatedPositions: Position[] = [];
|
||||
private elevatedPositionsAdjustedUnit: Position[] = [];
|
||||
private cumulatedDistance: number[] = [];
|
||||
@@ -483,7 +483,6 @@ export class ElevationProfile {
|
||||
},
|
||||
onHover: (_e, item) => {
|
||||
if (typeof this.settings.onMove !== "function") return;
|
||||
|
||||
try {
|
||||
const i = item[0].index;
|
||||
|
||||
@@ -753,6 +752,33 @@ export class ElevationProfile {
|
||||
}
|
||||
}
|
||||
|
||||
getChartCoordinatesFromPosition(lat: number, lon: number) {
|
||||
|
||||
let minDistance = Infinity
|
||||
let bestCandiateIndex: number = -1
|
||||
for (let i = 0; i < this.elevatedPositionsAdjustedUnit.length; i++) {
|
||||
const p = this.elevatedPositionsAdjustedUnit[i];
|
||||
const deltaLat = lat - p[1];
|
||||
const deltaLon = lon - p[0];
|
||||
const distance = deltaLat * deltaLat + deltaLon * deltaLon;
|
||||
|
||||
if (distance < minDistance) {
|
||||
minDistance = distance;
|
||||
bestCandiateIndex = i
|
||||
}
|
||||
};
|
||||
|
||||
if (bestCandiateIndex < 0) {
|
||||
return null;
|
||||
}
|
||||
const meta = this.chart.getDatasetMeta(0);
|
||||
const element = meta.data[bestCandiateIndex];
|
||||
if (element) {
|
||||
return [element.x, element.y];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
gradientFromElevation(chart: Chart, force: boolean = false) {
|
||||
const ctx = chart.ctx;
|
||||
const chartArea = chart.chartArea;
|
||||
@@ -864,7 +890,7 @@ export class ElevationProfile {
|
||||
async setData(data: GeoJsonObject, waypoints?: Waypoint[]) {
|
||||
// Concatenates the positions that may come from multiple LineStrings or MultiLineString
|
||||
const { positions, times } = geoJsonObjectToPositionsAndTimes(data);
|
||||
|
||||
|
||||
this.times = times;
|
||||
|
||||
this.elevatedPositions = smoothElevations(positions, Math.ceil(positions.length / 100));
|
||||
@@ -954,14 +980,17 @@ export class ElevationProfile {
|
||||
|
||||
const timeStart = this.times[segmentStartIndex]
|
||||
const timeEnd = this.times[i]
|
||||
const timeDelta = (timeEnd.getTime() - timeStart.getTime()) / 1000
|
||||
if (timeStart && timeEnd) {
|
||||
const timeDelta = (timeEnd.getTime() - timeStart.getTime()) / 1000
|
||||
|
||||
speed = (distanceDelta / timeDelta)
|
||||
if (this.settings.unit === "imperial") {
|
||||
speed = speed * MILES_HOUR_PER_METER_SECOND
|
||||
} else {
|
||||
speed = speed * KILOMETERS_HOUR_PER_METER_SECOND;
|
||||
speed = (distanceDelta / timeDelta)
|
||||
if (this.settings.unit === "imperial") {
|
||||
speed = speed * MILES_HOUR_PER_METER_SECOND
|
||||
} else {
|
||||
speed = speed * KILOMETERS_HOUR_PER_METER_SECOND;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user