JS Mojo Geocoder Demo
Added a JS example that demos encapsulating Google's geocoder web service with a Mojo application.
BUG=
R=eseidel@chromium.org
Review URL: https://codereview.chromium.org/848213003
diff --git a/examples/js/maps/BUILD.gn b/examples/js/maps/BUILD.gn
new file mode 100644
index 0000000..d10a973
--- /dev/null
+++ b/examples/js/maps/BUILD.gn
@@ -0,0 +1,17 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//mojo/public/tools/bindings/mojom.gni")
+
+group("maps") {
+ deps = [
+ ":bindings",
+ ]
+}
+
+mojom("bindings") {
+ sources = [
+ "geocoder.mojom",
+ ]
+}
diff --git a/examples/js/maps/demo.js b/examples/js/maps/demo.js
new file mode 100644
index 0000000..aa6e783
--- /dev/null
+++ b/examples/js/maps/demo.js
@@ -0,0 +1,79 @@
+#!mojo mojo:js_content_handler
+// Demonstate a Mojo wrapper for the Geocoder JSON API. The application
+// connects to geocoder_service.js which implements geocoder.mojom.
+// To run this application with mojo_shell, set DIR to be the absolute path
+// for this directory, then:
+// mojo_shell file://$DIR/demo.js
+
+define("main", [
+ "console",
+ "examples/js/maps/geocoder.mojom",
+ "mojo/public/js/core",
+ "mojo/public/js/unicode",
+ "mojo/services/public/js/application",
+ "third_party/js/url",
+], function(console, geocoder, core, unicode, application, url) {
+
+ const Application = application.Application;
+ const Geocoder = geocoder.Geocoder;
+ const Result = geocoder.Result;
+ const Location = geocoder.Location;
+ const Status = geocoder.Status;
+ const Options = geocoder.Options;
+ const URL = url.URL;
+
+ var geocoderService;
+
+ function demoAddressToLocation() {
+ console.log("Demo GeocoderServce.AddressToLocation()");
+ var addr = "1365 Shorebird way, Mountain View, CA";
+ geocoderService.addressToLocation(addr, new Options).then(
+ function(rv) {
+ if (rv.status == Status.OK) {
+ for (var i = 0; i < rv.results.length; i++) {
+ var address = rv.results[i].formatted_address;
+ var location = rv.results[i].geometry.location;
+ console.log("Latitude,longitude for \"" + address + "\":");
+ console.log(location.latitude + ", " + location.longitude);
+
+ console.log("");
+ demoLocationToAddress();
+ }
+ } else {
+ console.log("Geocoder request failed status=" + rv.status);
+ }
+ });
+ }
+
+ function demoLocationToAddress() {
+ console.log("Demo GeocoderServce.LocationToAddress()");
+ var coords = new Location({
+ latitude: 37.41811752319336,
+ longitude: -122.07335662841797,
+ });
+ geocoderService.locationToAddress(coords, new Options).then(
+ function(rv) {
+ if (rv.status == Status.OK) {
+ for (var i = 0; i < rv.results.length; i++) {
+ var address = rv.results[i].formatted_address;
+ var location = rv.results[i].geometry.location;
+ console.log("Latitude,longitude for \"" + address + "\":");
+ console.log(location.latitude + ", " + location.longitude);
+ }
+ } else {
+ console.log("Geocoder request failed status=" + rv.status);
+ }
+ });
+ }
+
+ class Demo extends Application {
+ initialize() {
+ var geocoderURL = new URL(this.url).resolve("geocoder_service.js");
+ geocoderService = this.shell.connectToService(geocoderURL, Geocoder);
+ demoAddressToLocation();
+ }
+ }
+
+ return Demo;
+});
+
diff --git a/examples/js/maps/geocoder.mojom b/examples/js/maps/geocoder.mojom
new file mode 100644
index 0000000..d7cbe4c
--- /dev/null
+++ b/examples/js/maps/geocoder.mojom
@@ -0,0 +1,68 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// All of the types that follow are simple mappings of the types defined by the
+// "Google Maps JavaScript API v3" defined here:
+// https://developers.google.com/maps/documentation/javascript/geocoding
+
+module geocoder;
+
+struct Location {
+ float latitude;
+ float longitude;
+};
+
+struct LocationType {
+ const string ROOFTOP = "ROOFTOP";
+ const string RANGE_INTERPOLATED = "RANGE_INTERPOLATED";
+ const string GEOMETRIC_CENTER = "GEOMETRIC_CENTER";
+ const string APPROXIMATE = "APPROXIMATE";
+};
+
+struct Bounds {
+ Location northeast;
+ Location southwest;
+};
+
+struct ComponentRestrictions {
+ string? administrative_area;
+ string? country;
+ string? locality;
+ string? postal_code;
+ string? route;
+};
+
+struct Options {
+ ComponentRestrictions? restrictions;
+ Location? location;
+ string? region;
+};
+
+struct Geometry {
+ Location location;
+ LocationType location_type;
+ Bounds viewport;
+ Bounds? bounds;
+};
+
+struct Result {
+ bool partial_match;
+ Geometry geometry;
+ string formatted_address;
+ array<string> types;
+ // TBD address_components
+};
+
+struct Status {
+ const string OK = "OK";
+ const string ZERO_RESULTS = "ZERO_RESULTS";
+ const string OVER_QUERY_LIMIT = "OVER_QUERY_LIMIT";
+ const string REQUEST_DENIED = "REQUEST_DENIED";
+ const string INVALID_REQUEST = "INVALID_REQUEST";
+};
+
+interface Geocoder {
+ AddressToLocation(string address, Options? options) => (string status, array<Result>? results);
+ LocationToAddress(Location location, Options? options) => (string status, array<Result>? results);
+};
diff --git a/examples/js/maps/geocoder_service.js b/examples/js/maps/geocoder_service.js
new file mode 100644
index 0000000..351a460
--- /dev/null
+++ b/examples/js/maps/geocoder_service.js
@@ -0,0 +1,128 @@
+#!mojo mojo:js_content_handler
+
+define("main", [
+ "console",
+ "examples/js/maps/geocoder.mojom",
+ "mojo/public/js/core",
+ "mojo/public/js/unicode",
+ "mojo/services/public/js/application",
+ "mojo/services/network/public/interfaces/network_service.mojom",
+ "mojo/services/network/public/interfaces/url_loader.mojom",
+ "third_party/js/url",
+], function(console, geocoder, core, unicode, application, network, loader, url) {
+
+ const Application = application.Application;
+ const Bounds = geocoder.Bounds;
+ const Geocoder = geocoder.Geocoder;
+ const Geometry = geocoder.Geometry;
+ const Location = geocoder.Location;
+ const NetworkService = network.NetworkService;
+ const Result = geocoder.Result;
+ const Status = geocoder.Status;
+ const URLRequest = loader.URLRequest;
+ const URL = url.URL;
+
+ var netService;
+
+ Location.prototype.queryString = function() {
+ // TBD: format floats to 6 decimal places
+ return this.latitude + ", " + this.longitude;
+ }
+
+ Location.fromJSON = function(json) {
+ return !json ? null : new Location({
+ latitude: json.lat,
+ longitude: json.lng,
+ });
+ }
+
+ Bounds.fromJSON = function(json) {
+ return !json ? null : new Bounds({
+ northeast: Location.fromJSON(json.northeast),
+ southwest: Location.fromJSON(json.southwest),
+ });
+ }
+
+ Geometry.fromJSON = function(json) {
+ return !json ? null : new Geometry({
+ location: Location.fromJSON(json.location),
+ location_type: json.location_type,
+ viewport: Bounds.fromJSON(json.viewport),
+ bounds: Bounds.fromJSON(json.bounds),
+ });
+ }
+
+ Result.fromJSON = function(json) {
+ return !json ? null : new Result({
+ partial_match: !!json.partial_match,
+ formatted_address: json.formatted_address,
+ geometry: Geometry.fromJSON(json.geometry),
+ types: json.types,
+ // TBD: address_components
+ });
+ }
+
+ function parseGeocodeResponse(arrayBuffer) {
+ return JSON.parse(unicode.decodeUtf8String(new Uint8Array(arrayBuffer)));
+ }
+
+ function geocodeRequest(url) {
+ return new Promise(function(resolveRequest) {
+ var urlLoader;
+ netService.createURLLoader(function(urlLoaderProxy) {
+ urlLoader = urlLoaderProxy;
+ });
+
+ var urlRequest = new URLRequest({
+ url: url.format(),
+ method: "GET",
+ auto_follow_redirects: true
+ });
+
+ urlLoader.start(urlRequest).then(function(urlLoaderResult) {
+ core.drainData(urlLoaderResult.response.body).then(
+ function(drainDataResult) {
+ // TBD: handle drainData failure
+ var value = parseGeocodeResponse(drainDataResult.buffer);
+ resolveRequest({
+ status: value.status,
+ results: value.results.map(Result.fromJSON),
+ });
+ });
+ });
+ });
+ }
+
+ function geocodeURL(key, value, options) {
+ var url = new URL("https://maps.googleapis.com/maps/api/geocode/json");
+ url.query = {};
+ url.query[key] = value;
+ // TBD: add options url.query
+ return url;
+ }
+
+ class GeocoderImpl {
+ addressToLocation(address, options) {
+ return geocodeRequest(geocodeURL("address", address, options));
+ }
+
+ locationToAddress(location, options) {
+ return geocodeRequest(
+ geocodeURL("latlng", location.queryString(), options));
+ }
+ }
+
+ class GeocoderService extends Application {
+ initialize() {
+ netService = this.shell.connectToService(
+ "mojo:network_service", NetworkService);
+ }
+
+ acceptConnection(initiatorURL, serviceProvider) {
+ serviceProvider.provideService(Geocoder, GeocoderImpl);
+ }
+ }
+
+ return GeocoderService;
+});
+