Unverified Commit 2ade5c0e authored by rgangela99's avatar rgangela99 Committed by GitHub

Implement a Navigation component (#1938)


Change-Id: Iaae8b8ca29b2006953b2283e305167eeba6b8588
Co-authored-by: default avatarEvan W. Patton <ewpatton@mit.edu>
parent d8db3d56
......@@ -648,6 +648,12 @@ public interface Images extends Resources {
@Source("com/google/appinventor/images/mediaIcon_video.png")
ImageResource mediaIconVideo();
/**
* Designer palette item:
*/
@Source("com/google/appinventor/images/navigation.png")
ImageResource navigationComponent();
/**
* Wilson Logo
*/
......@@ -665,5 +671,4 @@ public interface Images extends Resources {
*/
@Source("com/google/appinventor/images/YRLogo.png")
ImageResource YRLogo();
}
......@@ -5197,4 +5197,22 @@ public interface OdeMessages extends Messages, AutogeneratedOdeMessages {
"<br/>These applications will not run on Android versions older than 4.0.")
@Description("Text for the Package SDK 26 Warning Dialog Box (HTML)")
String Package26Notice();
// Navigation component
@DefaultMessage("Walking")
@Description("The label used to indicate walking navigation.")
String WalkingNavMethod();
@DefaultMessage("Driving")
@Description("The label used to indicate driving navigation.")
String DrivingNavMethod();
@DefaultMessage("Cycling")
@Description("The label used to indicate cycling navigation.")
String CyclingNavMethod();
@DefaultMessage("Wheelchair")
@Description("The label used to indicate wheelchair navigation.")
String WheelchairNavMethod();
}
......@@ -32,6 +32,7 @@ import com.google.appinventor.client.editor.youngandroid.properties.YoungAndroid
import com.google.appinventor.client.editor.youngandroid.properties.YoungAndroidLegoNxtSensorPortChoicePropertyEditor;
import com.google.appinventor.client.editor.youngandroid.properties.YoungAndroidMapScaleUnitsPropertyEditor;
import com.google.appinventor.client.editor.youngandroid.properties.YoungAndroidMapTypePropertyEditor;
import com.google.appinventor.client.editor.youngandroid.properties.YoungAndroidNavigationMethodChoicePropertyEditor;
import com.google.appinventor.client.editor.youngandroid.properties.YoungAndroidScreenAnimationChoicePropertyEditor;
import com.google.appinventor.client.editor.youngandroid.properties.YoungAndroidScreenOrientationChoicePropertyEditor;
import com.google.appinventor.client.editor.youngandroid.properties.YoungAndroidSensorDistIntervalChoicePropertyEditor;
......@@ -228,6 +229,8 @@ public class PropertiesUtil {
return new YoungAndroidMapScaleUnitsPropertyEditor();
} else if (editorType.equals(PropertyTypeConstants.PROPERTY_TYPE_MAP_ZOOM)) {
return new YoungAndroidIntegerRangePropertyEditor(1, 18);
} else if (editorType.equals(PropertyTypeConstants.PROPERTY_TYPE_NAVIGATION_METHOD)) {
return new YoungAndroidNavigationMethodChoicePropertyEditor();
} else if (editorType.equals(PropertyTypeConstants.PROPERTY_TYPE_NON_NEGATIVE_FLOAT)) {
return new NonNegativeFloatPropertyEditor();
} else if (editorType.equals(PropertyTypeConstants.PROPERTY_TYPE_NON_NEGATIVE_INTEGER)) {
......
......@@ -168,6 +168,7 @@ public final class SimpleComponentDescriptor {
bundledImages.put("images/linestring.png", images.linestring());
bundledImages.put("images/polygon.png", images.polygon());
bundledImages.put("images/featurecollection.png", images.featurecollection());
bundledImages.put("images/navigation.png", images.navigationComponent());
imagesInitialized = true;
}
......
// -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2019 MIT, All rights reserved
// Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0
package com.google.appinventor.client.editor.youngandroid.properties;
import com.google.appinventor.client.widgets.properties.ChoicePropertyEditor;
import com.google.appinventor.components.common.ComponentConstants;
import static com.google.appinventor.client.Ode.MESSAGES;
/**
* Property editor for navigation method choice.
*/
public class YoungAndroidNavigationMethodChoicePropertyEditor extends ChoicePropertyEditor {
private static final Choice[] methods = new Choice[] {
new Choice(MESSAGES.WalkingNavMethod(), "foot-walking"),
new Choice(MESSAGES.DrivingNavMethod(), "driving-car"),
new Choice(MESSAGES.CyclingNavMethod(), "cycling-regular"),
new Choice (MESSAGES.WheelchairNavMethod(), "wheelchair")
};
public YoungAndroidNavigationMethodChoicePropertyEditor() {
super(methods);
}
}
......@@ -1443,6 +1443,7 @@ Blockly.ComponentBlock.HELPURLS = {
"FeatureCollection": Blockly.Msg.LANG_COMPONENT_BLOCK_MAPS_FEATURECOLLECTION_HELPURL,
"LineString": Blockly.Msg.LANG_COMPONENT_BLOCK_MAPS_LINESTRING_HELPURL,
"Marker": Blockly.Msg.LANG_COMPONENT_BLOCK_MAPS_MARKER_HELPURL,
"Navigation": Blockly.Msg.LANG_COMPONENT_BLOCK_MAPS_NAVIGATION_HELPURL,
"Polygon": Blockly.Msg.LANG_COMPONENT_BLOCK_MAPS_POLYGON_HELPURL,
"Rectangle": Blockly.Msg.LANG_COMPONENT_BLOCK_MAPS_RECTANGLE_HELPURL,
"ContactPicker": Blockly.Msg.LANG_COMPONENT_BLOCK_CONTACTPICKER_HELPURL,
......@@ -1533,6 +1534,7 @@ Blockly.ComponentBlock.PROPERTIES_HELPURLS = {
"FeatureCollection": Blockly.Msg.LANG_COMPONENT_BLOCK_MAPS_FEATURECOLLECTION_HELPURL,
"LineString": Blockly.Msg.LANG_COMPONENT_BLOCK_MAPS_LINESTRING_HELPURL,
"Marker": Blockly.Msg.LANG_COMPONENT_BLOCK_MAPS_MARKER_HELPURL,
"Navigation": Blockly.Msg.LANG_COMPONENT_BLOCK_MAPS_NAVIGATION_HELPURL,
"Polygon": Blockly.Msg.LANG_COMPONENT_BLOCK_MAPS_POLYGON_HELPURL,
"Rectangle": Blockly.Msg.LANG_COMPONENT_BLOCK_MAPS_RECTANGLE_HELPURL,
"ContactPicker": Blockly.Msg.LANG_COMPONENT_BLOCK_CONTACTPICKER_PROPERTIES_HELPURL,
......@@ -1623,6 +1625,7 @@ Blockly.ComponentBlock.EVENTS_HELPURLS = {
"FeatureCollection": Blockly.Msg.LANG_COMPONENT_BLOCK_MAPS_FEATURECOLLECTION_HELPURL,
"LineString": Blockly.Msg.LANG_COMPONENT_BLOCK_MAPS_LINESTRING_HELPURL,
"Marker": Blockly.Msg.LANG_COMPONENT_BLOCK_MAPS_MARKER_HELPURL,
"Navigation": Blockly.Msg.LANG_COMPONENT_BLOCK_MAPS_NAVIGATION_HELPURL,
"Polygon": Blockly.Msg.LANG_COMPONENT_BLOCK_MAPS_POLYGON_HELPURL,
"Rectangle": Blockly.Msg.LANG_COMPONENT_BLOCK_MAPS_RECTANGLE_HELPURL,
"ContactPicker": Blockly.Msg.LANG_COMPONENT_BLOCK_CONTACTPICKER_EVENTS_HELPURL,
......@@ -1703,6 +1706,7 @@ Blockly.ComponentBlock.METHODS_HELPURLS = {
"FeatureCollection": Blockly.Msg.LANG_COMPONENT_BLOCK_MAPS_FEATURECOLLECTION_HELPURL,
"LineString": Blockly.Msg.LANG_COMPONENT_BLOCK_MAPS_LINESTRING_HELPURL,
"Marker": Blockly.Msg.LANG_COMPONENT_BLOCK_MAPS_MARKER_HELPURL,
"Navigation": Blockly.Msg.LANG_COMPONENT_BLOCK_MAPS_NAVIGATION_HELPURL,
"Polygon": Blockly.Msg.LANG_COMPONENT_BLOCK_MAPS_POLYGON_HELPURL,
"Rectangle": Blockly.Msg.LANG_COMPONENT_BLOCK_MAPS_RECTANGLE_HELPURL,
"ContactPicker": Blockly.Msg.LANG_COMPONENT_BLOCK_CONTACTPICKER_METHODS_HELPURL,
......
......@@ -1344,6 +1344,7 @@ Blockly.Msg.en.switch_language_to_english = {
Blockly.Msg.LANG_COMPONENT_BLOCK_MAPS_FEATURECOLLECTION_HELPURL = "/reference/components/maps.html#FeatureCollection";
Blockly.Msg.LANG_COMPONENT_BLOCK_MAPS_LINESTRING_HELPURL = "/reference/components/maps.html#LineString";
Blockly.Msg.LANG_COMPONENT_BLOCK_MAPS_MARKER_HELPURL = "/reference/components/maps.html#Marker";
Blockly.Msg.LANG_COMPONENT_BLOCK_MAPS_NAVIGATION_HELPURL = "/reference/components/maps.html#Navigation";
Blockly.Msg.LANG_COMPONENT_BLOCK_MAPS_POLYGON_HELPURL = "/reference/components/maps.html#Polygon";
Blockly.Msg.LANG_COMPONENT_BLOCK_MAPS_RECTANGLE_HELPURL = "/reference/components/maps.html#Rectangle";
......
......@@ -315,4 +315,10 @@ public class PropertyTypeConstants {
* See {@link com.google.appinventor.client.editor.youngandroid.properties.YoungAndroidThemeChoicePropertyEditor}
*/
public static final String PROPERTY_TYPE_THEME = "theme";
/**
* Choices of navigation methods. {@link
* com.google.appinventor.client.editor.youngandroid.properties.YoungAndroidNavigationMethodChoicePropertyEditor}
*/
public static final String PROPERTY_TYPE_NAVIGATION_METHOD = "navigation_method";
}
......@@ -503,8 +503,10 @@ public class YaVersion {
// - BLOCKS_LANGUAGE_VERSION was incremented to 30
// For YOUNG_ANDROID_VERSION 203:
// - WEBVIEWER_COMPONENT_VERSION was incremented to 9
// For YOUNG_ANDROID_VERSION 204:
// - NAVIGATION_COMPONENT_VERSION was initialized to 1
public static final int YOUNG_ANDROID_VERSION = 203;
public static final int YOUNG_ANDROID_VERSION = 204;
// ............................... Blocks Language Version Number ...............................
......@@ -1005,6 +1007,10 @@ public class YaVersion {
// - Added fill and stroke opacity properties
public static final int MARKER_COMPONENT_VERSION = 3;
// For NAVIGATION_COMPONENT_VERSION 1:
// - Initial Navigation implementation
public static final int NAVIGATION_COMPONENT_VERSION = 1;
// For NEARFIELD_COMPONENT_VERSION 1:
public static final int NEARFIELD_COMPONENT_VERSION = 1;
......
......@@ -34,6 +34,8 @@ import java.util.List;
import java.util.ListIterator;
import java.util.concurrent.CopyOnWriteArrayList;
import static com.google.appinventor.components.runtime.util.GeoJSONUtil.getGeoJSONFeatures;
import static com.google.appinventor.components.runtime.util.GeoJSONUtil.getGeoJSONType;
import static com.google.appinventor.components.runtime.util.GeoJSONUtil.processGeoJSONFeature;
@SimpleObject
......@@ -438,8 +440,7 @@ public abstract class MapFeatureContainerBase extends AndroidViewComponent imple
@SuppressWarnings("WeakerAccess")
protected void processGeoJSON(final String url, final String content) throws JSONException {
JSONObject parsedData = new JSONObject(stripBOM(content));
String type = parsedData.optString(GEOJSON_TYPE);
String type = getGeoJSONType(content, GEOJSON_TYPE);
if (!GEOJSON_FEATURECOLLECTION.equals(type) && !GEOJSON_GEOMETRYCOLLECTION.equals(type)) {
$form().runOnUiThread(new Runnable() {
public void run() {
......@@ -449,71 +450,11 @@ public abstract class MapFeatureContainerBase extends AndroidViewComponent imple
});
return;
}
JSONArray features = parsedData.getJSONArray(GEOJSON_FEATURES);
final List<YailList> yailFeatures = new ArrayList<YailList>();
for (int i = 0; i < features.length(); i++) {
yailFeatures.add(jsonObjectToYail(features.getJSONObject(i)));
}
final List<YailList> yailFeatures = getGeoJSONFeatures(TAG, content);
$form().runOnUiThread(new Runnable() {
public void run() {
MapFeatureContainerBase.this.GotFeatures(url, YailList.makeList(yailFeatures));
}
});
}
private YailList jsonObjectToYail(JSONObject object) throws JSONException {
List<YailList> pairs = new ArrayList<YailList>();
@SuppressWarnings("unchecked") // json only allows String keys
Iterator<String> j = object.keys();
while (j.hasNext()) {
String key = j.next();
Object value = object.get(key);
if (value instanceof Boolean ||
value instanceof Integer ||
value instanceof Long ||
value instanceof Double ||
value instanceof String) {
pairs.add(YailList.makeList(new Object[] { key, value }));
} else if (value instanceof JSONArray) {
pairs.add(YailList.makeList(new Object[] { key, jsonArrayToYail((JSONArray) value)}));
} else if (value instanceof JSONObject) {
pairs.add(YailList.makeList(new Object[] { key, jsonObjectToYail((JSONObject) value)}));
} else if (!JSONObject.NULL.equals(value)) {
Log.wtf(TAG, ERROR_UNKNOWN_TYPE + ": " + value.getClass());
throw new IllegalArgumentException(ERROR_UNKNOWN_TYPE);
}
}
return YailList.makeList(pairs);
}
private YailList jsonArrayToYail(JSONArray array) throws JSONException {
List<Object> items = new ArrayList<Object>();
for (int i = 0; i < array.length(); i++) {
Object value = array.get(i);
if (value instanceof Boolean ||
value instanceof Integer ||
value instanceof Long ||
value instanceof Double ||
value instanceof String) {
items.add(value);
} else if (value instanceof JSONArray) {
items.add(jsonArrayToYail((JSONArray) value));
} else if (value instanceof JSONObject) {
items.add(jsonObjectToYail((JSONObject) value));
} else if (!JSONObject.NULL.equals(value)) {
Log.wtf(TAG, ERROR_UNKNOWN_TYPE + ": " + value.getClass());
throw new IllegalArgumentException(ERROR_UNKNOWN_TYPE);
}
}
return YailList.makeList(items);
}
private static String stripBOM(String content) {
if (content.charAt(0) == '\uFEFF') {
return content.substring(1);
} else {
return content;
}
}
}
......@@ -269,7 +269,13 @@ public final class ErrorMessages {
public static final int ERROR_SERVER = 3808;
public static final int ERROR_SPEECH_TIMEOUT = 3809;
// Start the next group of errors at 3900
// Navigation Errors
public static final int ERROR_INVALID_API_KEY = 4001;
public static final int ERROR_UNABLE_TO_REQUEST_DIRECTIONS = 4002;
public static final int ERROR_ROUTING_SERVICE_ERROR = 4003;
public static final int ERROR_NO_ROUTE_FOUND = 4004;
// Start the next group of errors at 4100
// Mapping of error numbers to error message format strings.
private static final Map<Integer, String> errorMessages;
......@@ -669,6 +675,13 @@ public final class ErrorMessages {
errorMessages.put(ERROR_RECOGNIZER_BUSY, "RecognitionService Busy");
errorMessages.put(ERROR_SERVER, "Error From Server");
errorMessages.put(ERROR_SPEECH_TIMEOUT, "No Speech Input");
// Navigation Errors
errorMessages.put(ERROR_INVALID_API_KEY, "No api key provided");
errorMessages.put(ERROR_UNABLE_TO_REQUEST_DIRECTIONS,
"Unable to request directions. Reason: %s");
errorMessages.put(ERROR_ROUTING_SERVICE_ERROR, "Routing service failed with status %d %s");
errorMessages.put(ERROR_NO_ROUTE_FOUND, "No route returned by the routing service.");
}
private ErrorMessages() {
......
......@@ -22,7 +22,9 @@ import com.google.common.annotations.VisibleForTesting;
import gnu.lists.FString;
import gnu.lists.LList;
import gnu.lists.Pair;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.osmdroid.util.GeoPoint;
import java.io.FileOutputStream;
......@@ -43,9 +45,15 @@ import static com.google.appinventor.components.runtime.Component.*;
*/
public final class GeoJSONUtil {
private static final java.util.Map<String, Integer> colors;
private static final int ERROR_CODE_MALFORMED_GEOJSON = -3;
private static final String ERROR_MALFORMED_GEOJSON = "Malformed GeoJSON response. Expected FeatureCollection as root element.";
private static final String ERROR_UNKNOWN_TYPE = "Unrecognized/invalid type in JSON object";
private static final String GEOJSON_COORDINATES = "coordinates";
private static final String GEOJSON_FEATURE = "Feature";
private static final String GEOJSON_FEATURECOLLECTION = "FeatureCollection";
private static final String GEOJSON_FEATURES = "features";
private static final String GEOJSON_GEOMETRY = "geometry";
private static final String GEOJSON_GEOMETRYCOLLECTION = "GeometryCollection";
private static final String GEOJSON_PROPERTIES = "properties";
private static final String GEOJSON_TYPE = "type";
private static final String PROPERTY_ANCHOR_HORIZONTAL = "anchorHorizontal";
......@@ -442,6 +450,77 @@ public final class GeoJSONUtil {
}
}
public static List<YailList> getGeoJSONFeatures(final String logTag, final String content) throws JSONException {
JSONObject parsedData = new JSONObject(stripBOM(content));
JSONArray features = parsedData.getJSONArray(GEOJSON_FEATURES);
List<YailList> yailFeatures = new ArrayList<YailList>();
for (int i = 0; i < features.length(); i++) {
yailFeatures.add(jsonObjectToYail(logTag, features.getJSONObject(i)));
}
return yailFeatures;
}
public static String getGeoJSONType(final String content, final String geojsonType) throws JSONException {
JSONObject parsedData = new JSONObject(stripBOM(content));
String type = parsedData.optString(geojsonType);
return type;
}
private static YailList jsonObjectToYail(final String logTag, final JSONObject object) throws JSONException {
List<YailList> pairs = new ArrayList<YailList>();
@SuppressWarnings("unchecked") // json only allows String keys
Iterator<String> j = object.keys();
while (j.hasNext()) {
String key = j.next();
Object value = object.get(key);
if (value instanceof Boolean ||
value instanceof Integer ||
value instanceof Long ||
value instanceof Double ||
value instanceof String) {
pairs.add(YailList.makeList(new Object[] { key, value }));
} else if (value instanceof JSONArray) {
pairs.add(YailList.makeList(new Object[] { key, jsonArrayToYail(logTag, (JSONArray) value)}));
} else if (value instanceof JSONObject) {
pairs.add(YailList.makeList(new Object[] { key, jsonObjectToYail(logTag, (JSONObject) value)}));
} else if (!JSONObject.NULL.equals(value)) {
Log.wtf(logTag, ERROR_UNKNOWN_TYPE + ": " + value.getClass());
throw new IllegalArgumentException(ERROR_UNKNOWN_TYPE);
}
}
return YailList.makeList(pairs);
}
private static YailList jsonArrayToYail(final String logTag, final JSONArray array) throws JSONException {
List<Object> items = new ArrayList<Object>();
for (int i = 0; i < array.length(); i++) {
Object value = array.get(i);
if (value instanceof Boolean ||
value instanceof Integer ||
value instanceof Long ||
value instanceof Double ||
value instanceof String) {
items.add(value);
} else if (value instanceof JSONArray) {
items.add(jsonArrayToYail(logTag, (JSONArray) value));
} else if (value instanceof JSONObject) {
items.add(jsonObjectToYail(logTag, (JSONObject) value));
} else if (!JSONObject.NULL.equals(value)) {
Log.wtf(logTag, ERROR_UNKNOWN_TYPE + ": " + value.getClass());
throw new IllegalArgumentException(ERROR_UNKNOWN_TYPE);
}
}
return YailList.makeList(items);
}
private static String stripBOM(String content) {
if (content.charAt(0) == '\uFEFF') {
return content.substring(1);
} else {
return content;
}
}
private static final class FeatureWriter implements MapFactory.MapFeatureVisitor<Void> {
private final PrintStream out;
......@@ -721,6 +800,15 @@ public final class GeoJSONUtil {
return coordinates;
}
public static <E> List<List<E>> swapCoordinates2(List<List<E>> coordinates) {
for (List<E> point : coordinates) {
E temp = point.get(0);
point.set(0, point.get(1));
point.set(1, temp);
}
return coordinates;
}
public static LList swapNestedCoordinates(LList coordinates) {
LList it = coordinates;
while (!it.isEmpty()) {
......
......@@ -136,6 +136,7 @@
<li><a href="#LineString">LineString</a></li>
<li><a href="#Map">Map</a></li>
<li><a href="#Marker">Marker</a></li>
<li><a href="#Navigation">Navigation</a></li>
<li><a href="#Polygon">Polygon</a></li>
<li><a href="#Rectangle">Rectangle</a></li>
</ul>
......@@ -751,6 +752,75 @@
This method can be used to show the info box even if <a href="#Marker.EnableInfobox"><code class="highlighter-rouge">EnableInfobox</code></a> is false.</dd>
</dl>
<h2 id="Navigation">Navigation</h2>
<p>The Navigation component generates directions between two locations using a service called
<a href="https://openrouteservice.org">OpenRouteService</a>. You must provide a valid API key from that
service in order for this component to work.</p>
<h3 id="Navigation-Properties">Properties</h3>
<dl class="properties">
<dt id="Navigation.ApiKey" class="text wo"><em>ApiKey</em></dt>
<dd>API Key for Open Route Service. Obtain an API key at
<a href="https://openrouteservice.org">https://openrouteservice.org</a>.</dd>
<dt id="Navigation.EndLatitude" class="number"><em>EndLatitude</em></dt>
<dd>The latitude of the end location.</dd>
<dt id="Navigation.EndLocation" class="component wo bo"><em>EndLocation</em></dt>
<dd>Set the end location.</dd>
<dt id="Navigation.EndLongitude" class="number"><em>EndLongitude</em></dt>
<dd>The longitude of the end location.</dd>
<dt id="Navigation.Language" class="text"><em>Language</em></dt>
<dd>Property for Language</dd>
<dt id="Navigation.ResponseContent" class="dictionary ro bo"><em>ResponseContent</em></dt>
<dd>The raw response from the server. This can be used to access more details beyond what the
<a href="#Navigation.GotDirections"><code class="highlighter-rouge">GotDirections</code></a> event provides.</dd>
<dt id="Navigation.StartLatitude" class="number"><em>StartLatitude</em></dt>
<dd>The latitude of the start location.</dd>
<dt id="Navigation.StartLocation" class="component wo bo"><em>StartLocation</em></dt>
<dd>Set the start location.</dd>
<dt id="Navigation.StartLongitude" class="number"><em>StartLongitude</em></dt>
<dd>The longitude of the start location.</dd>
<dt id="Navigation.TransportationMethod" class="text"><em>TransportationMethod</em></dt>
<dd>The transportation method used for determining the route. Valid options are:
<ul>
<li><code class="highlighter-rouge">foot-walking</code>: Route based on walking paths</li>
<li><code class="highlighter-rouge">driving-car</code>: Route based on vehicle paths</li>
<li><code class="highlighter-rouge">cycling-regular</code>: Route based on bicycle paths</li>
<li><code class="highlighter-rouge">wheelchair</code>: Route based on wheelchair accessible paths</li>
</ul>
</dd>
</dl>
<h3 id="Navigation-Events">Events</h3>
<dl class="events">
<dt id="Navigation.GotDirections">GotDirections(<em class="list">directions</em>,<em class="list">points</em>,<em class="number">distance</em>,<em class="number">duration</em>)</dt>
<dd>Event indicating that a request has finished and has returned data. The following parameters
are provided:
<ul>
<li><code class="highlighter-rouge">directions</code>: A list of text directions, such as “Turn left at Massachusetts Avenue”.</li>
<li><code class="highlighter-rouge">points</code>: A list of (latitude, longitude) points that represent the path to take. This can
be passed to <a href="#LineString.Points"><code class="highlighter-rouge">LineString</code>’s <code class="highlighter-rouge">Points</code></a> to draw the line on a <a href="#Map"><code class="highlighter-rouge">Map</code></a>.</li>
<li><code class="highlighter-rouge">distance</code>: Estimated distance for the route, in meters.</li>
<li><code class="highlighter-rouge">duration</code>: Estimated duration for the route, in seconds.</li>
</ul>
</dd>
</dl>
<h3 id="Navigation-Methods">Methods</h3>
<dl class="methods">
<dt id="Navigation.RequestDirections" class="method"><i></i> RequestDirections()</dt>
<dd>Request directions from the routing service using the values of <a href="#Navigation.StartLatitude"><code class="highlighter-rouge">StartLatitude</code></a>,
<a href="#Navigation.StartLongitude"><code class="highlighter-rouge">StartLongitude</code></a>, <a href="#Navigation.EndLatitude"><code class="highlighter-rouge">EndLatitude</code></a>, and <a href="#Navigation.EndLongitude"><code class="highlighter-rouge">EndLongitude</code></a>. On success,
the <a href="#Navigation.GotDirections"><code class="highlighter-rouge">GotDirections</code></a> event block will run. If an
error occurs, the error will be reported via the
<a href="userinterface.html#Screen.ErrorOccurred"><code class="highlighter-rouge">Screen's ErrorOccurred</code></a> event.</dd>
</dl>
<h2 id="Polygon">Polygon</h2>
<p><code class="highlighter-rouge">Polygon</code> encloses an arbitrary 2-dimensional area on a <a href="#Map"><code class="highlighter-rouge">Map</code></a>. <code class="highlighter-rouge">Polygon</code>s can be used for
......
......@@ -13,6 +13,7 @@ Table of Contents:
* [LineString](#LineString)
* [Map](#Map)
* [Marker](#Marker)
* [Navigation](#Navigation)
* [Polygon](#Polygon)
* [Rectangle](#Rectangle)
......@@ -748,6 +749,80 @@ The `Marker` component indicates points on a [`Map`](#Map), such as buildings or
: Shows the info box for the `Marker` if it is not visible. Otherwise, this method has no effect.
This method can be used to show the info box even if [`EnableInfobox`](#Marker.EnableInfobox) is false.
## Navigation {#Navigation}
The Navigation component generates directions between two locations using a service called
[OpenRouteService](https://openrouteservice.org). You must provide a valid API key from that
service in order for this component to work.
### Properties {#Navigation-Properties}
{:.properties}
{:id="Navigation.ApiKey" .text .wo} *ApiKey*
: API Key for Open Route Service. Obtain an API key at
[https://openrouteservice.org](https://openrouteservice.org).
{:id="Navigation.EndLatitude" .number} *EndLatitude*
: The latitude of the end location.
{:id="Navigation.EndLocation" .component .wo .bo} *EndLocation*
: Set the end location.
{:id="Navigation.EndLongitude" .number} *EndLongitude*
: The longitude of the end location.
{:id="Navigation.Language" .text} *Language*
: Property for Language
{:id="Navigation.ResponseContent" .dictionary .ro .bo} *ResponseContent*
: The raw response from the server. This can be used to access more details beyond what the
[`GotDirections`](#Navigation.GotDirections) event provides.
{:id="Navigation.StartLatitude" .number} *StartLatitude*
: The latitude of the start location.
{:id="Navigation.StartLocation" .component .wo .bo} *StartLocation*
: Set the start location.
{:id="Navigation.StartLongitude" .number} *StartLongitude*
: The longitude of the start location.
{:id="Navigation.TransportationMethod" .text} *TransportationMethod*
: The transportation method used for determining the route. Valid options are:
- `foot-walking`: Route based on walking paths
- `driving-car`: Route based on vehicle paths
- `cycling-regular`: Route based on bicycle paths
- `wheelchair`: Route based on wheelchair accessible paths
### Events {#Navigation-Events}
{:.events}
{:id="Navigation.GotDirections"} GotDirections(*directions*{:.list},*points*{:.list},*distance*{:.number},*duration*{:.number})
: Event indicating that a request has finished and has returned data. The following parameters
are provided:
- `directions`: A list of text directions, such as "Turn left at Massachusetts Avenue".
- `points`: A list of (latitude, longitude) points that represent the path to take. This can
be passed to [`LineString`'s `Points`](#LineString.Points) to draw the line on a [`Map`](#Map).
- `distance`: Estimated distance for the route, in meters.
- `duration`: Estimated duration for the route, in seconds.
### Methods {#Navigation-Methods}
{:.methods}
{:id="Navigation.RequestDirections" class="method"} <i/> RequestDirections()
: Request directions from the routing service using the values of [`StartLatitude`](#Navigation.StartLatitude),
[`StartLongitude`](#Navigation.StartLongitude), [`EndLatitude`](#Navigation.EndLatitude), and [`EndLongitude`](#Navigation.EndLongitude). On success,
the [`GotDirections`](#Navigation.GotDirections) event block will run. If an
error occurs, the error will be reported via the
[`Screen's ErrorOccurred`](userinterface.html#Screen.ErrorOccurred) event.
## Polygon {#Polygon}
`Polygon` encloses an arbitrary 2-dimensional area on a [`Map`](#Map). `Polygon`s can be used for
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment