12 Commits

7 changed files with 156 additions and 14 deletions

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

@@ -55,6 +55,19 @@ class Place (models.Model):
longitude = models.FloatField()
description = models.TextField()
# Get center position of all LP-geocoordinates.
def average_latlon():
place_list = Place.objects.all()
amount = len(place_list)
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

File diff suppressed because one or more lines are too long

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

@@ -7,6 +7,7 @@
<div class="LP-PlaceGrid">
<h1 class="LP-Headline LP-Headline">Explore the latest locations</h1>
{% include 'partials/osm_map.html' %}
<ul class="LP-PlaceGrid__Grid">
{% for place in place_list %}
<li class="LP-PlaceGrid__Item">

View File

@@ -0,0 +1,71 @@
{% load static %}
<div id="map" class="map"></div>
<div id="info" class="map-popup"></div>
<script src="{% static 'ol.js' %}"></script>
<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([{{average_latlon|last}}, {{average_latlon|first}}]),
zoom: 6
})
});
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: '/{{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

@@ -64,8 +64,10 @@ class PlaceDetailView(IsAuthenticated, View):
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()
context = {
'place_list': place_list
'place_list': place_list,
'place_map_center': place_map_center
}
return render(request, 'home.html', context)