Browse Source

map: locate user and show marker

Nils Schneider 9 years ago
parent
commit
2c944224e3
6 changed files with 161 additions and 6 deletions
  1. 1 0
      CHANGELOG.md
  2. 59 0
      lib/locationmarker.js
  3. 91 5
      lib/map.js
  4. 4 0
      scss/_map.scss
  5. 4 0
      scss/main.scss
  6. 2 1
      tasks/linting.js

+ 1 - 0
CHANGELOG.md

@@ -11,6 +11,7 @@
 - Improved performance on Firefox
 - Labels in graph view
 - infobox: link to geouri with node's coordinates
+- map: locate user
 
 ### Fixed bugs:
 

+ 59 - 0
lib/locationmarker.js

@@ -0,0 +1,59 @@
+define(["leaflet"], function (L) {
+  return L.CircleMarker.extend({
+    outerCircle: {
+      stroke: false,
+      color: "#4285F4",
+      opacity: 1,
+      fillOpacity: 0.3,
+      clickable: false,
+      radius: 16
+    },
+
+    innerCircle: {
+      stroke: true,
+      color: "#ffffff",
+      fillColor: "#4285F4",
+      weight: 1.5,
+      clickable: false,
+      opacity: 1,
+      fillOpacity: 1,
+      radius: 7
+    },
+
+    accuracyCircle: {
+      stroke: true,
+      color: "#4285F4",
+      weight: 1,
+      clickable: false,
+      opacity: 0.7,
+      fillOpacity: 0.2
+    },
+
+    initialize: function(latlng) {
+      this.accuracyCircle = L.circle(latlng, 0, this.accuracyCircle)
+      this.outerCircle = L.circleMarker(latlng, this.outerCircle)
+      L.CircleMarker.prototype.initialize.call(this, latlng, this.innerCircle)
+
+      this.on("remove", function() {
+        this._map.removeLayer(this.accuracyCircle)
+        this._map.removeLayer(this.outerCircle)
+      })
+    },
+
+    setLatLng: function(latlng) {
+      this.accuracyCircle.setLatLng(latlng)
+      this.outerCircle.setLatLng(latlng)
+      L.CircleMarker.prototype.setLatLng.call(this, latlng)
+    },
+
+    setAccuracy: function(accuracy) {
+      this.accuracyCircle.setRadius(accuracy)
+    },
+
+    onAdd: function(map) {
+      this.accuracyCircle.addTo(map).bringToBack()
+      this.outerCircle.addTo(map)
+      L.CircleMarker.prototype.onAdd.call(this, map)
+    }
+  })
+})

+ 91 - 5
lib/map.js

@@ -1,7 +1,47 @@
-define(["d3", "leaflet", "moment", "leaflet.label"], function (d3, L, moment) {
-  var options = { worldCopyJump: true,
-                  zoomControl: false
-                }
+define(["d3", "leaflet", "moment", "locationmarker", "leaflet.label"],
+  function (d3, L, moment, LocationMarker) {
+   var options = { worldCopyJump: true,
+                   zoomControl: false
+                 }
+
+   var LocateButton = L.Control.extend({
+       options: {
+         position: "bottomright"
+       },
+
+       active: false,
+       button: undefined,
+
+       initialize: function (f, options) {
+         L.Util.setOptions(this, options)
+         this.f = f
+       },
+
+       onAdd: function () {
+         var button = L.DomUtil.create("button", "locate-user")
+
+         L.DomEvent.disableClickPropagation(button)
+         L.DomEvent.addListener(button, "click", this.onClick, this)
+
+         this.button = button
+
+         return button
+       },
+
+       update: function() {
+         this.button.classList.toggle("active", this.active)
+       },
+
+       set: function(v) {
+         this.active = v
+         this.update()
+       },
+
+       onClick: function () {
+         this.f(!this.active)
+       }
+    })
+
    function mkMarker(dict, iconFunc, router) {
      return function (d) {
        var m = L.circleMarker([d.nodeinfo.location.latitude, d.nodeinfo.location.longitude], iconFunc(d))
@@ -59,11 +99,49 @@ define(["d3", "leaflet", "moment", "leaflet.label"], function (d3, L, moment) {
     var barycenter
     var groupOnline, groupOffline, groupNew, groupLost, groupLines
 
+    var map, userLocation
+
+    var locateUserButton = new LocateButton(function (d) {
+      if (d)
+        enableTracking()
+      else
+        disableTracking()
+    })
+
+    function enableTracking() {
+      map.locate({watch: true,
+                  enableHighAccuracy: true,
+                  setView: true
+                 })
+      locateUserButton.set(true)
+    }
+
+    function disableTracking() {
+      map.stopLocate()
+      locationError()
+      locateUserButton.set(false)
+    }
+
+    function locationFound(e) {
+      if (!userLocation)
+        userLocation = new LocationMarker(e.latlng).addTo(map)
+
+      userLocation.setLatLng(e.latlng)
+      userLocation.setAccuracy(e.accuracy)
+    }
+
+    function locationError() {
+      if (userLocation) {
+        map.removeLayer(userLocation)
+        userLocation = null
+      }
+    }
+
     var el = document.createElement("div")
     el.classList.add("map")
     self.div = el
 
-    var map = L.map(el, options)
+    map = L.map(el, options)
 
     L.tileLayer("https://otile{s}-s.mqcdn.com/tiles/1.0.0/osm/{z}/{x}/{y}.jpg", {
       subdomains: "1234",
@@ -72,6 +150,11 @@ define(["d3", "leaflet", "moment", "leaflet.label"], function (d3, L, moment) {
       maxZoom: 18
     }).addTo(map)
 
+    map.on("locationfound", locationFound)
+    map.on("locationerror", locationError)
+
+    map.addControl(locateUserButton)
+
     var nodeDict = {}
     var linkDict = {}
     var highlight
@@ -200,16 +283,19 @@ define(["d3", "leaflet", "moment", "leaflet.label"], function (d3, L, moment) {
     }
 
     self.resetView = function () {
+      disableTracking()
       highlight = undefined
       updateView()
     }
 
     self.gotoNode = function (d) {
+      disableTracking()
       highlight = {type: "node", o: d}
       updateView()
     }
 
     self.gotoLink = function (d) {
+      disableTracking()
       highlight = {type: "link", o: d}
       updateView()
     }

+ 4 - 0
scss/_map.scss

@@ -6,6 +6,10 @@
   width: 100%;
   height: 100%;
 
+  button.locate-user:after {
+    content: '\f2a7';
+  }
+
  .node-alert {
     -webkit-animation: blink 2s linear;
     -webkit-animation-iteration-count: infinite;

+ 4 - 0
scss/main.scss

@@ -158,6 +158,10 @@ button {
   outline: none;
 }
 
+button.active {
+  color: #dc0067 !important;
+}
+
 button:hover {
   background: white;
   color: #dc0067;

+ 2 - 1
tasks/linting.js

@@ -20,7 +20,8 @@ module.exports = function (grunt) {
           "no-multi-spaces": 0,
           "no-new": 0,
           "no-shadow": 0,
-          "no-use-before-define": [1, "nofunc"]
+          "no-use-before-define": [1, "nofunc"],
+          "no-underscore-dangle": 0
         }
       },
       sources: {