readme update

This commit is contained in:
randogoth 2023-05-02 17:06:57 +03:00
parent ab1f420086
commit 840d907235
3 changed files with 229 additions and 225 deletions

View file

@ -1,27 +1,31 @@
# GeoBlog Plugin # GeoBlog Pelican Plugin
This plugin scans for `Location: <latitude>, <longitude>` metadata in articles and displays them on a map using the included `archives.html` template. It also writes `articles.gpx` and `articles.kml` files with the same information for offline GPS devices and Apps. This plugin scans for `Location: <latitude>, <longitude>` metadata in articles and displays them on a map using the included `archives.html` template. It also writes `articles.gpx` and `articles.kml` files with the same information for offline GPS devices and Apps.
## Installation ## Installation
Copy the `geoblog` folder to your local Pelican plug-ins folder and activate the plug-in in your `pelicanconf.py` file: Copy the `geoblog` folder to your local Pelican plug-ins folder and activate the plug-in in your `pelicanconf.py` file:
``` ```
PLUGINS = ['geoblog'] PLUGINS = ['geoblog']
``` ```
Copy the `archives.html` file to your Pelican theme's `templates` folder. Copy the `archives.html` file to your Pelican theme's `templates` folder.
If you want to use it for `categories` or other `index.html` derived template files, make sure to adjust the loop accordingly: If you want to use it for `categories` or other `index.html` derived template files, make sure to adjust the loop accordingly:
``` ```
{% for article in articles %} {% for article in articles %}
``` ```
## Use ## Use
Add location coordinates as decimal latitude and longitude values to your article metadata header. The map will display markers that show a pop up with the clickable title of the article when clicked. Add location coordinates as decimal latitude and longitude values to your article metadata header. The map will display markers that show a pop up with the clickable title of the article when clicked.
``` ```
Location: 12.009621864420991, 79.81141615530888 Location: 12.009621864420991, 79.81141615530888
``` ```
## Notes
The generated map is based on [leaflet.js](https://leafletjs.com) and is highly customizable

View file

@ -1,81 +1,81 @@
from pelican import signals from pelican import signals
from xml.dom import minidom from xml.dom import minidom
settings = {} settings = {}
collection = {} collection = {}
gpx_root = '''<?xml version="1.0" encoding="UTF-8"?> gpx_root = '''<?xml version="1.0" encoding="UTF-8"?>
<gpx xmlns="http://www.topografix.com/GPX/1/1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd" version="1.1" creator="nfc.flux.vision"></gpx>''' <gpx xmlns="http://www.topografix.com/GPX/1/1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd" version="1.1" creator="nfc.flux.vision"></gpx>'''
kml_root = '''<?xml version="1.0" encoding="UTF-8"?> kml_root = '''<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://www.opengis.net/kml/2.2" xmlns:gx="http://www.google.com/kml/ext/2.2"><Document><Folder></Folder></Document></kml>''' <kml xmlns="http://www.opengis.net/kml/2.2" xmlns:gx="http://www.google.com/kml/ext/2.2"><Document><Folder></Folder></Document></kml>'''
def init(self): def init(self):
settings['files'] = self.settings.get('OUTPUT_PATH') settings['files'] = self.settings.get('OUTPUT_PATH')
def generate_latlon(generator): def generate_latlon(generator):
for article in generator.articles: for article in generator.articles:
if "location" in article.metadata: if "location" in article.metadata:
lat, lon = [float(i) for i in article.metadata['location'].replace(' ', '').split(',')] lat, lon = [float(i) for i in article.metadata['location'].replace(' ', '').split(',')]
article.metadata['lat'] = lat article.metadata['lat'] = lat
article.metadata['lon'] = lon article.metadata['lon'] = lon
def make_files(void): def make_files(void):
print(collection) print(collection)
makeGPX() makeGPX()
makeKML() makeKML()
def makeKML(): def makeKML():
if len(collection) > 0: if len(collection) > 0:
root = minidom.parseString(kml_root) root = minidom.parseString(kml_root)
folder = root.createElement('name') folder = root.createElement('name')
foldername = root.createTextNode( 'articles' ) foldername = root.createTextNode( 'articles' )
folder.appendChild( foldername ) folder.appendChild( foldername )
root.childNodes[0].childNodes[0].childNodes[0].appendChild( folder ) root.childNodes[0].childNodes[0].childNodes[0].appendChild( folder )
for place in collection: for place in collection:
placemark = root.createElement('Placemark') placemark = root.createElement('Placemark')
name = root.createElement('name') name = root.createElement('name')
title = root.createTextNode( collection[place]['name'] + ' (' + collection[place]['url'] +')') title = root.createTextNode( collection[place]['name'] + ' (' + collection[place]['url'] +')')
name.appendChild( title ) name.appendChild( title )
placemark.appendChild( name ) placemark.appendChild( name )
point = root.createElement('Point') point = root.createElement('Point')
coordinates = root.createElement('coordinates') coordinates = root.createElement('coordinates')
lat, lon = collection[place]['coordinates'].replace(' ', '').split(',') lat, lon = collection[place]['coordinates'].replace(' ', '').split(',')
latlon = root.createTextNode( lon + ',' + lat) latlon = root.createTextNode( lon + ',' + lat)
coordinates.appendChild( latlon ) coordinates.appendChild( latlon )
point.appendChild( coordinates ) point.appendChild( coordinates )
placemark.appendChild( point ) placemark.appendChild( point )
root.childNodes[0].childNodes[0].childNodes[0].appendChild( placemark ) root.childNodes[0].childNodes[0].childNodes[0].appendChild( placemark )
with open(settings['files'] + '/articles.kml', 'w') as xml_file: with open(settings['files'] + '/articles.kml', 'w') as xml_file:
root.writexml(xml_file, indent="", addindent=" ", newl='\n') root.writexml(xml_file, indent="", addindent=" ", newl='\n')
def makeGPX(): def makeGPX():
if len(collection) > 0: if len(collection) > 0:
root = minidom.parseString(kml_root) root = minidom.parseString(kml_root)
for place in collection: for place in collection:
lat, lon = collection[place]['coordinates'].replace(' ', '').split(',') lat, lon = collection[place]['coordinates'].replace(' ', '').split(',')
wpt = root.createElement('wpt') wpt = root.createElement('wpt')
wpt.setAttribute('lat', lat) wpt.setAttribute('lat', lat)
wpt.setAttribute('lon', lon) wpt.setAttribute('lon', lon)
name = root.createElement('name') name = root.createElement('name')
title = root.createTextNode( collection[place]['name'] + ' (' + collection[place]['url'] +')' ) title = root.createTextNode( collection[place]['name'] + ' (' + collection[place]['url'] +')' )
name.appendChild( title ) name.appendChild( title )
wpt.appendChild( name ) wpt.appendChild( name )
root.childNodes[0].appendChild( wpt ) root.childNodes[0].appendChild( wpt )
with open(settings['files'] + '/articles.gpx', 'w') as xml_file: with open(settings['files'] + '/articles.gpx', 'w') as xml_file:
root.writexml(xml_file, indent="", addindent=" ", newl='\n') root.writexml(xml_file, indent="", addindent=" ", newl='\n')
def geodata(generator): def geodata(generator):
for article in generator.articles: for article in generator.articles:
if "location" in article.metadata: if "location" in article.metadata:
collection.update({ collection.update({
article.slug : { article.slug : {
"url" : generator.settings['SITEURL'] + '/' + article.url, "url" : generator.settings['SITEURL'] + '/' + article.url,
"name": article.title, "name": article.title,
"coordinates": article.metadata["location"], "coordinates": article.metadata["location"],
} }
}) })
def register(): def register():
signals.initialized.connect(init) signals.initialized.connect(init)
signals.article_generator_finalized.connect(generate_latlon) signals.article_generator_finalized.connect(generate_latlon)
signals.article_generator_finalized.connect(geodata) signals.article_generator_finalized.connect(geodata)
signals.finalized.connect(make_files) signals.finalized.connect(make_files)

View file

@ -1,118 +1,118 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="{{ DEFAULT_LANG }}"> <html lang="{{ DEFAULT_LANG }}">
<head> <head>
<base target="_top"> <base target="_top">
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ SITENAME }}</title> <title>{{ SITENAME }}</title>
<link rel="shortcut icon" type="image/x-icon" href="/images/favicon.ico" /> <link rel="shortcut icon" type="image/x-icon" href="/images/favicon.ico" />
<link rel="stylesheet" href="{{ SITEURL }}/theme/local.css"> <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=""/> <link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.3/dist/leaflet.css" integrity="sha256-kLaT2GOSpHechhsozzB+flnD+zUyjE2LlfWPgU04xyI=" crossorigin=""/>
<style> <style>
html, body { height: 100%; margin: 0; padding: 0; } html, body { height: 100%; margin: 0; padding: 0; }
#map { #map {
height: 100%; height: 100%;
width: 100vw; width: 100vw;
} }
#map img { #map img {
border: none border: none
} }
.info { .info {
padding: 6px 8px; padding: 6px 8px;
background: white; background: white;
background: rgba(255,255,255,0.8); background: rgba(255,255,255,0.8);
box-shadow: 0 0 15px rgba(0,0,0,0.2); box-shadow: 0 0 15px rgba(0,0,0,0.2);
border-radius: 5px; border-radius: 5px;
} }
.info h4 { .info h4 {
font-size: 1.6em; font-size: 1.6em;
margin: 0 0 5px; margin: 0 0 5px;
color: #777; color: #777;
} }
.info span { .info span {
line-height: 18px; line-height: 18px;
vertical-align: top; vertical-align: top;
} }
</style> </style>
<script src="https://unpkg.com/leaflet@1.9.3/dist/leaflet.js" integrity="sha256-WBkoXOwTeyKclOHuWtc+i2uENFpDZ9YPdf5Hf+D7ewM=" crossorigin=""></script> <script src="https://unpkg.com/leaflet@1.9.3/dist/leaflet.js" integrity="sha256-WBkoXOwTeyKclOHuWtc+i2uENFpDZ9YPdf5Hf+D7ewM=" crossorigin=""></script>
</head> </head>
<body> <body>
<script> <script>
var mapArticles = { var mapArticles = {
"type": "FeatureCollection", "type": "FeatureCollection",
"title": "{{ SITENAME }}", "title": "{{ SITENAME }}",
"features": [ "features": [
{% for article in dates %} {% for article in dates %}
{% if article.metadata['lat'] and article.metadata['lon'] %} {% if article.metadata['lat'] and article.metadata['lon'] %}
{ {
"type": "Feature", "type": "Feature",
"id": "{{ article.slug }}", "id": "{{ article.slug }}",
"geometry": { "geometry": {
"type": "Point", "type": "Point",
"coordinates": [{{ article.metadata['lon'] }}, {{ article.metadata['lat'] }}] "coordinates": [{{ article.metadata['lon'] }}, {{ article.metadata['lat'] }}]
}, },
"properties": { "properties": {
"title": "{{ article.title }}", "title": "{{ article.title }}",
"url": "{{ SITEURL }}/{{ article.url }}" "url": "{{ SITEURL }}/{{ article.url }}"
}, },
}, },
{% endif %} {% endif %}
{% endfor %} {% endfor %}
] ]
}; };
</script> </script>
<div id='map'></div> <div id='map'></div>
<script> <script>
const showArticles = L.geoJSON(mapArticles, { const showArticles = L.geoJSON(mapArticles, {
pointToLayer(feature, latlng) { return L.marker(latlng);}, pointToLayer(feature, latlng) { return L.marker(latlng);},
onEachFeature onEachFeature
}); });
const map = L.map('map').fitBounds(showArticles.getBounds()); const map = L.map('map').fitBounds(showArticles.getBounds());
const tiles = L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', { const tiles = L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 19, maxZoom: 19,
attribution: '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>' attribution: '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
}).addTo(map); }).addTo(map);
showArticles.addTo(map); showArticles.addTo(map);
function onEachFeature(feature, layer) { function onEachFeature(feature, layer) {
let popupContent = ``; let popupContent = ``;
if (feature.properties && feature.properties.title) { if (feature.properties && feature.properties.title) {
popupContent += '<a href="'+feature.properties.url+'">' + feature.properties.title + '</a>'; popupContent += '<a href="'+feature.properties.url+'">' + feature.properties.title + '</a>';
} }
layer.bindPopup(popupContent); layer.bindPopup(popupContent);
} }
var info = L.control({position: 'topright'}); var info = L.control({position: 'topright'});
var download = L.control({position: 'bottomleft'}); var download = L.control({position: 'bottomleft'});
info.onAdd = function (map) { info.onAdd = function (map) {
this._div = L.DomUtil.create('div', 'info'); // create a div with a class "info" this._div = L.DomUtil.create('div', 'info'); // create a div with a class "info"
this._div.innerHTML = '<h4>' + mapArticles["title"] + '</h4>'; this._div.innerHTML = '<h4>' + mapArticles["title"] + '</h4>';
return this._div; return this._div;
}; };
download.onAdd = function (map) { download.onAdd = function (map) {
this._div = L.DomUtil.create('div', 'info'); // create a div with a class "info" this._div = L.DomUtil.create('div', 'info'); // create a div with a class "info"
this._div.innerHTML = 'Download <a href="{{ SITEURL }}/articles.gpx">GPX</a> <a href="{{ SITEURL }}/articles.kml">KML</a>'; this._div.innerHTML = 'Download <a href="{{ SITEURL }}/articles.gpx">GPX</a> <a href="{{ SITEURL }}/articles.kml">KML</a>';
return this._div; return this._div;
}; };
info.addTo(map); info.addTo(map);
download.addTo(map); download.addTo(map);
</script> </script>
</body> </body>
</html> </html>