[gnome-maps] Refactor location related code into separate classes
- From: Zeeshan Ali Khattak <zeeshanak src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-maps] Refactor location related code into separate classes
- Date: Fri, 12 Apr 2013 01:29:35 +0000 (UTC)
commit d64ca9196892feac50a6df5f612f9d2df196acc2
Author: Zeeshan Ali (Khattak) <zeeshanak gnome org>
Date: Fri Apr 12 03:10:23 2013 +0300
Refactor location related code into separate classes
MapView class is very quickly becoming bloated so better do something
about it already before it becomes totally unmanageable.
src/Makefile-js.am | 4 +-
src/mapLocation.js | 89 ++++++++++++++++++++++
src/mapView.js | 206 +++++++++++----------------------------------------
src/userLocation.js | 119 +++++++++++++++++++++++++++++
4 files changed, 256 insertions(+), 162 deletions(-)
---
diff --git a/src/Makefile-js.am b/src/Makefile-js.am
index d80eaa4..2fe2c1c 100644
--- a/src/Makefile-js.am
+++ b/src/Makefile-js.am
@@ -3,10 +3,12 @@ dist_js_DATA = \
application.js \
main.js \
mainWindow.js \
+ mapLocation.js \
mapView.js \
path.js \
properties.js \
- utils.js
+ utils.js \
+ userLocation.js
BUILT_SOURCES += \
path.js \
diff --git a/src/mapLocation.js b/src/mapLocation.js
new file mode 100644
index 0000000..104f7ab
--- /dev/null
+++ b/src/mapLocation.js
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2011, 2012, 2013 Red Hat, Inc.
+ *
+ * GNOME Maps is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * GNOME Maps is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with GNOME Maps; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Author: Zeeshan Ali (Khattak) <zeeshanak gnome org>
+ */
+
+const Clutter = imports.gi.Clutter;
+const Champlain = imports.gi.Champlain;
+const Geocode = imports.gi.GeocodeGlib;
+
+const Lang = imports.lang;
+const Mainloop = imports.mainloop;
+
+const Utils = imports.utils;
+const Path = imports.path;
+const _ = imports.gettext.gettext;
+
+const MapLocation = new Lang.Class({
+ Name: 'MapLocation',
+
+ _init: function(geocodeLocation, mapView) {
+ this._mapView = mapView;
+ this._view = mapView.view;
+ this.latitude = geocodeLocation.latitude;
+ this.longitude = geocodeLocation.longitude;
+ this.description = geocodeLocation.description;
+ this.accuracy = geocodeLocation.accuracy;
+ },
+
+ goTo: function(animate) {
+ log("Going to " + this.description);
+
+ let zoom = Utils.getZoomLevelForAccuracy(this.accuracy);
+
+ if (!animate) {
+ this._view.center_on(this.latitude, this.longitude);
+ this._view.set_zoom_level(zoom);
+
+ return;
+ }
+
+ /* Lets first ensure that both current and destination location are visible
+ * before we start the animated journey towards destination itself. We do this
+ * to create the zoom-out-then-zoom-in effect that many map implementations
+ * do. This not only makes the go-to animation look a lot better visually but
+ * also give user a good idea of where the destination is compared to current
+ * location.
+ */
+ let locations = new Array();
+ locations[0] = new Geocode.Location({ latitude: this._view.get_center_latitude(),
+ longitude: this._view.get_center_longitude() });
+ locations[1] = this;
+ this._mapView.ensureVisible(locations);
+
+ let anim_completed_id = this._view.connect("animation-completed::go-to", Lang.bind(this,
+ function() {
+ // Apparently the signal is called before animation is really complete so if we don't
+ // zoom in idle, we get a crash. Perhaps a bug in libchamplain?
+ Mainloop.idle_add(Lang.bind(this,
+ function() {
+ this._view.set_zoom_level(zoom);
+ }));
+ this._view.disconnect(anim_completed_id);
+ }));
+ this._view.go_to(this.latitude, this.longitude);
+ },
+
+ addMarker: function(layer) {
+ let marker = new Champlain.Label();
+ marker.set_text(this.description);
+ marker.set_location(this.latitude, this.longitude);
+ layer.add_marker(marker);
+ log("Added marker at " + this.latitude + ", " + this.longitude);
+ },
+});
diff --git a/src/mapView.js b/src/mapView.js
index 9c63f9e..0a047d2 100644
--- a/src/mapView.js
+++ b/src/mapView.js
@@ -35,6 +35,8 @@ const Application = imports.application;
const Properties = imports.properties;
const Utils = imports.utils;
const Path = imports.path;
+const MapLocation = imports.mapLocation;
+const UserLocation = imports.userLocation;
const _ = imports.gettext.gettext;
const MapType = {
@@ -52,20 +54,20 @@ const MapView = new Lang.Class({
this.parent();
this.actor = this.get_view();
- this._view = this.actor;
+ this.view = this.actor;
this._properties = new Properties.Properties(this);
- this._view.bin_layout_add(this._properties.actor,
- Clutter.BinAlignment.FILL,
- Clutter.BinAlignment.FILL);
+ this.view.bin_layout_add(this._properties.actor,
+ Clutter.BinAlignment.FILL,
+ Clutter.BinAlignment.FILL);
this._markerLayer = new Champlain.MarkerLayer();
this._markerLayer.set_selection_mode(Champlain.SelectionMode.SINGLE);
- this._view.add_layer(this._markerLayer);
+ this.view.add_layer(this._markerLayer);
this._userLocationLayer = new Champlain.MarkerLayer();
this._userLocationLayer.set_selection_mode(Champlain.SelectionMode.NONE);
- this._view.add_layer(this._userLocationLayer);
+ this.view.add_layer(this._userLocationLayer);
this._factory = Champlain.MapSourceFactory.dup_default();
this.setMapType(MapType.STREET);
@@ -75,7 +77,7 @@ const MapView = new Lang.Class({
setMapType: function(mapType) {
let source = this._factory.create_cached_source(mapType);
- this._view.set_map_source(source);
+ this.view.set_map_source(source);
},
geocodeSearch: function(string) {
@@ -86,128 +88,44 @@ const MapView = new Lang.Class({
try {
let locations = forward.search_finish(res);
log (locations.length + " locations found");
- this._showLocations(locations);
+ let mapLocations = new Array();
+ locations.forEach(Lang.bind(this,
+ function(location) {
+ let mapLocation = new UserLocation.UserLocation(location, this);
+ mapLocations.push(mapLocation);
+ }));
+ this._showLocations(mapLocations);
} catch (e) {
log ("Failed to search '" + string + "': " + e.message);
}
}));
},
- _gotoLocation: function(location, animate) {
- log(location.description);
-
- let zoom = Utils.getZoomLevelForAccuracy(location.accuracy);
-
- if (!animate) {
- this._view.center_on(location.latitude, location.longitude);
- this._view.set_zoom_level(zoom);
-
- return;
- }
-
- /* Lets first ensure that both current and destination location are visible
- * before we start the animated journey towards destination itself. We do this
- * to create the zoom-out-then-zoom-in effect that many map implementations
- * do. This not only makes the go-to animation look a lot better visually but
- * also give user a good idea of where the destination is compared to current
- * location.
- */
- let locations = new Array();
- locations[0] = new Geocode.Location({ latitude: this._view.get_center_latitude(),
- longitude: this._view.get_center_longitude() });
- locations[1] = location;
- this._ensureVisible(locations);
-
- let anim_completed_id = this._view.connect("animation-completed::go-to", Lang.bind(this,
- function() {
- // Apparently the signal is called before animation is really complete so if we don't
- // zoom in idle, we get a crash. Perhaps a bug in libchamplain?
- Mainloop.idle_add(Lang.bind(this,
- function() {
- this._view.set_zoom_level(zoom);
- }));
- this._view.disconnect(anim_completed_id);
- }));
- this._view.go_to(location.latitude, location.longitude);
- },
-
- _showUserLocation: function(location, animate) {
- if (location.accuracy == Geocode.LOCATION_ACCURACY_UNKNOWN)
- return;
-
- this._gotoLocation(location, animate);
-
- this._userLocationLayer.remove_all();
-
- let locationMarker = new Champlain.CustomMarker();
- try {
- let pixbuf = GdkPixbuf.Pixbuf.new_from_file(Path.ICONS_DIR + "/pin.svg");
- let image = new Clutter.Image();
- image.set_data(pixbuf.get_pixels(),
- Cogl.PixelFormat.RGBA_8888,
- pixbuf.get_width(),
- pixbuf.get_height(),
- pixbuf.get_rowstride());
-
- locationMarker.set_location(location.latitude, location.longitude);
- locationMarker.set_reactive(false);
- // FIXME: Using deprecated function here cause I failed to get the same result
- // with locationMarker.set_pivot_point(0.5, 0).
- locationMarker.set_anchor_point_from_gravity(Clutter.Gravity.SOUTH);
- let actor = new Clutter.Actor();
- actor.set_content(image);
- actor.set_size(pixbuf.get_width(), pixbuf.get_height());
- locationMarker.add_actor(actor);
- } catch(e) {
- log("Failed to load image: " + e.message);
- return;
- }
-
- if (location.accuracy == 0) {
- this._userLocationLayer.add_marker(locationMarker);
- return;
- }
-
- // FIXME: Perhaps this is a misuse of Champlain.Point class and we
- // should draw the cirlce ourselves using Champlain.CustomMarker?
- // Although for doing so we'll need to add a C lib as cairo isn't
- // exactly introspectable.
- let accuracyMarker = new Champlain.Point();
- accuracyMarker.set_color(new Clutter.Color({ red: 0,
- blue: 255,
- green: 0,
- alpha: 50 }));
- accuracyMarker.set_location(location.latitude, location.longitude);
- accuracyMarker.set_reactive(false);
+ ensureVisible: function(locations) {
+ let min_latitude = 90;
+ let max_latitude = -90;
+ let min_longitude = 180;
+ let max_longitude = -180;
- let allocSize = Lang.bind(this,
- function(zoom) {
- let source = this._view.get_map_source();
- let metersPerPixel = source.get_meters_per_pixel(zoom, location.latitude,
location.longitude);
- let size = location.accuracy / metersPerPixel;
- let viewWidth = this._view.get_width();
- let viewHeight = this._view.get_height();
- // Ensure we don't endup creating way too big texture/canvas,
- // otherwise we easily end up with bus error
- if ((viewWidth > 0 && viewHeight > 0) &&
- (size > viewWidth && size > viewHeight))
- // Pythagorean theorem to get diagonal length of the view
- size = Math.sqrt(Math.pow(viewWidth, 2) + Math.pow(viewHeight, 2));
+ locations.forEach(Lang.bind(this,
+ function(location) {
+ if (location.latitude > max_latitude)
+ max_latitude = location.latitude;
+ if (location.latitude < min_latitude)
+ min_latitude = location.latitude;
+ if (location.longitude > max_longitude)
+ max_longitude = location.longitude;
+ if (location.longitude < min_longitude)
+ min_longitude = location.longitude;
+ }));
- accuracyMarker.set_size(size);
- });
- let zoom = Utils.getZoomLevelForAccuracy(location.accuracy);
- allocSize(zoom);
- this._userLocationLayer.add_marker(accuracyMarker);
- this._userLocationLayer.add_marker(locationMarker);
+ let bbox = new Champlain.BoundingBox();
+ bbox.left = min_longitude;
+ bbox.right = max_longitude;
+ bbox.bottom = min_latitude;
+ bbox.top = max_latitude;
- if (this._zoomLevelId > 0)
- this._view.disconnect(this._zoomLevelId);
- this._zoomLevelId = this._view.connect("notify::zoom-level", Lang.bind(this,
- function() {
- let zoom = this._view.get_zoom_level();
- allocSize(zoom);
- }));
+ this.view.ensure_visible(bbox, true);
},
_gotoUserLocation: function() {
@@ -223,7 +141,8 @@ const MapView = new Lang.Class({
let lastLocationDescription = Application.settings.get_string('last-location-description');
location.set_description(lastLocationDescription);
- this._showUserLocation(location, false);
+ let userLocation = new UserLocation.UserLocation(location, this);
+ userLocation.show(false, this._userLocationLayer);
}
let ipclient = new Geocode.Ipclient();
@@ -234,7 +153,8 @@ const MapView = new Lang.Class({
try {
let location = ipclient.search_finish(res);
- this._showUserLocation(location, true);
+ let userLocation = new UserLocation.UserLocation(location, this);
+ userLocation.show(true, this._userLocationLayer);
let variant = GLib.Variant.new('ad', [location.latitude, location.longitude,
location.accuracy]);
Application.settings.set_value('last-location', variant);
@@ -252,48 +172,12 @@ const MapView = new Lang.Class({
locations.forEach(Lang.bind(this,
function(location) {
- this._addMarker(location);
+ location.addMarker(this._markerLayer);
}));
if (locations.length == 1)
- this._gotoLocation(locations[0], true);
+ locations[0].goTo(true);
else
- this._ensureVisible(locations);
+ this.ensureVisible(locations);
},
-
- _addMarker: function(location) {
- log ("location: " + location);
- let marker = new Champlain.Label();
- marker.set_text(location.description);
- marker.set_location(location.latitude, location.longitude);
- this._markerLayer.add_marker(marker);
- log ("Added marker at " + location.latitude + ", " + location.longitude);
- },
-
- _ensureVisible: function(locations) {
- let min_latitude = 90;
- let max_latitude = -90;
- let min_longitude = 180;
- let max_longitude = -180;
-
- locations.forEach(Lang.bind(this,
- function(location) {
- if (location.latitude > max_latitude)
- max_latitude = location.latitude;
- if (location.latitude < min_latitude)
- min_latitude = location.latitude;
- if (location.longitude > max_longitude)
- max_longitude = location.longitude;
- if (location.longitude < min_longitude)
- min_longitude = location.longitude;
- }));
-
- let bbox = new Champlain.BoundingBox();
- bbox.left = min_longitude;
- bbox.right = max_longitude;
- bbox.bottom = min_latitude;
- bbox.top = max_latitude;
-
- this._view.ensure_visible(bbox, true);
- }
});
diff --git a/src/userLocation.js b/src/userLocation.js
new file mode 100644
index 0000000..486be5a
--- /dev/null
+++ b/src/userLocation.js
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2011, 2012, 2013 Red Hat, Inc.
+ *
+ * GNOME Maps is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * GNOME Maps is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with GNOME Maps; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Author: Zeeshan Ali (Khattak) <zeeshanak gnome org>
+ */
+
+const Clutter = imports.gi.Clutter;
+const Cogl = imports.gi.Cogl;
+const GdkPixbuf = imports.gi.GdkPixbuf;
+const Champlain = imports.gi.Champlain;
+const Geocode = imports.gi.GeocodeGlib;
+
+const Lang = imports.lang;
+const Mainloop = imports.mainloop;
+
+const MapLocation = imports.mapLocation;
+const Utils = imports.utils;
+const Path = imports.path;
+const _ = imports.gettext.gettext;
+
+const UserLocation = new Lang.Class({
+ Name: 'UserLocation',
+ Extends: MapLocation.MapLocation,
+
+ show: function(animate, layer) {
+ if (this.accuracy == Geocode.LOCATION_ACCURACY_UNKNOWN)
+ return;
+
+ this.goTo(animate);
+
+ layer.remove_all();
+
+ let locationMarker = new Champlain.CustomMarker();
+ try {
+ let pixbuf = GdkPixbuf.Pixbuf.new_from_file(Path.ICONS_DIR + "/pin.svg");
+ let image = new Clutter.Image();
+ image.set_data(pixbuf.get_pixels(),
+ Cogl.PixelFormat.RGBA_8888,
+ pixbuf.get_width(),
+ pixbuf.get_height(),
+ pixbuf.get_rowstride());
+
+ locationMarker.set_location(this.latitude, this.longitude);
+ locationMarker.set_reactive(false);
+ // FIXME: Using deprecated function here cause I failed to get the same result
+ // with locationMarker.set_pivot_point(0.5, 0).
+ locationMarker.set_anchor_point_from_gravity(Clutter.Gravity.SOUTH);
+ let actor = new Clutter.Actor();
+ actor.set_content(image);
+ actor.set_size(pixbuf.get_width(), pixbuf.get_height());
+ locationMarker.add_actor(actor);
+ } catch(e) {
+ log("Failed to load image: " + e.message);
+ return;
+ }
+
+ if (this.accuracy == 0) {
+ layer.add_marker(locationMarker);
+ return;
+ }
+
+ // FIXME: Perhaps this is a misuse of Champlain.Point class and we
+ // should draw the cirlce ourselves using Champlain.CustomMarker?
+ // Although for doing so we'll need to add a C lib as cairo isn't
+ // exactly introspectable.
+ let accuracyMarker = new Champlain.Point();
+ accuracyMarker.set_color(new Clutter.Color({ red: 0,
+ blue: 255,
+ green: 0,
+ alpha: 50 }));
+ accuracyMarker.set_location(this.latitude, this.longitude);
+ accuracyMarker.set_reactive(false);
+
+ let allocSize = Lang.bind(this,
+ function(zoom) {
+ let source = this._view.get_map_source();
+ let metersPerPixel = source.get_meters_per_pixel(zoom,
+ this.latitude,
+ this.longitude);
+ let size = this.accuracy / metersPerPixel;
+ let viewWidth = this._view.get_width();
+ let viewHeight = this._view.get_height();
+ // Ensure we don't endup creating way too big texture/canvas,
+ // otherwise we easily end up with bus error
+ if ((viewWidth > 0 && viewHeight > 0) &&
+ (size > viewWidth && size > viewHeight))
+ // Pythagorean theorem to get diagonal length of the view
+ size = Math.sqrt(Math.pow(viewWidth, 2) + Math.pow(viewHeight, 2));
+
+ accuracyMarker.set_size(size);
+ });
+ let zoom = Utils.getZoomLevelForAccuracy(this.accuracy);
+ allocSize(zoom);
+ layer.add_marker(accuracyMarker);
+ layer.add_marker(locationMarker);
+
+ if (this._zoomLevelId > 0)
+ this._view.disconnect(this._zoomLevelId);
+ this._zoomLevelId = this._view.connect("notify::zoom-level", Lang.bind(this,
+ function() {
+ let zoom = this._view.get_zoom_level();
+ allocSize(zoom);
+ }));
+ },
+});
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]