diff --git a/web/index.html b/web/index.html index 55fc4d0c6..4d7090d9c 100644 --- a/web/index.html +++ b/web/index.html @@ -114,6 +114,8 @@ ferrostarCore.profile = "bicycle"; ferrostarMap.map = mapInstance; + ferrostarMap.system = "imperial"; + ferrostarMap.maxDecimalPlaces = 2; // Create a search control. const searchBox = new MapLibreSearchControl({ diff --git a/web/package-lock.json b/web/package-lock.json index 731e83f1a..0ee6dd79e 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -9,7 +9,7 @@ "version": "0.40.0", "license": "BSD-3-Clause", "dependencies": { - "@maptimy/platform-formatters": "^0.6.0", + "@maptimy/platform-formatters": "^0.6.1", "@stadiamaps/ferrostar": "file:../common/ferrostar/pkg", "lit": "^3.2.1", "maplibre-gl": "^4.5.0 || ^5" @@ -35,7 +35,7 @@ }, "../common/ferrostar/pkg": { "name": "@stadiamaps/ferrostar", - "version": "0.40.0", + "version": "0.41.0", "license": "BSD-3-Clause" }, "node_modules/@babel/helper-string-parser": { @@ -891,9 +891,9 @@ } }, "node_modules/@maptimy/platform-formatters": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/@maptimy/platform-formatters/-/platform-formatters-0.6.0.tgz", - "integrity": "sha512-RcrraHnEvrr7M4wKx4I1SUrRi7b5R7/S7t6GBFt3EcToVDxa83kdOUN9INu876PKINLaoA4bTyJSYQBY0pXr9A==", + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/@maptimy/platform-formatters/-/platform-formatters-0.6.1.tgz", + "integrity": "sha512-jA8QY2I228C+sDKuBcpoin/Ophk9+iY5RCWNW0RwMlE8bU4UqcI+DxmkAjLvuP3JMM3Gf8bFokmzLajOoe1ZUw==", "license": "BSD-3-Clause", "peerDependencies": { "react-native": "*" diff --git a/web/package.json b/web/package.json index a857c14c9..f57b18791 100644 --- a/web/package.json +++ b/web/package.json @@ -34,7 +34,7 @@ "lint:fix": "npm run lint -- --fix" }, "dependencies": { - "@maptimy/platform-formatters": "^0.6.0", + "@maptimy/platform-formatters": "^0.6.1", "@stadiamaps/ferrostar": "file:../common/ferrostar/pkg", "lit": "^3.2.1", "maplibre-gl": "^4.5.0 || ^5" diff --git a/web/src/ferrostar-map.ts b/web/src/ferrostar-map.ts index a453a2843..30315a69e 100644 --- a/web/src/ferrostar-map.ts +++ b/web/src/ferrostar-map.ts @@ -6,6 +6,27 @@ import { TripState } from "@stadiamaps/ferrostar"; import "./instructions-view"; import "./trip-progress-view"; import { StateProvider as StateProvider } from "./types"; +import { DistanceSystem } from "@maptimy/platform-formatters"; + +const allowedSystems: Array = [ + "metric", + "imperial", + "imperialWithYards", +]; + +const distanceSystemConverter = { + fromAttribute(value: string | null): DistanceSystem | null { + if (!value) return null; + + if (allowedSystems.includes(value as DistanceSystem)) { + return value as DistanceSystem; + } + throw new Error(`Invalid distance system: ${value}`); + }, + toAttribute(value: DistanceSystem): string { + return value; + }, +}; /** * A MapLibre-based map component. @@ -68,6 +89,18 @@ export class FerrostarMap extends LitElement { @property({ type: Boolean }) addGeolocateControl: boolean = true; + @property({ converter: distanceSystemConverter }) + system?: DistanceSystem; + + /** + * Specifies the maximum number of digits allowed after the decimal point + * when formatting distance. This helps control the precision of fractional values. + * + * Example: For a value of 2, the number 3.1415 would be rounded as 3.14. + */ + @property({ type: Number }) + maxDecimalPlaces?: number; + /** * A callback function that is invoked when navigation is stopped. * Optional: This function can be provided by the StateProvider. @@ -390,28 +423,33 @@ export class FerrostarMap extends LitElement {
- + +
+ ${this.showNavigationUI + ? html` + +
+ + +
+ ` + : ""} +
- - ${this.showNavigationUI - ? html` - -
- - -
- ` - : ""}
`; } diff --git a/web/src/formatting.ts b/web/src/formatting.ts new file mode 100644 index 000000000..7442493ad --- /dev/null +++ b/web/src/formatting.ts @@ -0,0 +1,23 @@ +import { + DistanceSystem, + LocalizedDistanceFormatter, +} from "@maptimy/platform-formatters"; + +const DistanceFormatter = LocalizedDistanceFormatter(); + +export function formatDistance( + distanceMeters: number, + system: DistanceSystem = "metric", + desiredMaxDecimalPlaces: number = 2, +): string { + const THRESHOLDS: Record = { + metric: 1000, + imperial: 1609.34, // 1 mile + imperialWithYards: 1609.34, // 1 mile + }; + + const exceedsThreshold = distanceMeters > THRESHOLDS[system]; + const decimalPlaces = exceedsThreshold ? desiredMaxDecimalPlaces : 0; + + return DistanceFormatter.format(distanceMeters, system, decimalPlaces); +} diff --git a/web/src/instructions-view.ts b/web/src/instructions-view.ts index 60a51a0fd..c36f7d90a 100644 --- a/web/src/instructions-view.ts +++ b/web/src/instructions-view.ts @@ -1,15 +1,20 @@ import { LitElement, css, html } from "lit"; import { customElement, property } from "lit/decorators.js"; -import { LocalizedDistanceFormatter } from "@maptimy/platform-formatters"; +import { DistanceSystem } from "@maptimy/platform-formatters"; import "./maneuver-image"; - -const DistanceFormatter = LocalizedDistanceFormatter(); +import { formatDistance } from "./formatting"; @customElement("instructions-view") export class InstructionsView extends LitElement { @property() tripState: any = null; + @property() + system: DistanceSystem = "metric"; + + @property() + maxDecimalPlaces = 2; + static styles = [ css` .instructions-view-card { @@ -63,8 +68,10 @@ export class InstructionsView extends LitElement { ${this.tripState.Navigating.visualInstruction.primaryContent.text}

- ${DistanceFormatter.format( + ${formatDistance( this.tripState.Navigating.progress.distanceToNextManeuver, + this.system, + this.maxDecimalPlaces, )}

diff --git a/web/src/trip-progress-view.ts b/web/src/trip-progress-view.ts index bae0d0778..53ff97fb2 100644 --- a/web/src/trip-progress-view.ts +++ b/web/src/trip-progress-view.ts @@ -1,18 +1,30 @@ import { LocalizedDurationFormatter, - LocalizedDistanceFormatter, + DistanceSystem, } from "@maptimy/platform-formatters"; import { LitElement, css, html } from "lit"; import { customElement, property } from "lit/decorators.js"; +import { formatDistance } from "./formatting"; const DurationFormatter = LocalizedDurationFormatter(); -const DistanceFormatter = LocalizedDistanceFormatter(); @customElement("trip-progress-view") export class TripProgressView extends LitElement { @property() tripState: any = null; + @property() + system: DistanceSystem = "metric"; + + /** + * Specifies the maximum number of digits allowed after the decimal point + * when formatting distance. This helps control the precision of fractional values. + * + * Example: For a value of 2, the number 3.1415 would be rounded as 3.14. + */ + @property() + maxDecimalPlaces = 2; + static styles = [ css` .progress-view-card { @@ -65,8 +77,10 @@ export class TripProgressView extends LitElement { )}

- ${DistanceFormatter.format( + ${formatDistance( this.tripState.Navigating.progress.distanceRemaining, + this.system, + this.maxDecimalPlaces, )}