Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(Mostly) Web & Docs Cleanup #260

Merged
merged 8 commits into from
Sep 24, 2024
Merged
Show file tree
Hide file tree
Changes from 6 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
26 changes: 13 additions & 13 deletions Package.resolved
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/maplibre/maplibre-gl-native-distribution.git",
"state" : {
"revision" : "abe762f1e19e03a4c6943d2aad92c219da384b29",
"version" : "6.5.4"
"revision" : "def156895a9ce38ea9bf9632c1e2272280ce0ae3",
"version" : "6.6.0"
}
},
{
Expand All @@ -18,15 +18,6 @@
"version" : "0.0.4"
}
},
{
"identity" : "maplibre-swiftui-dsl-playground",
"kind" : "remoteSourceControl",
"location" : "https://github.com/stadiamaps/maplibre-swiftui-dsl-playground",
"state" : {
"revision" : "a789bbee505a1344a87d9a5f999455ed55acdcde",
"version" : "0.0.28"
}
},
{
"identity" : "mockable",
"kind" : "remoteSourceControl",
Expand All @@ -41,8 +32,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/pointfreeco/swift-snapshot-testing",
"state" : {
"revision" : "6d932a79e7173b275b96c600c86c603cf84f153c",
"version" : "1.17.4"
"revision" : "7b0bbbae90c41f848f90ac7b4df6c4f50068256d",
"version" : "1.17.5"
}
},
{
Expand All @@ -53,6 +44,15 @@
"revision" : "64889f0c732f210a935a0ad7cda38f77f876262d",
"version" : "509.1.1"
}
},
{
"identity" : "swiftui-dsl",
"kind" : "remoteSourceControl",
"location" : "https://github.com/maplibre/swiftui-dsl",
"state" : {
"revision" : "2b856f5b1ad7eb650e2e2a43ed85689a312c630d",
"version" : "0.0.29"
}
}
],
"version" : 2
Expand Down
6 changes: 3 additions & 3 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ if useLocalMapLibreSwiftUIDSL {
maplibreSwiftUIDSLPackage = .package(path: "../maplibre-swiftui-dsl-playground")
} else {
maplibreSwiftUIDSLPackage = .package(
url: "https://github.com/stadiamaps/maplibre-swiftui-dsl-playground",
url: "https://github.com/maplibre/swiftui-dsl",
from: "0.0.23"
)
}
Expand Down Expand Up @@ -74,8 +74,8 @@ let package = Package(
name: "FerrostarMapLibreUI",
dependencies: [
.target(name: "FerrostarCore"),
.product(name: "MapLibreSwiftDSL", package: "maplibre-swiftui-dsl-playground"),
.product(name: "MapLibreSwiftUI", package: "maplibre-swiftui-dsl-playground"),
.product(name: "MapLibreSwiftDSL", package: "swiftui-dsl"),
.product(name: "MapLibreSwiftUI", package: "swiftui-dsl"),
],
path: "apple/Sources/FerrostarMapLibreUI"
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ public enum NavigationMapViewContentInsetMode {
/// This is used to accommodate a left InstructionView
case landscape(within: GeometryProxy, verticalPct: CGFloat = 0.75, horizontalPct: CGFloat = 0.5)

/// A predefined mode for landscape navigation map views
/// A predefined mode for portrait navigation map views
/// where the user location should appear toward the bottom of the map.
///
/// This is used to accommodate a top InstructionView
Expand Down
6 changes: 5 additions & 1 deletion apple/Sources/UniFFI/ferrostar.swift

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 11 additions & 6 deletions common/ferrostar/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,21 @@
//!
//! Ferrostar is a modern SDK for building turn-by-turn navigation applications.
//!
//! Check out the [User Guide](https://stadiamaps.github.io/ferrostar/) for an introduction
//! and tutorials for major platforms like iOS and Android.
//! ![A screenshot of Ferrostar running on iOS](https://docs.stadiamaps.com/img/ferrostar-screenshot.png)
//!
//! This is the [core](https://stadiamaps.github.io/ferrostar/architecture.html) of Ferrostar,
//! This crate is the [core](https://stadiamaps.github.io/ferrostar/architecture.html) of Ferrostar,
//! which contains common data models, traits and integrations with common routing backends
//! like Valhalla, spatial algorithms, and the navigation state machine.
//!
//! If you're looking to build a navigation experience for a new platform,
//! or you just want to use the primitives in your existing architecture,
//! this crate is for you.
//! If you're looking to build a navigation experience for a platform
//! where Ferrostar doesn't currently offer a high-level interface,
//! you want to use the primitives in your existing architecture,
//! or you're genuinely curious about the internals,
//! you're in the right spot!
//!
//! And if you're a developer wanting to build a navigation experience in your application,
//! check out the [User Guide](https://stadiamaps.github.io/ferrostar/) for a high-level overview
//! and tutorials for major platforms including iOS and Android.

#![cfg_attr(not(feature = "std"), no_std)]

Expand Down
6 changes: 5 additions & 1 deletion common/ferrostar/src/navigation_controller/models.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,11 @@ pub struct TripProgress {
pub duration_remaining: f64,
}

/// Internal state of the navigation controller.
/// The state of a navigation session.
///
/// This is produced by [`NavigationController`](super::NavigationController) methods
/// including [`get_initial_state`](super::NavigationController::get_initial_state)
/// and [`update_user_location`](super::NavigationController::update_user_location).
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "uniffi", derive(uniffi::Enum))]
#[cfg_attr(feature = "wasm-bindgen", derive(Serialize, Deserialize))]
Expand Down
52 changes: 52 additions & 0 deletions guide/src/web-getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,9 @@ Here are the most important ones:
- `valhallaEndpointUrl`: The Valhalla routing endpoint to use. You can use any reasonably up-to-date Valhalla server, including your own. See [vendors](./vendor.md#routing) for a list of known compatible vendors.
- `httpClient`: You can set your own fetch-compatible HTTP client to make requests to the routing API (ex: Valhalla).
- `costingOptions`: You can set the costing options for the route provider (ex: Valhalla JSON options).
- `locationProvider`: Provides locations to the navigation controller.
`SimulatedLocationProvider` and `BrowserLocationProvider` are included.
See the demo app for an example of how to simulate a route.
- `configureMap`: Configures the map on first load. This lets you customize the UI, add MapLibre map controls, etc. on load.
- `onNavigationStart`: Callback when navigation starts.
- `onNavigationStop`: Callback when navigation ends.
Expand Down Expand Up @@ -115,6 +118,7 @@ In Vue, you can write “markup” in your components like this!
valhallaEndpointUrl="https://api.stadiamaps.com/route/v1"
styleUrl="https://tiles.stadiamaps.com/styles/outdoors.json"
profile="bicycle"
:location-provider="new BrowserLocationProvider()"
:center="{lng: -122.42, lat: 37.81}"
:zoom=18
:useVoiceGuidance=true
Expand All @@ -126,6 +130,54 @@ NOTE: The JavaScript API is currently limited to Valhalla,
but support for arbitrary providers (like we already have on iOS and Android)
is [tracked in this issue](https://github.com/stadiamaps/ferrostar/issues/191).

## Acquiring the user’s location

The `BrowserLocationProvider` includes a convenience function
to get the user’s location asynchronously (using a cached one if available).
Use this to get the user’s location in the correct format.

```typescript
const location = await ferrostar.locationProvider.getCurrentLocation();
```

## Getting routes

Once you have acquired the user’s location and have one or more waypoints to navigate to,
it’s time to get some routes!

```typescript
// Use the acquired user location to request the route
const routes = await ferrostar.getRoutes(location, waypoints);

// Select one of the routes; here we just pick the first one.
const route = routes[0];
```

## Starting navigation

Finally, we can start navigating!
We’re still working on getting full documentation generated in the typescript wrapper,
but in the meantime, the [Rust docs](https://docs.rs/ferrostar/latest/ferrostar/navigation_controller/models/struct.NavigationControllerConfig.html)
describe the available options.

```typescript
ferrostar.startNavigation(route, {
stepAdvance: {
RelativeLineStringDistance: {
minimumHorizontalAccuracy: 25,
automaticAdvanceDistance: 10,
},
},
routeDeviationTracking: {
StaticThreshold: {
minimumHorizontalAccuracy: 25,
maxAcceptableDeviation: 10.0,
},
},
snappedLocationCourseFiltering: "Raw",
});
```

## Demo app

We've put together a minimal demo app with an example integration.
Expand Down
38 changes: 34 additions & 4 deletions web/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
valhallaEndpointUrl="https://api.stadiamaps.com/route/v1"
styleUrl="https://tiles.stadiamaps.com/styles/outdoors.json"
profile="bicycle"
useIntegratedSearchBox="true"
></ferrostar-map>

<script type="module">
Expand All @@ -53,14 +52,45 @@
};

async function onload() {
// Get a reference to the Ferrostar map component
const ferrostar = document.getElementById("ferrostar");

// Create a search control.
const searchBox = new MapLibreSearchControl({
onResultSelected: async (feature) => {
await ferrostar.startNavigationFromSearch(feature.geometry.coordinates);
const coordinates = feature.geometry.coordinates;
const waypoints = [{ coordinate: { lat: coordinates[1], lng: coordinates[0] }, kind: "Break" }];

// FIXME: This is a hack basically to support the demo page that should go away.
if (!ferrostar.locationProvider || ferrostar.locationProvider instanceof SimulatedLocationProvider) {
ferrostar.locationProvider = new BrowserLocationProvider();
}

const location = await ferrostar.locationProvider.getCurrentLocation();

// Use the acquired user location to request the route
const routes = await ferrostar.getRoutes(location, waypoints);
const route = routes[0];

// Start the navigation
ferrostar.startNavigation(route, {
stepAdvance: {
RelativeLineStringDistance: {
minimumHorizontalAccuracy: 25,
automaticAdvanceDistance: 10,
},
},
routeDeviationTracking: {
StaticThreshold: {
minimumHorizontalAccuracy: 25,
maxAcceptableDeviation: 10.0,
},
},
snappedLocationCourseFiltering: "Raw",
});
},
});

const ferrostar = document.getElementById("ferrostar");

ferrostar.center = {lng: -122.42, lat: 37.81};
ferrostar.zoom = 18;
ferrostar.costingOptions = { bicycle: { use_roads: 0.2 } };
Expand Down
2 changes: 1 addition & 1 deletion web/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

59 changes: 16 additions & 43 deletions web/src/ferrostar-map.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,21 @@
import {css, html, LitElement, PropertyValues, unsafeCSS} from "lit";
import {customElement, property, state} from "lit/decorators.js";
import maplibregl, {GeolocateControl, LngLatLike, Map} from "maplibre-gl";
import maplibregl, {
GeolocateControl,
LngLat,
LngLatLike,
Map
} from "maplibre-gl";
import maplibreglStyles from "maplibre-gl/dist/maplibre-gl.css?inline";
import {NavigationController, RouteAdapter} from "@stadiamaps/ferrostar";
import "./instructions-view";
import "./arrival-view";
import {BrowserLocationProvider, SimulatedLocationProvider} from "./location";
import {SimulatedLocationProvider} from "./location";
import CloseSvg from "./assets/directions/close.svg";

/**
* A MapLibre-based map component specialized for navigation.
*/
@customElement("ferrostar-map")
export class FerrostarMap extends LitElement {
@property()
Expand Down Expand Up @@ -157,7 +165,11 @@ export class FerrostarMap extends LitElement {
if (changedProperties.get("center") === null && this.center !== null) {
this.map.jumpTo({center: this.center})
} else if (this.center !== null) {
this.map.flyTo({center: this.center})
if (this.map.getCenter().distanceTo(LngLat.convert(this.center)) > 500_000) {
this.map.jumpTo({center: this.center});
} else {
this.map.flyTo({center: this.center});
}
}
}
if (changedProperties.has("pitch")) {
Expand Down Expand Up @@ -226,6 +238,7 @@ export class FerrostarMap extends LitElement {

// TODO: type
startNavigation(route: any, config: any) {
this.locationProvider.start();
if (this.onNavigationStart && this.map) this.onNavigationStart(this.map);

// Initialize the navigation controller
Expand Down Expand Up @@ -285,46 +298,6 @@ export class FerrostarMap extends LitElement {
}
}

async startNavigationFromSearch(coordinates: any) {
const waypoints = [{ coordinate: { lat: coordinates[1], lng: coordinates[0] }, kind: "Break" }];

// FIXME: This is a hack basically to support the demo page that should go away.
if (!this.locationProvider || this.locationProvider instanceof SimulatedLocationProvider) {
this.locationProvider = new BrowserLocationProvider();
}

this.locationProvider.start();

// TODO: Replace this with a promise or callback
while (!this.locationProvider.lastLocation) {
await new Promise((resolve) => setTimeout(resolve, 100));
}

// Use the acquired user location to request the route
const routes = await this.getRoutes(this.locationProvider.lastLocation, waypoints);
const route = routes[0];

// TODO: type + use TypeScript enum
const config = {
stepAdvance: {
RelativeLineStringDistance: {
minimumHorizontalAccuracy: 25,
automaticAdvanceDistance: 10,
},
},
routeDeviationTracking: {
StaticThreshold: {
minimumHorizontalAccuracy: 25,
maxAcceptableDeviation: 10.0,
},
},
snappedLocationCourseFiltering: "Raw",
};

// Start the navigation
this.startNavigation(route, config);
}

async stopNavigation() {
// TODO: Factor out the UI layer from the core
this.routeAdapter?.free();
Expand Down
Loading
Loading