This commit is contained in:
2019-10-27 02:18:42 +01:00
commit 134a3fa598
32 changed files with 1056 additions and 0 deletions
View File
+3
View File
@@ -0,0 +1,3 @@
from django.contrib import admin
# Register your models here.
+5
View File
@@ -0,0 +1,5 @@
from django.apps import AppConfig
class MapConfig(AppConfig):
name = 'map'
+3
View File
@@ -0,0 +1,3 @@
from django.db import models
# Create your models here.
+43
View File
@@ -0,0 +1,43 @@
#map1 {
height: 43%
}
#map2 {
margin-top: 10px;
height: 43%;
margin-bottom: 7px;
}
.slider {
-webkit-appearance: none;
width: 100%;
height: 15px;
border-radius: 5px;
background: #d3d3d3;
outline: none;
opacity: 0.7;
-webkit-transition: .2s;
transition: opacity .2s;
}
.slider::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 25px;
height: 25px;
border-radius: 50%;
background: #4CAF50;
cursor: pointer;
}
.slider::-moz-range-thumb {
width: 25px;
height: 25px;
border-radius: 50%;
background: #4CAF50;
cursor: pointer;
}
.no-bloom-icon {
height: 30px;
}
+139
View File
@@ -0,0 +1,139 @@
var p_date = document.getElementById("p_date");
var map1 = L.map('map1').setView([49.4093524, 8.6931736], 15);
var map2 = L.map('map2').setView([49.4093524, 8.6931736], 15);
map1.sync(map2);
map2.sync(map1);
var tile = "https://c.tile.openstreetmap.org/{z}/{x}/{y}.png "
var layer1 = L.tileLayer(tile, {
attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
}).addTo(map1);
var layer2 = L.tileLayer(tile, {
attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
}).addTo(map2);
//var layer1 = L.tileLayer('https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token={accessToken}', {
// attribution: 'Map data &copy; <a href="https://www.openstreetmap.org/">OpenStreetMap</a> contributors, <a href="https://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>, Imagery © <a href="https://www.mapbox.com/">Mapbox</a>',
// maxZoom: 18,
// id: 'mapbox.streets',
// accessToken: 'pk.eyJ1IjoicG9zdGZsYXYiLCJhIjoiY2syN29xZHVpMnlzcDNtbXZkN2tlYWdhaSJ9.Th5tmsyOlPKoogGrOQrMNA'
//});
//var layer2 = L.tileLayer('https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token={accessToken}', {
// attribution: 'Map data &copy; <a href="https://www.openstreetmap.org/">OpenStreetMap</a> contributors, <a href="https://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>, Imagery © <a href="https://www.mapbox.com/">Mapbox</a>',
// maxZoom: 18,
// id: 'mapbox.hiking',
// accessToken: 'pk.eyJ1IjoicG9zdGZsYXYiLCJhIjoiY2syN29xZHVpMnlzcDNtbXZkN2tlYWdhaSJ9.Th5tmsyOlPKoogGrOQrMNA'
//});
layer1.addTo(map1);
layer2.addTo(map2);
function mk_not_bloom_icon(label) {
return new L.DivIcon({
className: 'no-bloom-icon',
html: '<img class="no-bloom-icon" src="/home/christian/repos/bloomMap2k19/bloomhunt/map/static/map/tree_not_blooming.png"/>' +
'<span>' + label + '</span>',
iconAnchor: [15, 30]
});
}
function mk_bloom_icon(label) {
return new L.DivIcon({
className: 'bloom-icon',
html: '<img class="no-bloom-icon" src="/home/christian/repos/bloomMap2k19/bloomhunt/map/static/map/tree_blooming.png"/>' +
'<span>' + label + '</span>',
iconAnchor: [15, 30]
});
}
//var not_bloom_icon = L.icon({
// iconUrl: 'tree_not_blooming.png',
//
// iconSize: [40, 40], // size of the icon
// shadowSize: [0, 0], // size of the shadow
// iconAnchor: [20, 40], // point of the icon which will correspond to marker's location
// shadowAnchor: [4, 62], // the same for the shadow
// popupAnchor: [-3, -76] // point from which the popup should open relative to the iconAnchor
//});
//var bloom_icon = L.icon({
// iconUrl: 'tree_blooming.png',
//
// iconSize: [40, 40], // size of the icon
// shadowSize: [0, 0], // size of the shadow
// iconAnchor: [20, 40], // point of the icon which will correspond to marker's location
// shadowAnchor: [4, 62], // the same for the shadow
// popupAnchor: [-3, -76] // point from which the popup should open relative to the iconAnchor
//});
class Tree {
constructor(name, bloom_start, xcoord, ycoord) {
this.name = name;
this.bloom_start = bloom_start;
this.marker = L.marker([xcoord, ycoord],
{icon: mk_not_bloom_icon(this.name)});
this.blooming = false;
}
update(dayno) {
if ((dayno < this.bloom_start || dayno >= this.bloom_start + 14)
&& this.blooming) {
this.marker.setIcon(mk_not_bloom_icon(this.name));
this.blooming = false;
} else if (dayno >= this.bloom_start
&& dayno < this.bloom_start + 14
&& !this.blooming) {
this.marker.setIcon(mk_bloom_icon(this.name));
this.blooming = true;
}
}
}
var tree = new Tree("Fritz", 55, 49.4093524, 8.6931736);
var tree2 = new Tree("Hans", 80, 45.02, 8.6931736);
var tree3 = new Tree("Hans", 80, 49.02, 8.69317);
var a_tree = new Tree("Fritz", 120, 49.4093524, 8.6931736);
var a_tree2 = new Tree("Hans", 100, 45.02, 8.6931736);
var a_tree3 = new Tree("Hans", 100, 49.02, 8.69317);
function updateMap(value) {
tree.update(value);
tree2.update(value);
tree3.update(value);
a_tree.update(value);
a_tree2.update(value);
a_tree3.update(value);
p_date.innerHTML = "Date: " + dateFromDay(value);
}
function dateFromDay(dayno) {
var date = new Date(2019, 0); // initialize a date in `year-01-01`
var date2 = new Date(date.setDate(dayno));
return date2.getMonth() + 1 + "-" + date2.getDate();
}
var cities1 = L.layerGroup([tree.marker, tree2.marker, tree3.marker]);
var cities2 = L.layerGroup([a_tree.marker, a_tree2.marker, a_tree3.marker]);
cities1.addTo(map1);
cities2.addTo(map2);
//var control1 = L.control.layers({'2019': cities1, '2020': cities1}, null, {collapsed: false});
//var control2 = L.control.layers({'2019': cities2, '2020': cities2}, null, {collapsed: false});
//control1.addTo(map1);
//control2.addTo(map2);
//map1.on('baselayerchange', function(val) {
// console.log(val);
//});
//
//map2.on('baselayerchange', function(val) {
// console.log("map2", val);
//});
+269
View File
@@ -0,0 +1,269 @@
/*
* Extends L.Map to synchronize the interaction on one map to one or more other maps.
*/
(function () {
var NO_ANIMATION = {
animate: false,
reset: true,
disableViewprereset: true
};
L.Sync = function () {};
/*
* Helper function to compute the offset easily.
*
* The arguments are relative positions with respect to reference and target maps of
* the point to sync. If you provide ratioRef=[0, 1], ratioTarget=[1, 0] will sync the
* bottom left corner of the reference map with the top right corner of the target map.
* The values can be less than 0 or greater than 1. It will sync points out of the map.
*/
L.Sync.offsetHelper = function (ratioRef, ratioTarget) {
var or = L.Util.isArray(ratioRef) ? ratioRef : [0.5, 0.5];
var ot = L.Util.isArray(ratioTarget) ? ratioTarget : [0.5, 0.5];
return function (center, zoom, refMap, targetMap) {
var rs = refMap.getSize();
var ts = targetMap.getSize();
var pt = refMap.project(center, zoom)
.subtract([(0.5 - or[0]) * rs.x, (0.5 - or[1]) * rs.y])
.add([(0.5 - ot[0]) * ts.x, (0.5 - ot[1]) * ts.y]);
return refMap.unproject(pt, zoom);
};
};
L.Map.include({
sync: function (map, options) {
this._initSync();
options = L.extend({
noInitialSync: false,
syncCursor: false,
syncCursorMarkerOptions: {
radius: 10,
fillOpacity: 0.3,
color: '#da291c',
fillColor: '#fff'
},
offsetFn: function (center, zoom, refMap, targetMap) {
// no transformation at all
return center;
}
}, options);
// prevent double-syncing the map:
if (this._syncMaps.indexOf(map) === -1) {
this._syncMaps.push(map);
this._syncOffsetFns[L.Util.stamp(map)] = options.offsetFn;
}
if (!options.noInitialSync) {
map.setView(
options.offsetFn(this.getCenter(), this.getZoom(), this, map),
this.getZoom(), NO_ANIMATION);
}
if (options.syncCursor) {
if (typeof map.cursor === 'undefined') {
map.cursor = L.circleMarker([0, 0], options.syncCursorMarkerOptions).addTo(map);
}
this._cursors.push(map.cursor);
this.on('mousemove', this._cursorSyncMove, this);
this.on('mouseout', this._cursorSyncOut, this);
}
// on these events, we should reset the view on every synced map
// dragstart is due to inertia
this.on('resize zoomend', this._selfSetView);
this.on('moveend', this._syncOnMoveend);
this.on('dragend', this._syncOnDragend);
return this;
},
// unsync maps from each other
unsync: function (map) {
var self = this;
if (this._cursors) {
this._cursors.forEach(function (cursor, indx, _cursors) {
if (cursor === map.cursor) {
_cursors.splice(indx, 1);
}
});
}
// TODO: hide cursor in stead of moving to 0, 0
if (map.cursor) {
map.cursor.setLatLng([0, 0]);
}
if (this._syncMaps) {
this._syncMaps.forEach(function (synced, id) {
if (map === synced) {
delete self._syncOffsetFns[L.Util.stamp(map)];
self._syncMaps.splice(id, 1);
}
});
}
if (!this._syncMaps || this._syncMaps.length == 0) {
// no more synced maps, so these events are not needed.
this.off('resize zoomend', this._selfSetView);
this.off('moveend', this._syncOnMoveend);
this.off('dragend', this._syncOnDragend);
}
return this;
},
// Checks if the map is synced with anything or a specifyc map
isSynced: function (otherMap) {
var has = (this.hasOwnProperty('_syncMaps') && Object.keys(this._syncMaps).length > 0);
if (has && otherMap) {
// Look for this specific map
has = false;
this._syncMaps.forEach(function (synced) {
if (otherMap == synced) { has = true; }
});
}
return has;
},
// Callbacks for events...
_cursorSyncMove: function (e) {
this._cursors.forEach(function (cursor) {
cursor.setLatLng(e.latlng);
});
},
_cursorSyncOut: function (e) {
this._cursors.forEach(function (cursor) {
// TODO: hide cursor in stead of moving to 0, 0
cursor.setLatLng([0, 0]);
});
},
_selfSetView: function (e) {
// reset the map, and let setView synchronize the others.
this.setView(this.getCenter(), this.getZoom(), NO_ANIMATION);
},
_syncOnMoveend: function (e) {
if (this._syncDragend) {
// This is 'the moveend' after the dragend.
// Without inertia, it will be right after,
// but when inertia is on, we need this to detect that.
this._syncDragend = false; // before calling setView!
this._selfSetView(e);
this._syncMaps.forEach(function (toSync) {
toSync.fire('moveend');
});
}
},
_syncOnDragend: function (e) {
// It is ugly to have state, but we need it in case of inertia.
this._syncDragend = true;
},
// overload methods on originalMap to replay interactions on _syncMaps;
_initSync: function () {
if (this._syncMaps) {
return;
}
var originalMap = this;
this._syncMaps = [];
this._cursors = [];
this._syncOffsetFns = {};
L.extend(originalMap, {
setView: function (center, zoom, options, sync) {
// Use this sandwich to disable and enable viewprereset
// around setView call
function sandwich (obj, fn) {
var viewpreresets = [];
var doit = options && options.disableViewprereset && obj && obj._events;
if (doit) {
// The event viewpreresets does an invalidateAll,
// that reloads all the tiles.
// That causes an annoying flicker.
viewpreresets = obj._events.viewprereset;
obj._events.viewprereset = [];
}
var ret = fn(obj);
if (doit) {
// restore viewpreresets event to its previous values
obj._events.viewprereset = viewpreresets;
}
return ret;
}
// Looks better if the other maps 'follow' the active one,
// so call this before _syncMaps
var ret = sandwich(this, function (obj) {
return L.Map.prototype.setView.call(obj, center, zoom, options);
});
if (!sync) {
originalMap._syncMaps.forEach(function (toSync) {
sandwich(toSync, function (obj) {
return toSync.setView(
originalMap._syncOffsetFns[L.Util.stamp(toSync)](center, zoom, originalMap, toSync),
zoom, options, true);
});
});
}
return ret;
},
panBy: function (offset, options, sync) {
if (!sync) {
originalMap._syncMaps.forEach(function (toSync) {
toSync.panBy(offset, options, true);
});
}
return L.Map.prototype.panBy.call(this, offset, options);
},
_onResize: function (event, sync) {
if (!sync) {
originalMap._syncMaps.forEach(function (toSync) {
toSync._onResize(event, true);
});
}
return L.Map.prototype._onResize.call(this, event);
},
_stop: function (sync) {
L.Map.prototype._stop.call(this);
if (!sync) {
originalMap._syncMaps.forEach(function (toSync) {
toSync._stop(true);
});
}
}
});
originalMap.dragging._draggable._updatePosition = function () {
L.Draggable.prototype._updatePosition.call(this);
var self = this;
originalMap._syncMaps.forEach(function (toSync) {
L.DomUtil.setPosition(toSync.dragging._draggable._element, self._newPos);
toSync.eachLayer(function (layer) {
if (layer._google !== undefined) {
var offsetFn = originalMap._syncOffsetFns[L.Util.stamp(toSync)];
var center = offsetFn(originalMap.getCenter(), originalMap.getZoom(), originalMap, toSync);
layer._google.setCenter(center);
}
});
toSync.fire('move');
});
};
}
});
})();
Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

+177
View File
@@ -0,0 +1,177 @@
{% load static %}
<html>
<head>
<title>Bloommap</title>
<link rel="shortcut icon" type="image/png" href="{% static 'favicon.ico' %}"/>
<link rel="stylesheet" href="{% static 'map/index.css' %}">
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.5.1/dist/leaflet.css"
integrity="sha512-xwE/Az9zrjBIphAcBb3F6JVqxf46+CDLwfLMHloNu6KEQCAWi6HcDUbeOfBIptF7tcCzusKFjFw2yuvEpDL9wQ=="
crossorigin=""/>
<script src="https://unpkg.com/leaflet@1.5.1/dist/leaflet.js"
integrity="sha512-GffPMF3RvMeYyc1LWMHtK8EbPv0iNZ8/oTtHPx9/cc2ILxQ+u905qIwdpULaqDkyBKgOaB57QTMg7ztg8Jm2Og=="
crossorigin=""></script>
<script src="{% static 'map/mapsync.js' %}"></script>
</head>
<body>
<div id="map1"></div>
<div id="map2"></div>
<div style="pointer-events: none; position: absolute; top: 30px; right: 40px; z-index: 1000">2019</div>
<div style="pointer-events: none; position: absolute; top: 310px; right: 40px; z-index: 1001">2029</div>
<div class="slidecontainer">
<input type="range" min="1" max="365" value="180" class="slider" id="myRange"
oninput="updateMap(this.value)">
</div>
<p id="p_date"></p>
<script>
var p_date = document.getElementById("p_date");
var map1 = L.map('map1').setView([49.4093524, 8.6931736], 15);
var map2 = L.map('map2').setView([49.4093524, 8.6931736], 15);
map1.sync(map2);
map2.sync(map1);
var tile = "https://c.tile.openstreetmap.org/{z}/{x}/{y}.png "
//var layer1 = L.tileLayer(tile, {
// attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
//}).addTo(map1);
//
//var layer2 = L.tileLayer(tile, {
// attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
//}).addTo(map2);
var layer1 = L.tileLayer('https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token={accessToken}', {
attribution: 'Map data &copy; <a href="https://www.openstreetmap.org/">OpenStreetMap</a> contributors, <a href="https://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>, Imagery © <a href="https://www.mapbox.com/">Mapbox</a>',
maxZoom: 18,
id: 'mapbox.streets',
accessToken: 'pk.eyJ1IjoicG9zdGZsYXYiLCJhIjoiY2syN29xZHVpMnlzcDNtbXZkN2tlYWdhaSJ9.Th5tmsyOlPKoogGrOQrMNA'
});
var layer2 = L.tileLayer('https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token={accessToken}', {
attribution: 'Map data &copy; <a href="https://www.openstreetmap.org/">OpenStreetMap</a> contributors, <a href="https://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>, Imagery © <a href="https://www.mapbox.com/">Mapbox</a>',
maxZoom: 18,
id: 'mapbox.streets',
accessToken: 'pk.eyJ1IjoicG9zdGZsYXYiLCJhIjoiY2syN29xZHVpMnlzcDNtbXZkN2tlYWdhaSJ9.Th5tmsyOlPKoogGrOQrMNA'
});
layer1.addTo(map1);
layer2.addTo(map2);
function mk_not_bloom_icon(label) {
return new L.DivIcon({
className: 'no-bloom-icon',
html: '<img class="no-bloom-icon" src="{% static 'map/tree_not_blooming.png' %}"/>' +
'<span>' + label + '</span>',
iconAnchor: [15, 30]
});
}
function mk_bloom_icon(label) {
return new L.DivIcon({
className: 'bloom-icon',
html: '<img class="no-bloom-icon" src="{% static 'map/tree_blooming.png' %}"/>' +
'<span>' + label + '</span>',
iconAnchor: [15, 30]
});
}
//var not_bloom_icon = L.icon({
// iconUrl: 'tree_not_blooming.png',
//
// iconSize: [40, 40], // size of the icon
// shadowSize: [0, 0], // size of the shadow
// iconAnchor: [20, 40], // point of the icon which will correspond to marker's location
// shadowAnchor: [4, 62], // the same for the shadow
// popupAnchor: [-3, -76] // point from which the popup should open relative to the iconAnchor
//});
//var bloom_icon = L.icon({
// iconUrl: 'tree_blooming.png',
//
// iconSize: [40, 40], // size of the icon
// shadowSize: [0, 0], // size of the shadow
// iconAnchor: [20, 40], // point of the icon which will correspond to marker's location
// shadowAnchor: [4, 62], // the same for the shadow
// popupAnchor: [-3, -76] // point from which the popup should open relative to the iconAnchor
//});
class Tree {
constructor(name, bloom_start, xcoord, ycoord) {
this.name = name;
this.bloom_start = bloom_start;
this.marker = L.marker([xcoord, ycoord],
{icon: mk_not_bloom_icon(this.name)});
this.blooming = false;
}
update(dayno) {
if ((dayno < this.bloom_start || dayno >= this.bloom_start + 14)
&& this.blooming) {
this.marker.setIcon(mk_not_bloom_icon(this.name));
this.blooming = false;
} else if (dayno >= this.bloom_start
&& dayno < this.bloom_start + 14
&& !this.blooming) {
this.marker.setIcon(mk_bloom_icon(this.name));
this.blooming = true;
}
}
}
var treesFromJSON = {{ trees|safe }}["trees"];
var trees_1 = [];
for (var i = 0; i < treesFromJSON.length; i++) {
let raw = treesFromJSON[i];
let tree = new Tree(raw["name"], raw["bloom_start"],
raw["latitude"], raw["longitude"]);
trees_1.push(tree);
}
var trees_2 = [];
for (var i = 0; i < treesFromJSON.length; i++) {
let raw = treesFromJSON[i];
let tree = new Tree(raw["name"], raw["bloom_start"] + 20,
raw["latitude"], raw["longitude"]);
trees_2.push(tree);
}
function updateMap(value) {
for (var i = 0; i < trees_1.length; i++) {
trees_1[i].update(value);
}
for (var i = 0; i < trees_2.length; i++) {
trees_2[i].update(value);
}
p_date.innerHTML = "Date: " + dateFromDay(value);
}
function dateFromDay(dayno) {
var date = new Date(2019, 0); // initialize a date in `year-01-01`
var date2 = new Date(date.setDate(dayno));
return date2.getMonth() + 1 + "-" + date2.getDate();
}
var cities1 = L.layerGroup(trees_1.map(t => t.marker));
var cities2 = L.layerGroup(trees_2.map(t => t.marker));
cities1.addTo(map1);
cities2.addTo(map2);
</script>
</body>
</html>
+3
View File
@@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.
+7
View File
@@ -0,0 +1,7 @@
from django.urls import path
from . import views
urlpatterns = [
path('', views.index, name='index')
]
+15
View File
@@ -0,0 +1,15 @@
from django.http import HttpResponse
from django.shortcuts import render
import json
import os
def index(request):
if not os.path.isfile("/tmp/data.json"):
data = {"trees": str({ "trees": []}) }
else:
with open("/tmp/data.json", "r") as f:
loaded = json.load(f)
s = json.dumps(loaded);
data = {"trees": s}
return render(request, "map/index.html", context=data);