Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Comparing changes

Choose two branches to see what's changed or to start a new pull request. If you need to, you can also compare across forks.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also compare across forks.
base fork: bmcmahen/Trailmix
base: 4e2f663fe6
...
head fork: bmcmahen/Trailmix
compare: af6b020184
  • 2 commits
  • 5 files changed
  • 0 commit comments
  • 1 contributor
View
BIN  trailmix/client/scripts/.DS_Store
Binary file not shown
View
150 trailmix/client/scripts/editSidebar.coffee
@@ -1,150 +0,0 @@
-createFeatures = (json) ->
- for feature in json
- _.extend feature, trail: Session.get 'currentTrail'
- Features.insert(feature)
-
-
-Template.editSidebar.helpers
-
- trail: ->
- current = Session.get 'currentTrail'
- Trails.findOne current if current
-
- features: ->
- currentTrail = Session.get 'currentTrail'
- Features.find( trail : currentTrail) if currentTrail
-
- featuresTab: ->
- Session.equals 'tabView', 'features'
-
- descriptionTab: ->
- Session.equals 'tabView', 'description'
-
- addFeaturesTab: ->
- Session.equals 'tabView', 'addFeatures'
-
-
-Template.editSidebar.created = ->
- Session.set 'tabView', 'description'
-
-
-Template.editSidebar.rendered = ->
-
- $(window).on 'dragover', (e) ->
- e.preventDefault()
- $('#features').addClass 'dragover'
-
- $(window).on 'dragleave', (e) ->
- $('#features').removeClass 'dragover'
-
- $(window).on 'drop', (e) ->
- e.preventDefault()
-
-
-Template.editSidebar.events
-
- 'drop #features': (e, t) ->
- e.preventDefault()
- $(e.currentTarget).removeClass 'dragover'
- files = e.dataTransfer.files
-
- # Check that we have files or support FileReader
- return unless files? or window.FileReader?
-
- reader = new FileReader()
- reader.onload = (e) ->
- Trailmix.Utils.GPXtoGeoJSON e.target.result, (json) ->
- createFeatures json
- reader.readAsText files[0]
-
- 'submit #trail-info': (e, t) ->
- e.preventDefault()
- name = t.find('.name').value
- desc = t.find('.description').value
-
- Trails.update _id: @_id,
- '$set'
- name: name
- description desc
-
- return false
-
- # Upon input, if we are in tagging mode then we want to keep track
- # of the start index of our query, and the end index of our query.
- 'input textarea': (e) ->
- @endTagging = ->
- delete @start
- delete @end
- @tagging = false
- Session.set 'taggingQuery', null
-
- if @tagging
- currentPos = @textarea.selectionStart
-
- if currentPos - @start < 0
- @endTagging()
- return
-
- @start = currentPos unless @start?
-
- if @start is 0 then @textarea.selectionStart = 1
- else if @textarea.value.charAt @start is '@'
- @start += 1
-
- if currentPos > @end + 1 or currentPos < @start
- @endTagging()
- return
-
- if not @end or currentPos > @end
- @end = @textarea.selectionStart + 1
-
- query = @textarea.value.substring @start, @end + 1
- Session.set 'taggingQuery', query
-
- 'keydown textarea': (e) ->
- @key = e.which
- @selectionLength = null
- @textarea = $('#trail-description')[0] unless @textarea?
- if @tagging
- @selectionLength = @textarea.selectionEnd - @textarea.selectionStart
-
- # Detect @symbol
- if e.shiftKey and e.which is 50
- @endTagging() if @tagging
- @tagging = true
-
-
- Template.editSidebar.destroyed = ->
- $(window).off 'dragover, dragleave, drop'
-
-
- # Feature Template
- Template.feature.events
-
- 'click .delete-feature': ->
- Features.remove @_id
-
- 'click .edit-feature': ->
- Trailmix.map.editFeature this
-
- 'click .edit-trail': ->
- Session.set 'isEditing', true
-
- 'click .feature-instance': ->
- Session.set 'selectedFeature', @_id
- Trailmix.map.highlightFeature @_id
-
-
- Template.feature.helpers
-
- # Highlight the currently selected feature
- selected : ->
- Session.equals 'selectedFeature', @_id
-
-
- Template.feature.preserve
- 'img[id]' : (node) -> node.id
-
-
-
-
View
118 trailmix/client/scripts/map-behaviors.js
@@ -0,0 +1,118 @@
+Trailmix.behaviors = {};
+
+/*
+* Behavior Modules
+*/
+
+// Observe the features that belong to our currently selected
+// trail, and sync them with the map.
+Trailmix.behaviors.observeTrailFeatures = function(context) {
+ return {
+
+ on : function() {
+ var _this = this;
+
+ this.autorun = Meteor.autorun(function() {
+ var query = Features.find({ trail: Session.get('currentTrail') });
+ if (_this.handle) {
+ _this.handle.stop();
+ context.removeAllFeatures();
+ }
+ _this.handle = query.observe({
+ added: function(newDoc) { context.addFeature(newDoc); },
+ changed: function(newDoc, oldDoc) { console.log('update'); },
+ removed: function(oldDoc) { context.removeFeature(oldDoc); }
+ });
+ });
+ },
+
+ off : function() {
+ if (this.autorun) this.autorun.stop();
+ if (this.handle) {
+ this.handle.stop();
+ this.context.removeAllFeatures();
+ }
+ }
+
+ };
+};
+
+// Observe our Trails subscription, and update the map with any
+// trail that exists within our description.
+Trailmix.behaviors.observeTrails = function(context){
+ return {
+
+ on : function() {
+ var _this = this;
+ this.autorun = Meteor.autorun(function() {
+ var query = Trails.find();
+ if (_this.handle) {
+ _this.handle.stop();
+ context.removeAllFeatures();
+ }
+ _this.handle = query.observe({
+ added: function(newDoc) { context.addFeature(newDoc); },
+ changed: function(newDoc, oldDoc) { console.log('update'); },
+ removed: function(oldDoc) { context.removeFeature(oldDoc); }
+ });
+ });
+ },
+
+ off : function() {
+ if (this.autorun) this.autorun.stop();
+ if (this.handle) {
+ this.handle.stop();
+ this.removeAllFeatures();
+ }
+ }
+ };
+};
+
+// When our map bounds change, we need to update our bounds collection
+// so that our subscription information also changes.
+Trailmix.behaviors.observeBoundsChanges = function(context){
+ return {
+
+ onBoundsChange: function(e) {
+ var bounds = context.map.getBounds(),
+ boundObject = {
+ sourthWest: [ bounds._southWest.lat, bounds._southWest.lng ],
+ northEast: [ bounds._northEast.lat, bounds._northEast.lng ]
+ };
+
+ if (MapBounds.find().count() > 1)
+ MapBounds.insert(boundObject);
+ else
+ MapBounds.update({}, boundObject);
+ context.browseLocation = context.map.getCenter();
+ context.browseZoom = context.map.getZoom();
+ },
+
+ on : function(){
+ context.map.on('moveend', this.onBoundsChange);
+ },
+
+ off : function(){
+ context.map.off('moveend', this.onBoundsChange);
+ }
+ };
+};
+
+// Determine where the user is currently located, and set the
+// map at that location.
+Trailmix.behaviors.geoLocate = function(context){
+ return {
+
+ onLocationFound: function(e){
+ context.map.setView(e.latlng, 12);
+ },
+
+ on : function() {
+ context.map.on('locationfound', this.onLocationFound);
+ },
+
+ off : function() {
+ context.map.off('locationfound', this.onLocationFound);
+ }
+ };
+};
View
212 trailmix/client/scripts/map-class.js
@@ -1,10 +1,6 @@
Trailmix.MapView = (function(){
-
- // Meteor Observer -> Leaflet Controller/View
- //
- // Keeps a dict of _id to Feature elements, which we can
- // use to map objects to their elements. Each element also
- // is built with a _id attribute, allowing us to go back the other way.
+
+ // Meteor Observer -> Leaflet View
var MapView = function(){
this.map = new L.Map('map', {
center: new L.LatLng(53.1103, -119.1567),
@@ -17,167 +13,68 @@ Trailmix.MapView = (function(){
L.control.scale().addTo(this.map);
this.features = L.featureGroup().addTo(this.map);
this.idToFeatures = {};
+ this.modes = {
+ detail : new Trailmix.modes.Detail(this),
+ browse : new Trailmix.modes.Browse(this)
+ };
this.determineMapMode();
};
_.extend(MapView.prototype, {
- // Different Modes
- //
- // MapView is controlled by Session variable 'mapView'
- // and can either be 'detail' or 'browse'.
+ // Install/bind our behaviors
+ install: function(behavior){
+ behavior.on();
+ },
+
+ // Remove/bind our behaviors
+ uninstall: function(behavior) {
+ behavior.off();
+ },
+
+ // Responds to Session.get('mapView') and either enters
+ // detailMode or browseMode.
determineMapMode: function(){
- var _this = this;
+ var _this = this;
if (this.determineMode) this.determineMode.stop();
this.determineMode = Meteor.autorun(function(){
if (Session.equals('mapView', 'detail'))
- _this.enterTrailDetailMode();
+ _this.enterMode('detail');
else if (Session.equals('mapView', 'browse'))
- _this.enterTrailBrowseMode();
+ _this.enterMode('browse');
});
},
- //
- // We can either be in 'Trail Detail Mode' or 'Trail Browse Mode'. These
- // functions help us swap between the two.
- enterTrailDetailMode: function(){
- this.detailMode = true;
- this.removeAllFeatures();
- // Unbind TrailBrowse Events
- this.map
- .off('moveend')
- .off('locationfound');
- this.observeTrailFeatures();
+ // TODO: Modes aren't necessarily mutually exclusive. If we are
+ // editing, for instance, we will be in 'detail' mode.
+ enterMode: function(name){
+ if (this.mode && name !== 'drawing') this.mode.exit();
+ console.log(this);
+ this.modes[name].enter();
+ this.mode = this.modes[name];
},
- enterTrailBrowseMode: function(){
- // Either acquire the currentLocation of the user, or, if
- // they have navigated to another location, remember that, and
- // zoom back to that location.
- this.detailMode = false;
- this.removeAllFeatures();
- // Bind TrailBrowse Events
- this.map
- .on('moveend', _.bind(this.onViewChange, this))
- .on('locationfound', _.bind(this.onLocationFound, this));
-
- if (this.browseLocation) {
- this.browseZoom = this.browseZoom || 12;
- this.map.setView(this.browseLocation, this.browseZoom);
- } else {
- this.map.locate();
- }
-
- this.observeTrails();
- },
-
- // Observe
- //
- // When in 'Trail Detail Mode' we want to observe the selected trail.
- observeTrailFeatures: function(){
- var _this = this;
-
- if (this.autorun) this.autorun.stop();
-
- this.autorun = Meteor.autorun(function() {
- var query = Features.find({
- trail: Session.get('currentTrail')
- });
-
- if (_this.handle){
- _this.handle.stop();
- _this.removeAllFeatures();
- }
-
- _this.handle = query.observe({
- added: function(doc) {
- _this.addFeature(doc).delayFitBounds();
- },
- changed: function(newDocument, oldDocument) {
- if (!_.isEqual(newDocument, oldDocument)) {
- console.log('we need update this document');
- }
- },
- removed: function(oldDocument) {
- _this.removeFeature(oldDocument);
- }
- });
-
- })
- },
-
- // When in 'Trail Browse Mode' we want to observe our
- // Trail subscription.
- observeTrails: function(){
- var _this = this;
- if (this.autorun) this.autorun.stop();
-
- this.autorun = Meteor.autorun(function() {
- var query = Trails.find();
-
- if (_this.handle){
- _this.handle.stop();
- _this.removeAllFeatures();
- }
-
- _this.handle = query.observe({
- added: function(doc) {
- _this.addFeature(doc);
- },
- changed: function(newDoc, oldDoc) {
- console.log('we need to update position of trail');
- },
- removed: function(oldDoc){
- _this.removeFeature(oldDoc);
- }
- });
- });
- },
-
- // Events
- //
- onViewChange: function(e){
- var bounds = this.map.getBounds()
- , boundObject = {
- southWest: [bounds._southWest.lat, bounds._southWest.lng],
- northEast: [bounds._northEast.lat, bounds._northEast.lng]
- };
-
- if (MapBounds.find().count() < 1) MapBounds.insert(boundObject);
- else MapBounds.update({}, boundObject);
-
- this.browseLocation = this.map.getCenter();
- this.browseZoom = this.map.getZoom();
- },
-
- onLocationFound: function(e){
- this.map.setView(e.latlng, 12);
- },
// Handle Observe -> Map data synchronization.
- //
addFeature: function(doc){
- var newFeature = Trailmix.Feature(doc, { map : this })
- , el;
-
- if (!newFeature)
- return;
+ var newFeature = Trailmix.Feature(doc, { map : this }),
+ el;
+ if (!newFeature) return;
el = newFeature.el;
-
if (newFeature) {
this.idToFeatures[doc._id] = newFeature;
this.features.addLayer(el);
if (el._label && el._label.options.noHide)
el.showLabel();
}
- return this;
+ return this;
},
// Remove Feature & Remove Trail are basically the same, except
// for 'features' contains a different kind of object. I should
- // eventually make this perform the same, which would allow
- // better code reuse.
+ // eventually make this perform the same, which would allow
+ // better code reuse.
removeFeature: function(doc){
var feature = this.idToFeatures[doc._id];
if (feature) {
@@ -199,7 +96,6 @@ Trailmix.MapView = (function(){
},
// Basic map functions
- //
fitBounds: function(){
if (this.features) {
this.map.fitBounds(this.features.getBounds());
@@ -208,16 +104,16 @@ Trailmix.MapView = (function(){
if (currentTrail.coordinates){
this.map
.panTo(currentTrail.coordinates)
- .setZoom(12);
+ .setZoom(12);
}
}
},
- // Wait until all of the features have loaded before
+ // Wait until all of the features have loaded before
// we determine our new map bounds.
delayFitBounds: function(){
- this.timer && clearInterval(this.timer);
- this.timer = setTimeout(_.bind(this.fitBounds, this), 300);
+ if (this.timer) Meteor.clearInterval(this.timer);
+ this.timer = Meteor.setTimeout(_.bind(this.fitBounds, this), 300);
},
resizeMap: function(){
@@ -227,16 +123,19 @@ Trailmix.MapView = (function(){
// XXX also allow adding a marker
addDrawingControls: function(){
- // L.Draw.Polyline();
- this.draw = new L.Polyline.Draw(this.map, {title: 'Draw a line.'});
- this.map.on('draw:poly-created', _.bind(this.onFeatureCreated, this));
- this.draw.on('activated', function(e){
- console.log('drawing controls activated');
- });
- this.map.on('drawing', function(){
- console.log('drawing is happening');
- });
- this.draw.enable();
+ // Enable Polyline Drawing
+ this.draw = new L.Polyline.Draw(this.map, { title: 'Draw a line.' });
+ this.map
+ .on('draw:poly-created', _.bind(this.onFeatureCreated, this))
+ .on('drawing', function(){
+ console.log('drawing is happening');
+ });
+
+ this.draw
+ .on('activated', function(e){
+ console.log('drawing controls activated');
+ })
+ .enable();
},
highlightFeature: function(id){
@@ -246,15 +145,14 @@ Trailmix.MapView = (function(){
},
// Editing States
- //
editFeature: function(doc) {
var el = this.idToFeatures[doc._id];
if (this.currentlyEditing)
this.currentlyEditing.disableEditing();
- this.currentlyEditing = el;
- el.enableEditing();
+ this.currentlyEditing = el;
+ el.enableEditing();
},
disableEditFeature: function(doc) {
@@ -265,7 +163,7 @@ Trailmix.MapView = (function(){
onFeatureCreated: function(e){
// XXX - it might be easier if I use the {lat: , lng: }
// format over the array format. Seems to be the more standard
- // approach in both leaflet and mongo.
+ // approach in both leaflet and mongo.
var coordinates = _.map(e.poly.getLatLngs(), function(coords){
return [coords.lat, coords.lng];
});
@@ -284,7 +182,7 @@ Trailmix.MapView = (function(){
// of coordinates we have. We need to project these coordinates
// into LatLng objects, and then into Points. We simplify the Points,
// and then convert them back to LatLngs. We then return the
- // array of LatLngs, to be saved in the database.
+ // array of LatLngs, to be saved in the database.
simplifyPolyline: function(coordinates){
// Convert each feature into a point.
var pts = _.map(coordinates, function(latlng, i){
View
56 trailmix/client/scripts/map-modes.js
@@ -0,0 +1,56 @@
+(function(){
+
+ Trailmix.modes = {};
+
+ // Shared mode functions
+ var modeFunctions = {
+ enter: function(){
+ _.each(this.behaviors, function(behavior){
+ this.context.install(behavior);
+ });
+ },
+ exit: function(){
+ _.each(this.behaviors, function(behavior){
+ this.context.uninstall(behavior);
+ });
+ }
+ };
+
+ Trailmix.modes.Detail = function(context){
+ var mode = {
+ context : context,
+ behaviors: [
+ Trailmix.behaviors.observeTrailFeatures(context)
+ ]
+ };
+ _.extend(mode, modeFunctions);
+ return mode;
+ };
+
+ Trailmix.modes.Browse = function(context){
+ var mode = {
+ context : context,
+ behaviors: [
+ Trailmix.behaviors.observeTrails(context),
+ Trailmix.behaviors.observeBoundsChanges(context)
+ ]
+ };
+
+ if (!context.browseLocation)
+ mode.behaviors.push(Trailmix.behaviors.geoLocate(context));
+
+ mode.enter = function(){
+ _.each(this.behaviors, function(behavior){
+ context.install(behavior);
+ });
+ if (context.browseLocation)
+ context.map.setView(context.browseLocation, context.browseZoom);
+ };
+
+ mode.exit = modeFunctions.exit;
+ return mode;
+ };
+
+
+
+})();

No commit comments for this range

Something went wrong with that request. Please try again.