35 Commits

Author SHA1 Message Date
ffef52269a SVG Icons as a dependency 2020-08-26 19:31:06 +02:00
9a30ced90c Calculates correct map_center for paginated place_list. 2020-08-22 09:58:57 +02:00
d44bf0c0f2 Customized PlaceListView to provide data for map rendering. 2020-08-22 09:24:50 +02:00
cad53c070c Added map to place_list, but place_center_map is still a bit off. 2020-08-22 09:23:12 +02:00
a0627761a7 Fixed indentation again. Because I'm stupid ;-) 2020-08-22 09:22:20 +02:00
04940a0901 Added ol.css.map to static files and noted it down in linklist. 2020-08-22 09:19:50 +02:00
3ef31eda0f Added OSM map to place_detail view and template. 2020-08-22 09:19:01 +02:00
7cb8bc6bac Added place_list sorting to sort by name. 2020-08-22 02:59:04 +02:00
636bb880c1 Removed debug output. 2020-08-21 20:38:52 +02:00
c9d9ca9de0 Indentation fixed to 4 spaces. 2020-08-21 20:38:05 +02:00
5f3be5fc83 Pointed template to new location of static map files. 2020-08-21 10:33:56 +02:00
f916ac9742 Removed obsolete include of static files function. 2020-08-21 10:33:33 +02:00
03af8a0c02 Made the center of the map consider only shown places (dynamic). 2020-08-21 10:31:30 +02:00
65f3642272 Added note to where these files were pulled from. 2020-08-21 10:30:17 +02:00
e00a0f687b Moved static osm_map files to subfolder. 2020-08-21 10:29:59 +02:00
9af55d3f24 Made place urls dynamic, changed zoom level. Works so far - but div is still 0px high :P. 2020-08-20 23:49:16 +02:00
719e75a449 Reverted to paginate by 5 in place_list. 2020-08-20 23:33:33 +02:00
6688536a78 Revert "Reverted to paginate by 5 in place_list."
This reverts commit 7835ddcf16.
2020-08-20 23:32:52 +02:00
7835ddcf16 Reverted to paginate by 5 in place_list. 2020-08-20 23:32:27 +02:00
3caada8f08 Moved additional headers to parent template. 2020-08-20 23:07:52 +02:00
4113811c5f Added and included ol.css. 2020-08-20 22:46:56 +02:00
a660763ea4 Corrected map_center_coords variables. 2020-08-20 22:08:35 +02:00
55fe79b82c Added missing ol.js.map. 2020-08-20 22:02:47 +02:00
b34e88a3ad Formatting. 2020-08-20 21:50:00 +02:00
f52dd733d8 Inluded ol.js. 2020-08-20 21:47:44 +02:00
ff428beaef Added ol.js for map rendering. 2020-08-20 21:44:05 +02:00
e8c4faff8e Minor corrections. 2020-08-20 21:38:35 +02:00
0b0a401486 Added export of place coords to home conext. 2020-08-20 21:38:01 +02:00
2b56eed759 Added OSM map partial, Place model function and added it to home. 2020-08-20 21:37:27 +02:00
e387091da6 Removed obsoleted JS. 2020-08-20 21:07:39 +02:00
5c5ad9502c Updated dependencies 2020-08-18 14:35:13 +02:00
baf3f54e1a Again 2020-08-18 14:24:29 +02:00
8cb7e61274 Fixed formatting 2020-08-18 14:24:08 +02:00
fa1274c595 Merge branch 'master' of mowoe.com:reverend/lostplaces-backend into master 2020-08-18 14:22:35 +02:00
a5839c2c36 Added installation instructions 2020-08-18 14:22:33 +02:00
15 changed files with 194 additions and 16 deletions

View File

@@ -11,6 +11,7 @@ django = "*"
easy-thumbnails = "*"
image = "*"
django-widget-tweaks = "*"
django-svg-icons = "*"
# Commented out to not explicitly specify Python 3 subversion.
# [requires]

View File

@@ -9,7 +9,11 @@ Right now it depends on the following non-core Python 3 libraries. These can be
* [django](https://www.djangoproject.com/) django is a high-level Python Web framework that encourages rapid development and clean, pragmatic design.
* [easy-thumbnails](https://github.com/SmileyChris/easy-thumbnails) A powerful, yet easy to implement thumbnailing application for Django 1.11+
* [image](https://github.com/francescortiz/image) Image cropping for django
* [django-widget-tweaks](https://github.com/jazzband/django-widget-tweaks) Tweak the form field rendering in templates, not in python-level form definitions.
## Development
### Setting up a (pipenv) virtual environment for development
After having obtained the repository contents (either via .zip download or git clone), you can easily setup a pipenv virtual environment. The repo provides a Pipfile for easy dependency management that does not mess with your system.
@@ -18,6 +22,7 @@ After having obtained the repository contents (either via .zip download or git c
$ cd lostplaces-backend
$ pipenv install
$ pipenv shell
(lostplaces-backend) $ lostplaces/manage.py makemigrations
(lostplaces-backend) $ lostplaces/manage.py migrate
(lostplaces-backend) $ lostplaces/manage.py createsuperuser
(lostplaces-backend) $ lostplaces/manage.py runserver
@@ -33,4 +38,65 @@ $ pipenv shell
Visit: [admin](http://localhost:8000/admin) for administrative backend or
[frontend](http://localhost:8000/)
## Installing lostplaces
### Install dependencies
Python3, Django3, easy-thumbnails, image, django-widget-tweaks
```
pip install --user django easy-thumbnails image django-widget-tweaks
```
Or, if you use pipenv
```
pipenv install
```
### Add 'lostplaces_app' to your INSTALLED_APPS setting like this
```
INSTALLED_APPS = [
...
'lostplaces_app',
'easy_thumbnails',
'widget_tweaks',
]
```
### Add this configuration to your settings.py
```
from django.urls import reverse_lazy
...
AUTH_USER_MODEL = 'lostplaces_app.Explorer'
LOGIN_URL = reverse_lazy('login')
THUMBNAIL_ALIASES = {
'': {
'thumbnail': {'size': (300, 300), 'crop': False},
'hero': {'size': (700, 700), 'crop': False},
'large': {'size': (1920, 1920), 'crop': False},
},
}
```
### Include the lostplaces URLconf in your project urls.py like this
```
from django.urls import path, include
...
urlpatterns = [
...
path('lostplaces/', include('lostplaces_app.urls')),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
```
Run ``python manage.py migrate`` to create the lost places models.
Start the development server and visit http://127.0.0.1:8000/admin/
Visit http://127.0.0.1:8000/lostplaces/ to CRUD lost places.
Happy developing ;-)

View File

@@ -44,6 +44,7 @@ INSTALLED_APPS = [
'django.contrib.staticfiles',
'easy_thumbnails',
'widget_tweaks',
'svg_icons'
]
MIDDLEWARE = [

View File

@@ -55,6 +55,19 @@ class Place (models.Model):
longitude = models.FloatField()
description = models.TextField()
# Get center position of LP-geocoordinates.
def average_latlon(place_list):
amount = len(place_list)
# Init fill values to prevent None
longitude = 0
latitude = 0
for place in place_list:
longitude += place.longitude
latitude += place.latitude
return (latitude / amount, longitude / amount)
def __str__(self):
return self.name

View File

@@ -0,0 +1,2 @@
.ol-box{box-sizing:border-box;border-radius:2px;border:2px solid #00f}.ol-mouse-position{top:8px;right:8px;position:absolute}.ol-scale-line{background:rgba(0,60,136,.3);border-radius:4px;bottom:8px;left:8px;padding:2px;position:absolute}.ol-scale-line-inner{border:1px solid #eee;border-top:none;color:#eee;font-size:10px;text-align:center;margin:1px;will-change:contents,width;transition:all .25s}.ol-scale-bar{position:absolute;bottom:8px;left:8px}.ol-scale-step-marker{width:1px;height:15px;background-color:#000;float:right;z-Index:10}.ol-scale-step-text{position:absolute;bottom:-5px;font-size:12px;z-Index:11;color:#000;text-shadow:-2px 0 #fff,0 2px #fff,2px 0 #fff,0 -2px #fff}.ol-scale-text{position:absolute;font-size:14px;text-align:center;bottom:25px;color:#000;text-shadow:-2px 0 #fff,0 2px #fff,2px 0 #fff,0 -2px #fff}.ol-scale-singlebar{position:relative;height:10px;z-Index:9;border:1px solid #000}.ol-unsupported{display:none}.ol-unselectable,.ol-viewport{-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-tap-highlight-color:transparent}.ol-overlaycontainer,.ol-overlaycontainer-stopevent{pointer-events:none}.ol-overlaycontainer-stopevent>*,.ol-overlaycontainer>*{pointer-events:auto}.ol-selectable{-webkit-touch-callout:default;-webkit-user-select:text;-moz-user-select:text;-ms-user-select:text;user-select:text}.ol-grabbing{cursor:-webkit-grabbing;cursor:-moz-grabbing;cursor:grabbing}.ol-grab{cursor:move;cursor:-webkit-grab;cursor:-moz-grab;cursor:grab}.ol-control{position:absolute;background-color:rgba(255,255,255,.4);border-radius:4px;padding:2px}.ol-control:hover{background-color:rgba(255,255,255,.6)}.ol-zoom{top:.5em;left:.5em}.ol-rotate{top:.5em;right:.5em;transition:opacity .25s linear,visibility 0s linear}.ol-rotate.ol-hidden{opacity:0;visibility:hidden;transition:opacity .25s linear,visibility 0s linear .25s}.ol-zoom-extent{top:4.643em;left:.5em}.ol-full-screen{right:.5em;top:.5em}.ol-control button{display:block;margin:1px;padding:0;color:#fff;font-size:1.14em;font-weight:700;text-decoration:none;text-align:center;height:1.375em;width:1.375em;line-height:.4em;background-color:rgba(0,60,136,.5);border:none;border-radius:2px}.ol-control button::-moz-focus-inner{border:none;padding:0}.ol-control button span{pointer-events:none}.ol-zoom-extent button{line-height:1.4em}.ol-compass{display:block;font-weight:400;font-size:1.2em;will-change:transform}.ol-touch .ol-control button{font-size:1.5em}.ol-touch .ol-zoom-extent{top:5.5em}.ol-control button:focus,.ol-control button:hover{text-decoration:none;background-color:rgba(0,60,136,.7)}.ol-zoom .ol-zoom-in{border-radius:2px 2px 0 0}.ol-zoom .ol-zoom-out{border-radius:0 0 2px 2px}.ol-attribution{text-align:right;bottom:.5em;right:.5em;max-width:calc(100% - 1.3em)}.ol-attribution ul{margin:0;padding:0 .5em;color:#000;text-shadow:0 0 2px #fff}.ol-attribution li{display:inline;list-style:none}.ol-attribution li:not(:last-child):after{content:" "}.ol-attribution img{max-height:2em;max-width:inherit;vertical-align:middle}.ol-attribution button,.ol-attribution ul{display:inline-block}.ol-attribution.ol-collapsed ul{display:none}.ol-attribution:not(.ol-collapsed){background:rgba(255,255,255,.8)}.ol-attribution.ol-uncollapsible{bottom:0;right:0;border-radius:4px 0 0}.ol-attribution.ol-uncollapsible img{margin-top:-.2em;max-height:1.6em}.ol-attribution.ol-uncollapsible button{display:none}.ol-zoomslider{top:4.5em;left:.5em;height:200px}.ol-zoomslider button{position:relative;height:10px}.ol-touch .ol-zoomslider{top:5.5em}.ol-overviewmap{left:.5em;bottom:.5em}.ol-overviewmap.ol-uncollapsible{bottom:0;left:0;border-radius:0 4px 0 0}.ol-overviewmap .ol-overviewmap-map,.ol-overviewmap button{display:inline-block}.ol-overviewmap .ol-overviewmap-map{border:1px solid #7b98bc;height:150px;margin:2px;width:150px}.ol-overviewmap:not(.ol-collapsed) button{bottom:1px;left:2px;position:absolute}.ol-overviewmap.ol-collapsed .ol-overviewmap-map,.ol-overviewmap.ol-uncollapsible button{display:none}.ol-overviewmap:not(.ol-collapsed){background:rgba(255,255,255,.8)}.ol-overviewmap-box{border:2px dotted rgba(0,60,136,.7)}.ol-overviewmap .ol-overviewmap-box:hover{cursor:move}
/*# sourceMappingURL=ol.css.map */

View File

@@ -0,0 +1 @@
{"version":3,"sources":["src/ol/ol.css"],"names":[],"mappings":"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"}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,7 @@
# Keeping these files up-to-date is something for CI / release management.
# But for now I noted the source urls down here for later reference.
https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.3.1/css/ol.css
https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.3.1/css/ol.css.map
https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.3.1/build/ol.js
https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.3.1/build/ol.js.map

View File

@@ -12,19 +12,6 @@
{% block additional_head %}
{% endblock additional_head %}
<script>
document.addEventListener("DOMContentLoaded", function(){
Array.from(document.getElementsByClassName('LP-Main__Sidebar')).forEach(function(element){
element.classList.add('LP-Main__Sidebar--hidden')
})
setTimeout(function(){
Array.from(document.getElementsByClassName('LP-Main__Sidebar')).forEach(function(element){
element.classList.remove('LP-Main__Sidebar--hidden')
})
}, 500)
})
</script>
</head>

View File

@@ -1,10 +1,15 @@
{% extends 'global.html'%}
{% load static %}
{% block additional_head %}
<link rel="stylesheet" href="{% static 'maps/ol.css' %}" type="text/css">
<script src="{% static 'maps/ol.js' %}"></script>
{% endblock additional_head %}
# {% block title %}Start{% endblock %}
{% block maincontent %}
{% include 'partials/osm_map.html' %}
<div class="LP-PlaceGrid">
<h1 class="LP-Headline LP-Headline">Explore the latest locations</h1>
<ul class="LP-PlaceGrid__Grid">

View File

@@ -0,0 +1,69 @@
<div id="map" class="map" style="height: 300px"></div>
<div id="info" class="map-popup"></div>
<script type="text/javascript">
var map = new ol.Map({
target: 'map',
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
}),
],
view: new ol.View({
center: ol.proj.fromLonLat([{{place_map_center|last}}, {{place_map_center|first}}]),
zoom: 9
})
});
var vectorSource = new ol.source.Vector({
features: [
{% for place in place_list %}
new ol.Feature({
geometry: new ol.geom.Point(
ol.proj.fromLonLat([{{place.longitude}},{{place.latitude}}])
),
url: '{% url 'place_detail' pk=place.pk %}',
name: '{{place.name}}'
}),
{% endfor %}
]
});
var markerVectorLayer = new ol.layer.Vector({
source: vectorSource,
style: new ol.style.Style({
image: new ol.style.Icon({
anchor: [0.5, 46],
anchorXUnits: 'fraction',
anchorYUnits: 'pixels',
scale: 0.3,
src: 'http://icons.iconarchive.com/icons/paomedia/small-n-flat/128/map-marker-icon.png'
})
})
});
map.addLayer(markerVectorLayer);
var overlay = new ol.Overlay({
element: document.getElementById('info'),
positioning: 'bottom-left'
});
overlay.setMap(map);
map.on(['singleclick'], function(evt) {
var feature = map.forEachFeatureAtPixel(evt.pixel, function(feature) {
window.open(feature.get('url'), '_blank');
});
});
map.on(['pointermove'], function(evt) {
var feature = map.forEachFeatureAtPixel(evt.pixel, function(feature) {
overlay.setPosition(evt.coordinate.map(element => element + 1));
overlay.getElement().innerHTML = feature.get('name');
return feature;
});
overlay.getElement().style.display = feature ? '' : 'none';
document.body.style.cursor = feature ? 'pointer' : '';
});
</script>

View File

@@ -1,5 +1,9 @@
{% extends 'global.html'%}
{% load static %}
{% block additional_head %}
<link rel="stylesheet" href="{% static 'maps/ol.css' %}" type="text/css">
<script src="{% static 'maps/ol.js' %}"></script>
{% endblock additional_head %}
{% load thumbnail %}
{% block title %}{{place.name}}{% endblock %}
@@ -27,6 +31,7 @@
<section class="LP-Section">
<h1 class="LP-Headline">Map-Links</h1>
{% include 'partials/osm_map.html' %}
<div class="LP-LinkList">
<ul class="LP-LinkList__List">
<li class="LP-LinkList__Item"><a target="_blank" href="https://www.google.com/maps?q={{place.latitude}},{{place.longitude}}" class="LP-Link"><span class="LP-Text">Google Maps</span></a></li>

View File

@@ -1,9 +1,16 @@
{% extends 'global.html'%}
{% load static %}
{% block additional_head %}
<link rel="stylesheet" href="{% static 'maps/ol.css' %}" type="text/css">
<script src="{% static 'maps/ol.js' %}"></script>
{% endblock additional_head %}
{% block title %}Lost Places{% endblock %}
{% block maincontent %}
{% include 'partials/osm_map.html' %}
<div class="LP-PlaceList">
<h1 class="LP-Headline">Listing our places</h1>
<ul class="LP-PlaceList__List">

View File

@@ -50,22 +50,33 @@ class SignUpView(SuccessMessageMixin, CreateView):
success_message = 'User created.'
class PlaceListView(IsAuthenticated, ListView):
paginate_by = 2
paginate_by = 5
model = Place
template_name = 'place/place_list.html'
ordering = ['name']
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['place_map_center'] = Place.average_latlon(context['place_list'])
return context
class PlaceDetailView(IsAuthenticated, View):
def get(self, request, pk):
place = Place.objects.get(pk=pk)
context = {
'place': Place.objects.get(pk=pk)
'place': place,
'place_list': [ place ],
'place_map_center': [ place.latitude, place.longitude ]
}
return render(request, 'place/place_detail.html', context)
class HomeView(View):
def get(self, request, *args, **kwargs):
place_list = Place.objects.all().order_by('-submitted_when')[:10]
place_map_center = Place.average_latlon(place_list)
context = {
'place_list': place_list
'place_list': place_list,
'place_map_center': place_map_center
}
return render(request, 'home.html', context)