Prechádzať zdrojové kódy

fetch region name server side

subDesTagesMitExtraKaese 2 rokov pred
rodič
commit
d44cb14cdb

+ 231 - 252
static/gps_logger/js/main.js

@@ -1,68 +1,68 @@
 const selColor = "#FF5C26";
 let d = [{
-	label:"Altitude,m",
-	data:[], 
-	yaxis: 2
+  label:"Altitude,m",
+  data:[], 
+  yaxis: 2
 },
 {
-	label:"Speed,km/h",
-	data:[]
+  label:"Speed,km/h",
+  data:[]
 }];
 
 let options = {
-	xaxis: {
-		mode: "time",
-		tickLength: 5,
-		zoomRange: [60 * 1000, 1000 * 3600 * 24 * 365]
-	},
-	/*selection: {
-		mode: "x",
-		color: selColor
-	},*/
-	yaxes: [{
-		min: 0,
-		zoomRange: false,
-		panRange: false
-	}, {
-		position: "right",
-		alignTicksWithAxis: 1,
-		min: 0,
-		zoomRange: false,
-		panRange: false
-	}],
-	zoom: {
-		interactive: true
-	},
-	pan: {
-		interactive: true,
-		cursor: "move",
-		frameRate: 60
-	}
+  xaxis: {
+    mode: "time",
+    tickLength: 5,
+    zoomRange: [60 * 1000, 1000 * 3600 * 24 * 365]
+  },
+  /*selection: {
+    mode: "x",
+    color: selColor
+  },*/
+  yaxes: [{
+    min: 0,
+    zoomRange: false,
+    panRange: false
+  }, {
+    position: "right",
+    alignTicksWithAxis: 1,
+    min: 0,
+    zoomRange: false,
+    panRange: false
+  }],
+  zoom: {
+    interactive: true
+  },
+  pan: {
+    interactive: true,
+    cursor: "move",
+    frameRate: 60
+  }
 };
 let optO = {
-	legend : {
-		show: false
-	},
-	series: {
-		lines: {
-			show: true,
-			lineWidth: 1
-		},
-		shadowSize: 0
-	},
-	xaxis: {
-		//ticks: [],
-		mode: "time"
-	},
-	yaxis: {
-		ticks: [],
-		autoscaleMargin: 0.1
-	},
-	selection: {
-		mode: "x",
-		color: selColor,
-		minSize: 0
-	}
+  legend : {
+    show: false
+  },
+  series: {
+    lines: {
+      show: true,
+      lineWidth: 1
+    },
+    shadowSize: 0
+  },
+  xaxis: {
+    //ticks: [],
+    mode: "time"
+  },
+  yaxis: {
+    ticks: [],
+    autoscaleMargin: 0.1
+  },
+  selection: {
+    mode: "x",
+    color: selColor,
+    minSize: 0
+  }
 };
 
 let gps = new GPS();
@@ -70,7 +70,7 @@ let plot, overview;
 
 window.onload = function() {
 	Cesium.Ion.defaultAccessToken = '<token>';
-	
+  
   var extent = {west: -0.2540382220862719, south: 0.6872565916005104, east: 0.6129855406042352, north: 0.9377043806513488};
 
   Cesium.Camera.DEFAULT_VIEW_RECTANGLE = extent;
@@ -83,15 +83,15 @@ window.onload = function() {
   });
 
   viewer = new Cesium.Viewer('map', {
-		fullscreenElement: "map",
-		terrainProvider : Cesium.createWorldTerrain({
-			requestVertexNormals: true,
-			requestWaterMask: true
-		}),
-		//shadows: true
-	});
-	viewer.scene.globe.enableLighting = true;
-	viewer.resolutionScale = 1.2;
+    fullscreenElement: "map",
+    terrainProvider : Cesium.createWorldTerrain({
+      requestVertexNormals: true,
+      requestWaterMask: true
+    }),
+    //shadows: true
+  });
+  viewer.scene.globe.enableLighting = true;
+  viewer.resolutionScale = 1.2;
   viewer.scene.screenSpaceCameraController.enableTilt = !('ontouchstart' in window);
   viewer.baseLayerPicker.viewModel.selectedImagery = new Cesium.ProviderViewModel({
     name: 'Bing Maps Aerial with Labels',
@@ -101,46 +101,46 @@ window.onload = function() {
       return bingMapsProvider
     }
   });
-	var paths = [];
+  var paths = [];
 
-	
-	fetch("trips")
-	.then(function(response) {
-		return response.json();
-	})
-	.then(function(jsonResponse) {
-		gps.parse(jsonResponse);
-		for(const t of gps.trips) {
-			var desc = "Start: <b>" + timeFormat(t.startTime, "datetime") + 
-						"</b><br/>Finish: <b>" + timeFormat(t.endTime, "datetime") + "</b><br/>" +
-						"Track time (full): "+ timeFormat(t.totalTime) + "<br>" +
-						"Track time (mov.): "+ timeFormat(t.movementTime) + "<br>" +
-						"Alt: &uarr;" + t.ascendHeight.toFixed(1) + "m  &darr;" + t.descendHeight.toFixed(1) + "m"+
-						"<br/>Distance: "+(t.distance/1000).toFixed(1)+"km<br/>" +
-						"top speed: "+t.topSpeed.toFixed(1)+
-						"km/h<br/>"+
-						"average speed: "+t.avgSpeed.toFixed(1)+"km/h<br/>";
+  
+  fetch("trips")
+  .then(function(response) {
+    return response.json();
+  })
+  .then(function(jsonResponse) {
+    gps.parse(jsonResponse);
+    for(const t of gps.trips) {
+      var desc = "Start: <b>" + timeFormat(t.startTime, "datetime") + 
+            "</b><br/>Finish: <b>" + timeFormat(t.endTime, "datetime") + "</b><br/>" +
+            "Track time (full): "+ timeFormat(t.totalTime) + "<br>" +
+            "Track time (mov.): "+ timeFormat(t.movementTime) + "<br>" +
+            "Alt: &uarr;" + t.ascendHeight.toFixed(1) + "m  &darr;" + t.descendHeight.toFixed(1) + "m"+
+            "<br/>Distance: "+(t.distance/1000).toFixed(1)+"km<br/>" +
+            "top speed: "+t.topSpeed.toFixed(1)+
+            "km/h<br/>"+
+            "average speed: "+t.avgSpeed.toFixed(1)+"km/h<br/>";
 
-			const col = Cesium.Color.fromCssColorString(t.color)
-			var path = viewer.entities.add({
-				label : "Track "+t.id,
+      const col = Cesium.Color.fromCssColorString(t.color)
+      var path = viewer.entities.add({
+        label : "Track "+t.id,
         id: "track_"+t.id,
         description: desc,
-				polyline : {
-					positions : t.path.map(p => Cesium.Cartesian3.fromDegrees(p.lng, p.lat, p.alt)),
-					width : 5,
-					material : new Cesium.PolylineOutlineMaterialProperty({
-						color : col,
-					}),
-					//clampToGround: true,
-					depthFailMaterial: new Cesium.PolylineOutlineMaterialProperty({
-						color : Cesium.Color.fromAlpha(col, 0.6),
-					}),
-					shadows: Cesium.ShadowMode.ENABLED
-				}
-			});
-			paths.push(path);
-		}
+        polyline : {
+          positions : t.path.map(p => Cesium.Cartesian3.fromDegrees(p.lng, p.lat, p.alt)),
+          width : 5,
+          material : new Cesium.PolylineOutlineMaterialProperty({
+            color : col,
+          }),
+          //clampToGround: true,
+          depthFailMaterial: new Cesium.PolylineOutlineMaterialProperty({
+            color : Cesium.Color.fromAlpha(col, 0.6),
+          }),
+          shadows: Cesium.ShadowMode.ENABLED
+        }
+      });
+      paths.push(path);
+    }
     var handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
     handler.setInputAction(function (movement) {
       var pick = viewer.scene.pick(movement.position);
@@ -152,171 +152,150 @@ window.onload = function() {
     }, Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK);
 
     viewer.flyTo(paths[paths.length - 1], { offset: new Cesium.HeadingPitchRange(0, -90, 0)});
-		let regionIndex = 0;
-		for(let r=0; r<gps.regions.length; r++) {
-      setTimeout(addInfo, (gps.regions.length-1-regionIndex) * 300, bingMapsProvider, viewer, regionIndex, gps.regions[r]);
-			regionIndex++;
-		}
-		const i = gps.getInfo();
-		var html =
-			"Time (full): "+ timeFormat(i.totalTime) + "<br>" +
-			"Time (mov.): "+ timeFormat(i.movementTime) + "<br>" +
-			"Alt: &uarr;" + (i.ascendHeight).toFixed(1) + "m  &darr;" + (i.descendHeight).toFixed(1) + "m<br>"+
-			"Distance: <b>"+(i.distance/1000).toFixed(1)+"km</b><br/>" +
-			"Top speed: <b>"+i.topSpeed.toFixed(1) + "km/h</b><br/>"+
-			"Avg. speed: "+i.avgSpeed.toFixed(1)+"km/h<br/>"+
-			"Data points: "+i.points+"<br/>"+
-			"<a href='javascript:show(" + (gps.trips.length-1) + ")'>Graph</a>";
-		
-		$(".status").append(html);
+    let regionIndex = 0;
+    for(let r=0; r<gps.regions.length; r++) {
+      addInfo(bingMapsProvider, viewer, regionIndex, gps.regions[r]);
+      regionIndex++;
+    }
+    const i = gps.getInfo();
+    var html =
+      "Time (full): "+ timeFormat(i.totalTime) + "<br>" +
+      "Time (mov.): "+ timeFormat(i.movementTime) + "<br>" +
+      "Alt: &uarr;" + (i.ascendHeight).toFixed(1) + "m  &darr;" + (i.descendHeight).toFixed(1) + "m<br>"+
+      "Distance: <b>"+(i.distance/1000).toFixed(1)+"km</b><br/>" +
+      "Top speed: <b>"+i.topSpeed.toFixed(1) + "km/h</b><br/>"+
+      "Avg. speed: "+i.avgSpeed.toFixed(1)+"km/h<br/>"+
+      "Data points: "+i.points+"<br/>"+
+      "<a href='javascript:show(" + (gps.trips.length-1) + ")'>Graph</a>";
+    
+    $(".status").append(html);
 
-	});
+  });
 
-	plot = $.plot("#placeholder", d, options);
-	overview = $.plot("#overview", d, optO);
-	// now connect the two
+  plot = $.plot("#placeholder", d, options);
+  overview = $.plot("#overview", d, optO);
+  // now connect the two
 
-	$("#placeholder").bind("plotpan", updateOverview);
-	$("#placeholder").bind("plotzoom", updateOverview);
-	function updateOverview(event, ranges) {
-		var axes = plot.getAxes();
-		for(var axis in axes) {
-			axes[axis].from = axes[axis].min;
-			axes[axis].to = axes[axis].max;
-		}
-		overview.setSelection(axes, true);
-	}
-	$("#overview").bind("plotselected", function (event, ranges) {
-		$.each(plot.getXAxes(), function(_, axis) {
-			var opts = axis.options;
-			opts.min = ranges.xaxis.from;
-			opts.max = ranges.xaxis.to;
-		});
-		plot.setupGrid();
-		plot.draw();
-	});
-	
-	$("#whole").click(function () {
-		setZoom(false,false);
-	});
-	$("#right").click(function () {
-		var min = plot.getXAxes()[0].options.min;
-		var max = plot.getXAxes()[0].options.max;
-		if(min != null && max != null)
-			setZoom((min+max)/2, max * 1.5 - min/2);
-	});
-	$("#left").click(function () {
-		var min = plot.getXAxes()[0].options.min;
-		var max = plot.getXAxes()[0].options.max;
-		if(min != null && max != null)
-			setZoom(min * 1.5 - max/2, (min+max)/2);
-	});
+  $("#placeholder").bind("plotpan", updateOverview);
+  $("#placeholder").bind("plotzoom", updateOverview);
+  function updateOverview(event, ranges) {
+    var axes = plot.getAxes();
+    for(var axis in axes) {
+      axes[axis].from = axes[axis].min;
+      axes[axis].to = axes[axis].max;
+    }
+    overview.setSelection(axes, true);
+  }
+  $("#overview").bind("plotselected", function (event, ranges) {
+    $.each(plot.getXAxes(), function(_, axis) {
+      var opts = axis.options;
+      opts.min = ranges.xaxis.from;
+      opts.max = ranges.xaxis.to;
+    });
+    plot.setupGrid();
+    plot.draw();
+  });
+  
+  $("#whole").click(function () {
+    setZoom(false,false);
+  });
+  $("#right").click(function () {
+    var min = plot.getXAxes()[0].options.min;
+    var max = plot.getXAxes()[0].options.max;
+    if(min != null && max != null)
+      setZoom((min+max)/2, max * 1.5 - min/2);
+  });
+  $("#left").click(function () {
+    var min = plot.getXAxes()[0].options.min;
+    var max = plot.getXAxes()[0].options.max;
+    if(min != null && max != null)
+      setZoom(min * 1.5 - max/2, (min+max)/2);
+  });
 }
 
 let firstShow = true;
 
 function show(id) {
-	if(firstShow) {
-		firstShow = false;
-		
-		d[0].data = smoothOut(gps.data.map(v => v.alt), 0.85);
-		d[1].data = smoothOut(gps.data.map(v => v.speed), 0.85);
-		
-		for(let i=0; i<gps.data.length; i++) {
-			const cur = gps.data[i];
-			if((cur.timeDiff > 60 && cur.speed < 0.5) || cur.speed === null) {
-				d[0].data[i] = null;
-				d[1].data[i] = null;
-			}
-			d[0].data[i] = [cur.timestamp*1000, d[0].data[i]];
-			d[1].data[i] = [cur.timestamp*1000, d[1].data[i]];
-		}
-		let opts = plot.getXAxes()[0].options;
-		opts.panRange = [
-			gps.data[0].timestamp*1000,
-			gps.data[gps.data.length-1].timestamp*1000
-		];
-		
-		plot.setData(d);
-		plot.setupGrid(); //only necessary if your new data will change the axes or grid
-		plot.draw();
-		overview.setData(d);
-		overview.setupGrid(); //only necessary if your new data will change the axes or grid
-		overview.draw();
-		
-		for(let t of gps.trips) {
-			$("#tracks").append("<li><input type='button' onclick='setZoom("+t.startTime*1000+","+t.endTime*1000+")' value='" + timeFormat(t.startTime, "date") + " " + (t.distance/1000).toFixed(1) + "km'</li>");
-		}
-	}
-	
-	$("#shadow").css("visibility", "visible");
-	$("#frame").css("visibility", "visible");
-	console.log(id);
-	
-	let start = gps.trips[id].startTime*1000;
-	let end = gps.trips[id].endTime*1000;
-	
-	setZoom(start,end);
-	
-	$("#track").click(function () {
-		setZoom(start,end);
-	});
+  if(firstShow) {
+    firstShow = false;
+    
+    d[0].data = smoothOut(gps.data.map(v => v.alt), 0.85);
+    d[1].data = smoothOut(gps.data.map(v => v.speed), 0.85);
+    
+    for(let i=0; i<gps.data.length; i++) {
+      const cur = gps.data[i];
+      if((cur.timeDiff > 60 && cur.speed < 0.5) || cur.speed === null) {
+        d[0].data[i] = null;
+        d[1].data[i] = null;
+      }
+      d[0].data[i] = [cur.timestamp*1000, d[0].data[i]];
+      d[1].data[i] = [cur.timestamp*1000, d[1].data[i]];
+    }
+    let opts = plot.getXAxes()[0].options;
+    opts.panRange = [
+      gps.data[0].timestamp*1000,
+      gps.data[gps.data.length-1].timestamp*1000
+    ];
+    
+    plot.setData(d);
+    plot.setupGrid(); //only necessary if your new data will change the axes or grid
+    plot.draw();
+    overview.setData(d);
+    overview.setupGrid(); //only necessary if your new data will change the axes or grid
+    overview.draw();
+    
+    for(let t of gps.trips) {
+      $("#tracks").append("<li><input type='button' onclick='setZoom("+t.startTime*1000+","+t.endTime*1000+")' value='" + timeFormat(t.startTime, "date") + " " + (t.distance/1000).toFixed(1) + "km'</li>");
+    }
+  }
+  
+  $("#shadow").css("visibility", "visible");
+  $("#frame").css("visibility", "visible");
+  console.log(id);
+  
+  let start = gps.trips[id].startTime*1000;
+  let end = gps.trips[id].endTime*1000;
+  
+  setZoom(start,end);
+  
+  $("#track").click(function () {
+    setZoom(start,end);
+  });
 };
 function hide() {
-	$(".popup").css("visibility", "hidden");
+  $(".popup").css("visibility", "hidden");
 };
 function setZoom(Xmin, Xmax) {
-	var opts = plot.getXAxes()[0].options;
-	if(Xmax==false) {
-		Xmax = +new Date() - 60 * new Date().getTimezoneOffset() * 1000;
-	}
-	if(Xmin==false) {
-		Xmin = d[0].data[0][0];
-		overview.clearSelection();
-	} else {
-		overview.setSelection({ xaxis: { from: Xmin, to: Xmax}});
-	}
-	opts.min=Xmin;
-	opts.max=Xmax;
+  var opts = plot.getXAxes()[0].options;
+  if(Xmax==false) {
+    Xmax = +new Date() - 60 * new Date().getTimezoneOffset() * 1000;
+  }
+  if(Xmin==false) {
+    Xmin = d[0].data[0][0];
+    overview.clearSelection();
+  } else {
+    overview.setSelection({ xaxis: { from: Xmin, to: Xmax}});
+  }
+  opts.min=Xmin;
+  opts.max=Xmax;
 
-	plot.setupGrid();
-	plot.draw();
-	plot.clearSelection();
+  plot.setupGrid();
+  plot.draw();
+  plot.clearSelection();
 
-	return false;
+  return false;
 }
 
 function addInfo(bingMapsProvider, viewer, id, data) {
-  var url = `https://dev.virtualearth.net/REST/v1/LocationRecog/${data.lat.toFixed(6) + "," + data.lng.toFixed(6)}?radius=2&top=1&c=de-DE&includeEntityTypes=address&key=${bingMapsProvider._key}&output=json`;
-  fetch(url).then(res=>res.json()).then(function(result) {
-    if (result.statusDescription === 'OK') {
-      const address = result?.resourceSets[0]?.resources[0]?.addressOfLocation[0];
-			if (address) {
-
-        let txt = address.locality + " " + address.neighborhood;
-        if (!address.locality && !address.neighborhood) {
-          txt = address.adminDivision;
-        }
-        if (address.countryIso2 != "DE") {
-          txt += " " + address.countryIso2;
-        }
-
-				$('.sidebar').append("<div class='info' id='info_" + id + "'>" + 
-					timeFormat(data.timestamp, "short") + "<br>" +
-          txt + "<br><b>" +
-					(data.distance/1000).toFixed(1) + " km</b></div>");
-					
-				$('#info_'+id).click(function() {
-          viewer.camera.flyTo({
-            destination: Cesium.Cartesian3.fromDegrees(data.lng, data.lat, data.distance),
-            offset: new Cesium.HeadingPitchRange(0, -90, 0)
-          });
-				});
-			} else {
-				console.log('No results found');
-			}
-		} else {
-			console.log('Geocoder failed due to: ' + result.statusDescription);
-		}
-	});
+  $('.sidebar').append("<div class='info' id='info_" + id + "'>" + 
+    timeFormat(data.timestamp, "short") + "<br>" +
+    data.name + "<br><b>" +
+    (data.distance/1000).toFixed(1) + " km</b></div>");
+    
+  $('#info_'+id).click(function() {
+    viewer.camera.flyTo({
+      destination: Cesium.Cartesian3.fromDegrees(data.lng, data.lat, data.distance),
+      offset: new Cesium.HeadingPitchRange(0, -90, 0)
+    });
+  });
 }

+ 2 - 1
static/gps_logger/js/tracks.js

@@ -26,7 +26,8 @@ class GPS {
           lat: median(trip.map(v => v.center.lat)),
           lng: median(trip.map(v => v.center.lng)),
           timestamp: median(trip.map(v => v.startTime)),
-          distance: dist
+          distance: dist,
+          name: trip[0].name
         });
       }
       s = i;

+ 30 - 7
workers/points2trips.py

@@ -1,3 +1,4 @@
+import os
 import json
 import gzip
 import random
@@ -6,10 +7,10 @@ import colorsys
 from math import radians, cos, sin, asin, sqrt
 
 from django.contrib.gis.geos import Point, LineString
-
+import requests
 
 from ..models import Marker, Trip
-
+from website.settings import VIRTUALEARTH_API_KEY
 
 max_time_diff = timedelta(hours=6)
 max_distance = 3000 # m
@@ -46,11 +47,16 @@ def create_trip(markers: list[Marker]) -> Trip:
       color = get_path_color(markers[0].timestamp)
     )
   elif trip.startTime == markers[0].timestamp and trip.endTime == markers[-1].timestamp:
-    data = json.loads(gzip.decompress(trip.path))
-    if len(data) > len(markers) * 0.9 and len(data) <= len(markers):
-      print("Trip already exists")
-      return trip
-
+    print("Trip already exists")
+    return trip
+  
+  if not trip.name or "None" in trip.name:
+    start = get_location_name(markers[0].location)
+    end = get_location_name(markers[-1].location)
+    if start != end:
+      trip.name = f"{start} - {end}"
+    else:
+      trip.name = start
   trip.startTime = markers[0].timestamp
   trip.endTime = markers[-1].timestamp
   trip.totalTime = trip.endTime - trip.startTime
@@ -130,6 +136,23 @@ def Distance(point1: Point, point2: Point) -> float:
   r = 6371000 # Radius of earth in meters. Use 3956 for miles
   return c * r
 
+def get_location_name(point: Point) -> str:
+  url = f"https://dev.virtualearth.net/REST/v1/LocationRecog/{round(point.y, 6)},{round(point.x, 6)}?radius=2&top=1&c=de-DE&includeEntityTypes=address&key={VIRTUALEARTH_API_KEY}&output=json"
+  response = requests.get(url)
+  if response.status_code == 200:
+    data = response.json()
+    if data["resourceSets"][0]["estimatedTotal"] > 0:
+      address = data["resourceSets"][0]["resources"][0]["addressOfLocation"][0]
+      if address["locality"] and address["neighborhood"]:
+        txt = f"{address['locality']} {address['neighborhood']}"
+      else:
+        txt = address["adminDivision"]
+      
+      if address["countryIso2"]:
+        txt += f" {address['countryIso2']}"
+      return txt
+  return None
+
 def get_path_color(time: datetime) -> str:
   random.seed(int(time.timestamp()))
   hue = random.random()