maps
This commit is contained in:
parent
33d02a4845
commit
20c0224bc8
53 changed files with 1329 additions and 60 deletions
15
web/nfc-theme/static/bluedot.svg
Normal file
15
web/nfc-theme/static/bluedot.svg
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
<?xml version="1.0" standalone="yes"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
|
||||
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||
<svg version="1.0" width="64" height="64" xmlns="http://www.w3.org/2000/svg">
|
||||
<defs>
|
||||
<radialGradient id="Shiny"
|
||||
cx="0.5" cy="0.5" r="0.5" fx="0.25" fy="0.25">
|
||||
<stop offset="0%" stop-color="#ffffff" />
|
||||
<stop offset="50%" stop-color="#00c0ff" />
|
||||
<stop offset="75%" stop-color="#0080ff" />
|
||||
<stop offset="100%" stop-color="#000000" />
|
||||
</radialGradient>
|
||||
</defs>
|
||||
<circle r="30" cx="32" cy="32" fill="url(#Shiny)" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 591 B |
|
|
@ -4,7 +4,12 @@ const ios = ua.indexOf("ios") > -1;
|
|||
const windows = ua.indexOf("windows") > -1;
|
||||
const linux = ua.indexOf("linux") > -1;
|
||||
const mac = ua.indexOf("macos") > -1;
|
||||
var hashlink = document.querySelector(".geo a");
|
||||
if ( windows || mac || linux ) hashlink.href = "https://maps.google.com/?q=" + hashlink.getAttribute("latlon");
|
||||
else if ( android ) hashlink.href = "geo:0,0?q=" + hashlink.getAttribute("latlon");
|
||||
else if ( ios ) hashlink.href = "http://maps.apple.com/?ll=" + hashlink.getAttribute("latlon") + "&q=" + hashlink.innerHTML;
|
||||
var hashlinks = document.querySelectorAll(".geo a");
|
||||
var hasharray = [...hashlinks];
|
||||
if ( hasharray.length > 0 ) {
|
||||
hasharray.forEach(hashlink => {
|
||||
if ( windows || mac || linux ) hashlink.href = "https://maps.google.com/?q=" + hashlink.getAttribute("latlon");
|
||||
else if ( android ) hashlink.href = "geo:0,0?q=" + hashlink.getAttribute("latlon");
|
||||
else if ( ios ) hashlink.href = "http://maps.apple.com/?ll=" + hashlink.getAttribute("latlon") + "&q=" + hashlink.innerHTML;
|
||||
});
|
||||
}
|
||||
|
|
@ -141,4 +141,32 @@ blockquote {
|
|||
border: 1px solid;
|
||||
margin: 0;
|
||||
padding-left: 1em;
|
||||
}
|
||||
|
||||
#map {
|
||||
height: 100%;
|
||||
width: 100vw;
|
||||
}
|
||||
|
||||
#map img {
|
||||
border: none
|
||||
}
|
||||
|
||||
.info {
|
||||
padding: 6px 8px;
|
||||
background: white;
|
||||
background: rgba(255,255,255,0.8);
|
||||
box-shadow: 0 0 15px rgba(0,0,0,0.2);
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.info h4 {
|
||||
font-size: 1.6em;
|
||||
margin: 0 0 5px;
|
||||
color: #777;
|
||||
}
|
||||
|
||||
.info span {
|
||||
line-height: 18px;
|
||||
vertical-align: top;
|
||||
}
|
||||
82
web/nfc-theme/static/map.js
Normal file
82
web/nfc-theme/static/map.js
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
var bluedot = L.icon({
|
||||
iconUrl: '/theme/bluedot.svg',
|
||||
iconSize: [18, 18],
|
||||
iconAnchor: [9, 9],
|
||||
popupAnchor: [0, -10]
|
||||
});
|
||||
|
||||
var nfctag = L.icon({
|
||||
iconUrl: '/theme/nfclogo.svg',
|
||||
iconSize: [20, 20],
|
||||
iconAnchor: [10, 10],
|
||||
popupAnchor: [0, -12]
|
||||
});
|
||||
|
||||
const showNfcTags = L.geoJSON(nfcTags, {
|
||||
pointToLayer(feature, latlng) { return L.marker(latlng, { icon: nfctag });},
|
||||
onEachFeature
|
||||
});
|
||||
|
||||
const map = L.map('map').fitBounds(showNfcTags.getBounds());
|
||||
|
||||
const tiles = L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
||||
maxZoom: 19,
|
||||
attribution: '© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
|
||||
}).addTo(map);
|
||||
|
||||
showNfcTags.addTo(map);
|
||||
map.on('locationfound', onLocationFound);
|
||||
map.on('locationerror', onLocationError);
|
||||
map.locate({setView: false, watch: true});
|
||||
|
||||
function onEachFeature(feature, layer) {
|
||||
let popupContent = ``;
|
||||
|
||||
if (feature.properties && feature.properties.title) {
|
||||
popupContent += feature.properties.title;
|
||||
}
|
||||
|
||||
layer.bindPopup(popupContent);
|
||||
}
|
||||
|
||||
var locationMarker, locationCircle;
|
||||
pageload = true;
|
||||
|
||||
function onLocationFound(e) {
|
||||
if (locationMarker) {
|
||||
map.removeLayer(locationMarker);
|
||||
map.removeLayer(locationCircle);
|
||||
}
|
||||
const radius = e.accuracy / 2;
|
||||
if ( pageload ) {
|
||||
area = showNfcTags.getBounds();
|
||||
area.extend(e.latlng);
|
||||
map.fitBounds(area);
|
||||
map.zoomOut(1, {animate: false});
|
||||
pageload = false;
|
||||
}
|
||||
locationMarker = L.marker(e.latlng, {icon: bluedot}).addTo(map)
|
||||
locationCircle = L.circle(e.latlng, radius).addTo(map);
|
||||
}
|
||||
|
||||
function onLocationError(e) {
|
||||
alert(e.message);
|
||||
}
|
||||
|
||||
var info = L.control({position: 'topright'});
|
||||
var download = L.control({position: 'bottomleft'});
|
||||
|
||||
info.onAdd = function (map) {
|
||||
this._div = L.DomUtil.create('div', 'info'); // create a div with a class "info"
|
||||
this._div.innerHTML = '<h4>' + nfcTags["title"] + '</h4>' + '<img style="display:inline; width:18px" src="/theme/nfclogo.svg" /> <span>NFC Tag Locations</span>';
|
||||
return this._div;
|
||||
};
|
||||
|
||||
download.onAdd = function (map) {
|
||||
this._div = L.DomUtil.create('div', 'info'); // create a div with a class "info"
|
||||
this._div.innerHTML = 'Download <a href="/projects/' + nfcTags["id"] + '.gpx">GPX</a> <a href="/projects/' + nfcTags["id"] + '.kml">KML</a>';
|
||||
return this._div;
|
||||
};
|
||||
|
||||
info.addTo(map);
|
||||
download.addTo(map);
|
||||
31
web/nfc-theme/static/nfclogo.svg
Normal file
31
web/nfc-theme/static/nfclogo.svg
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
|
||||
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
|
||||
width="1600.000000pt" height="1600.000000pt" viewBox="0 0 1600.000000 1600.000000"
|
||||
preserveAspectRatio="xMidYMid meet">
|
||||
<metadata>
|
||||
Created by potrace 1.15, written by Peter Selinger 2001-2017
|
||||
</metadata>
|
||||
<g transform="translate(0.000000,1600.000000) scale(0.100000,-0.100000)"
|
||||
fill="#000000" stroke="none">
|
||||
<path d="M2697 15989 c-565 -50 -1108 -264 -1567 -619 -114 -88 -391 -362
|
||||
-484 -480 -164 -206 -340 -509 -434 -745 -84 -211 -143 -430 -184 -680 l-23
|
||||
-140 -3 -5105 c-2 -3709 0 -5145 8 -5250 70 -905 549 -1724 1304 -2229 357
|
||||
-239 778 -402 1203 -466 209 -32 404 -36 1438 -33 l1030 3 -50 29 c-473 272
|
||||
-900 980 -1135 1880 -136 521 -200 952 -262 1766 -9 116 -13 1563 -15 5719
|
||||
l-3 5564 59 -54 c33 -30 1450 -1433 3150 -3119 l3091 -3065 0 -960 0 -960
|
||||
-167 166 c-276 272 -3662 3637 -4288 4261 l-580 578 -3 -3028 c-3 -3056 0
|
||||
-3387 34 -3957 76 -1289 257 -2251 558 -2968 58 -138 195 -404 271 -527 156
|
||||
-251 434 -560 648 -719 357 -266 779 -449 1320 -571 l177 -41 2633 4 c2894 3
|
||||
2667 -2 2983 62 961 194 1787 893 2148 1816 86 221 140 430 183 709 16 108 18
|
||||
413 21 5185 2 3454 0 5117 -8 5217 -19 278 -61 490 -144 743 -374 1126 -1377
|
||||
1914 -2561 2015 -72 6 -555 10 -1200 10 l-1080 0 58 -33 c100 -56 179 -119
|
||||
297 -237 465 -463 808 -1273 979 -2310 54 -329 89 -654 123 -1145 8 -125 12
|
||||
-1627 15 -5704 l4 -5533 -39 33 c-22 19 -1074 1060 -2338 2314 -1264 1254
|
||||
-2665 2642 -3111 3085 l-813 805 0 964 0 963 1853 -1843 c1018 -1014 2152
|
||||
-2143 2520 -2508 l667 -665 0 3025 c0 1749 -4 3153 -10 3329 -57 1794 -274
|
||||
2992 -695 3838 -153 308 -311 536 -525 756 -221 227 -441 386 -735 531 -266
|
||||
131 -536 223 -883 301 l-154 34 -2596 -1 c-1429 -1 -2636 -5 -2685 -10z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.8 KiB |
|
|
@ -1 +1,20 @@
|
|||
{% extends "base.html" %}
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<section id="content">
|
||||
{% block content_title %}
|
||||
{% endblock %}
|
||||
|
||||
{% for article in articles %}
|
||||
|
||||
<article class="hentry">
|
||||
<header>
|
||||
<h2 class="entry-title">
|
||||
<a href="{{ SITEURL }}/{{ article.url }}" rel="bookmark">{{ article.category }}: {{ article.title }}</a>
|
||||
</h2>
|
||||
<span class="entry-summary">{{ article.summary }}</span>
|
||||
</header>
|
||||
</article>
|
||||
{% endfor %}
|
||||
|
||||
</section>
|
||||
{% endblock content %}
|
||||
|
|
|
|||
|
|
@ -4,10 +4,8 @@
|
|||
<div class="entry-content">
|
||||
{{ article.content }}
|
||||
{% if article.metadata.geohash %}
|
||||
<span class="geo"><a latlon="{{ article.metadata.latlon }}" href="geo:{{ article.metadata.latlon }}">{{ article.metadata.geohash }}</a></span>
|
||||
<a href="{{ SITEURL }}/{{ article.category.url }}">NFC</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</section>
|
||||
<script src="{{ SITEURL }}/theme/platform.js"></script>
|
||||
<script src="{{ SITEURL }}/theme/geo.js"></script>
|
||||
{% endblock %}
|
||||
|
|
|
|||
|
|
@ -20,4 +20,6 @@
|
|||
</footer>
|
||||
{% endif %}
|
||||
</body>
|
||||
<script src="{{ SITEURL }}/theme/platform.js"></script>
|
||||
<script src="{{ SITEURL }}/theme/geo.js"></script>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,46 @@
|
|||
{% extends "index.html" %}
|
||||
{% block content_title %}
|
||||
<h2>{{ category }}</h2>
|
||||
{% endblock %}
|
||||
<!DOCTYPE html>
|
||||
<html lang="{{ DEFAULT_LANG }}">
|
||||
<head>
|
||||
<base target="_top">
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
|
||||
<title>{{ category }}</title>
|
||||
|
||||
<link rel="shortcut icon" type="image/x-icon" href="/images/favicon.ico" />
|
||||
<link rel="stylesheet" href="{{ SITEURL }}/theme/local.css">
|
||||
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.3/dist/leaflet.css" integrity="sha256-kLaT2GOSpHechhsozzB+flnD+zUyjE2LlfWPgU04xyI=" crossorigin=""/>
|
||||
<style>
|
||||
html, body { height: 100%; margin: 0; padding: 0; }
|
||||
</style>
|
||||
<script src="https://unpkg.com/leaflet@1.9.3/dist/leaflet.js" integrity="sha256-WBkoXOwTeyKclOHuWtc+i2uENFpDZ9YPdf5Hf+D7ewM=" crossorigin=""></script>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
var nfcTags = {
|
||||
"type": "FeatureCollection",
|
||||
"title": "{{ category }}",
|
||||
"id" : "{{ category.slug }}",
|
||||
"features": [
|
||||
{% for article in articles_page.object_list %}
|
||||
{
|
||||
"type": "Feature",
|
||||
"id": "{{ article.slug }}",
|
||||
"geometry": {
|
||||
"type": "Point",
|
||||
"coordinates": [{{ article.metadata['lon'] }}, {{ article.metadata['lat'] }}]
|
||||
},
|
||||
"properties": {
|
||||
"title": "{{ article.title }}"
|
||||
},
|
||||
},
|
||||
{% endfor %}
|
||||
]
|
||||
};
|
||||
|
||||
</script>
|
||||
<div id='map'></div>
|
||||
<script src="{{ SITEURL }}/theme/map.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -1,14 +0,0 @@
|
|||
{% if GOSQUARED_SITENAME %}
|
||||
<script type="text/javascript">
|
||||
var GoSquared={};
|
||||
GoSquared.acct = "{{ GOSQUARED_SITENAME }}";
|
||||
(function(w){
|
||||
function gs(){
|
||||
w._gstc_lt=+(new Date); var d=document;
|
||||
var g = d.createElement("script"); g.type = "text/javascript"; g.async = true; g.src = "//d1l6p2sc9645hc.cloudfront.net/tracker.js";
|
||||
var s = d.getElementsByTagName("script")[0]; s.parentNode.insertBefore(g, s);
|
||||
}
|
||||
w.addEventListener?w.addEventListener("load",gs,false):w.attachEvent("onload",gs);
|
||||
})(window);
|
||||
</script>
|
||||
{% endif %}
|
||||
|
|
@ -9,7 +9,7 @@
|
|||
<article class="hentry">
|
||||
<header>
|
||||
<h2 class="entry-title">
|
||||
<a href="{{ SITEURL }}/{{ article.url }}" rel="bookmark">{{ article.title }}</a>
|
||||
<span class="geo"><a latlon="{{ article.metadata.latlon }}" href="geo:{{ article.metadata.latlon }}">{{ article.metadata.geohash }}</a></span>
|
||||
</h2>
|
||||
<span class="entry-summary">{{ article.summary }}</span>
|
||||
</header>
|
||||
|
|
@ -18,4 +18,4 @@
|
|||
|
||||
{% include 'pagination.html' %}
|
||||
</section>
|
||||
{% endblock content %}
|
||||
{% endblock content %}
|
||||
127
web/nfc-theme/templates/locate.html
Normal file
127
web/nfc-theme/templates/locate.html
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="{{ DEFAULT_LANG }}">
|
||||
<head>
|
||||
<base target="_top">
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
|
||||
<title>{{ page.name }}</title>
|
||||
|
||||
<link rel="shortcut icon" type="image/x-icon" href="/images/favicon.ico" />
|
||||
<link rel="stylesheet" href="{{ SITEURL }}/theme/local.css">
|
||||
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.3/dist/leaflet.css" integrity="sha256-kLaT2GOSpHechhsozzB+flnD+zUyjE2LlfWPgU04xyI=" crossorigin=""/>
|
||||
<style>
|
||||
html, body { height: 100%; margin: 0; padding: 0; }
|
||||
h1 {
|
||||
font-size: 4em;
|
||||
margin: 0;
|
||||
}
|
||||
</style>
|
||||
<script src="https://unpkg.com/leaflet@1.9.3/dist/leaflet.js" integrity="sha256-WBkoXOwTeyKclOHuWtc+i2uENFpDZ9YPdf5Hf+D7ewM=" crossorigin=""></script>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<div id='map'></div>
|
||||
<script>
|
||||
BITS = [16, 8, 4, 2, 1];
|
||||
BASE32 = "0123456789bcdefghjkmnpqrstuvwxyz";
|
||||
function encodeGeoHash(latitude, longitude) {
|
||||
var is_even=1;
|
||||
var i=0;
|
||||
var lat = []; var lon = [];
|
||||
var bit=0;
|
||||
var ch=0;
|
||||
var precision = 10;
|
||||
geohash = "";
|
||||
|
||||
lat[0] = -90.0; lat[1] = 90.0;
|
||||
lon[0] = -180.0; lon[1] = 180.0;
|
||||
|
||||
while (geohash.length < precision) {
|
||||
if (is_even) {
|
||||
mid = (lon[0] + lon[1]) / 2;
|
||||
if (longitude > mid) {
|
||||
ch |= BITS[bit];
|
||||
lon[0] = mid;
|
||||
} else
|
||||
lon[1] = mid;
|
||||
} else {
|
||||
mid = (lat[0] + lat[1]) / 2;
|
||||
if (latitude > mid) {
|
||||
ch |= BITS[bit];
|
||||
lat[0] = mid;
|
||||
} else
|
||||
lat[1] = mid;
|
||||
}
|
||||
|
||||
is_even = !is_even;
|
||||
if (bit < 4)
|
||||
bit++;
|
||||
else {
|
||||
geohash += BASE32[ch];
|
||||
bit = 0;
|
||||
ch = 0;
|
||||
}
|
||||
}
|
||||
return geohash;
|
||||
}
|
||||
|
||||
function copyToClipboard() {
|
||||
var copyText = document.getElementById("geohash").innerText;
|
||||
navigator.clipboard.writeText(copyText).then(() => {
|
||||
alert("Copied " + copyText + " to clipboard");
|
||||
});
|
||||
}
|
||||
|
||||
var bluedot = L.icon({
|
||||
iconUrl: '/theme/bluedot.svg',
|
||||
iconSize: [18, 18],
|
||||
iconAnchor: [9, 9],
|
||||
popupAnchor: [0, -10]
|
||||
});
|
||||
|
||||
const map = L.map('map').fitWorld();
|
||||
|
||||
const tiles = L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
||||
maxZoom: 19,
|
||||
attribution: '© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
|
||||
}).addTo(map);
|
||||
|
||||
var locationMarker, locationCircle;
|
||||
|
||||
function onLocationFound(e) {
|
||||
|
||||
if (locationMarker) {
|
||||
map.removeLayer(locationMarker);
|
||||
map.removeLayer(locationCircle);
|
||||
}
|
||||
|
||||
const radius = e.accuracy / 2;
|
||||
locationMarker = L.marker(e.latlng, {icon: bluedot}).addTo(map);
|
||||
locationCircle = L.circle(e.latlng, radius).addTo(map);
|
||||
info.update(e);
|
||||
}
|
||||
|
||||
function onLocationError(e) {
|
||||
alert(e.message);
|
||||
}
|
||||
|
||||
map.on('locationfound', onLocationFound);
|
||||
map.on('locationerror', onLocationError);
|
||||
map.locate({setView: true, watch: true});
|
||||
|
||||
var info = L.control({position: 'topright'});
|
||||
|
||||
info.onAdd = function (map) {
|
||||
this._div = L.DomUtil.create('div', 'info'); // create a div with a class "info"
|
||||
return this._div;
|
||||
};
|
||||
|
||||
info.update = function (e) {
|
||||
this._div.innerHTML = this._div.innerHTML = '<h1 id="geohash" onclick="copyToClipboard()">' + encodeGeoHash(e.latlng.lat, e.latlng.lng) + '</h1>';
|
||||
};
|
||||
|
||||
info.addTo(map);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Loading…
Add table
Add a link
Reference in a new issue