6 Commits

Author SHA1 Message Date
relikd
9503f105a3 chore: update readme 2024-07-03 00:24:27 +02:00
relikd
427bdca611 feat: display field 2024-07-03 00:23:29 +02:00
relikd
cf9bd5bdf6 feat: toggle buttons reset & set-center 2024-07-03 00:23:01 +02:00
relikd
10316bd247 fix: truly hide map pin 2024-07-03 00:21:03 +02:00
relikd
ea5d41a8ad ref: remove default "returnToPrevBounds" 2024-07-03 00:16:28 +02:00
relikd
cc8833037f ref: context value "id" 2024-07-03 00:14:42 +02:00
6 changed files with 45 additions and 24 deletions

View File

@@ -4,6 +4,11 @@ Adds a fully-static location field (Leaflet) to manage location-based data witho
![screenshot](screenshot.jpg) ![screenshot](screenshot.jpg)
Features:
- Click on map or drag&drop pin to select location
- Reset button & use map-center button
- Display selected location or map center coordinates with zoom level
## Install ## Install
@@ -33,7 +38,6 @@ class Place(models.Model):
# attribution: '© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>', # attribution: '© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>',
# }, # },
# 'locate': { # 'locate': {
# 'returnToPrevBounds': True,
# 'showPopup': False, # 'showPopup': False,
# }, # },
}) })
@@ -48,7 +52,7 @@ class Place(models.Model):
| markerZoom | Initial zoom scale (on load) if a marker is set. (default: `18`) | markerZoom | Initial zoom scale (on load) if a marker is set. (default: `18`)
| tileLayer | [TileLayer](https://leafletjs.com/reference.html#tilelayer) urlTemplate (default: `"https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"`) | tileLayer | [TileLayer](https://leafletjs.com/reference.html#tilelayer) urlTemplate (default: `"https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"`)
| tileOptions | [TileLayer Options](https://leafletjs.com/reference.html#tilelayer-option) (default: `{}`) | tileOptions | [TileLayer Options](https://leafletjs.com/reference.html#tilelayer-option) (default: `{}`)
| locate | [Leaflet.Locate Options](https://github.com/domoritz/leaflet-locatecontrol#possible-options) (default: `{returnToPrevBounds: true, showPopup: false}`) | locate | [Leaflet.Locate Options](https://github.com/domoritz/leaflet-locatecontrol#possible-options) (default: `{showPopup: false}`)
## Usage ## Usage

View File

@@ -28,6 +28,7 @@ class MapLocationWidget(Widget):
def get_context(self, name, value, attrs): def get_context(self, name, value, attrs):
context = super().get_context(name, value, attrs) context = super().get_context(name, value, attrs)
context['id'] = context['widget']['attrs']['id']
context['map_options'] = json.dumps( context['map_options'] = json.dumps(
context['widget']['attrs'].get('options')) context['widget']['attrs'].get('options'))
return context return context

View File

@@ -1,12 +1,19 @@
function MapLocationInit(mapId, options = {}) { function MapLocationInit(mapId, options = {}) {
const valField = document.getElementById(mapId + '_value'); const valField = document.getElementById(mapId + '_value');
const theMap = document.getElementById(mapId + '_map'); const theMap = document.getElementById(mapId + '_map');
const resetButton = document.getElementById(mapId + '_reset'); const btnAction = document.getElementById(mapId + '_btn');
const display = document.getElementById(mapId + '_disp');
function isZero(latlng) { function isZero(latlng) {
return latlng.lat === 0 && latlng.lng === 0; return latlng.lat === 0 && latlng.lng === 0;
} }
function asString(latlng) {
if (isZero(latlng)) { return ''; }
const pos = latlng.wrap();
return pos.lat.toFixed(6) + ',' + pos.lng.toFixed(6);
}
const osm = L.tileLayer(options.tileLayer || 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', options.tileOptions); const osm = L.tileLayer(options.tileLayer || 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', options.tileOptions);
const map = L.map(mapId + '_map', { const map = L.map(mapId + '_map', {
layers: [osm], layers: [osm],
@@ -14,11 +21,7 @@ function MapLocationInit(mapId, options = {}) {
zoom: 2, zoom: 2,
...(options.map || {}) ...(options.map || {})
}); });
L.control.locate({ L.control.locate({ showPopup: false, ...(options.locate || {}) }).addTo(map);
returnToPrevBounds: true,
showPopup: false,
...(options.locate || {})
}).addTo(map);
function loadPos() { function loadPos() {
if (!valField.value) { if (!valField.value) {
@@ -27,11 +30,10 @@ function MapLocationInit(mapId, options = {}) {
return valField.value.split(','); return valField.value.split(',');
} }
} }
const marker = L.marker(loadPos(), { draggable: true }).addTo(map); const marker = L.marker(loadPos(), { draggable: true });
marker.on('move', function (e) { marker.on('move', function (e) {
const pos = map.wrapLatLng(e.latlng); valField.value = asString(e.latlng);
const flag = isZero(pos); updatePrint();
valField.value = flag ? null : pos.lat.toFixed(6) + ',' + pos.lng.toFixed(6);
}); });
map.on('click', function (e) { map.on('click', function (e) {
if (isZero(marker.getLatLng())) { if (isZero(marker.getLatLng())) {
@@ -39,20 +41,33 @@ function MapLocationInit(mapId, options = {}) {
setMapState(false); setMapState(false);
} }
}); });
resetButton.onclick = function () { btnAction.onclick = function () {
marker.setLatLng([0, 0]); const isReset = !!btnAction.dataset.reset;
setMapState(true); marker.setLatLng(isReset ? [0, 0] : map.getCenter());
setMapState(isReset ? true : false);
return false; return false;
}; };
function setMapState(initial) { function setMapState(initial) {
theMap.style.cursor = initial ? 'crosshair' : null; theMap.style.cursor = initial ? 'crosshair' : null;
marker.setOpacity(initial ? 0 : 1); initial ? marker.remove() : marker.addTo(map);
btnAction.dataset.reset = initial ? '' : '1';
btnAction.innerText = initial ? 'Set center' : 'Reset';
} }
if (isZero(marker.getLatLng())) { function updatePrint() {
setMapState(true); const prefix = valField.value
} else { ? ('pin: ' + valField.value)
: ('center: ' + asString(map.getCenter()));
display.innerText = prefix + ' zoom: ' + map.getZoom();
}
map.on('zoomend', updatePrint);
map.on('move', updatePrint);
setMapState(isZero(marker.getLatLng()));
updatePrint();
if (valField.value) {
map.setView(valField.value.split(','), options.markerZoom || 18); map.setView(valField.value.split(','), options.markerZoom || 18);
} }
// re-center map // re-center map

View File

@@ -1,8 +1,9 @@
<div style="width: 100%"> <div style="width: 100%">
<input name="{{ widget.name }}" id="{{ widget.attrs.id }}_value" type="hidden" value="{{ widget.value|default:'' }}" /> <input name="{{ widget.name }}" id="{{id}}_value" type="hidden" value="{{ widget.value|default:'' }}" />
<div id="{{ widget.attrs.id }}_map" style="width: 100%; height: 400px"></div> <div id="{{id}}_map" style="width: 100%; height: 400px"></div>
<a href="" id="{{ widget.attrs.id }}_reset">Remove</a> <a href="" id="{{id}}_btn"></a>
<span id="{{id}}_disp" style="opacity: 0.5; margin-left: 1em"></span>
<script> <script>
MapLocationInit("{{ widget.attrs.id }}", {{ map_options|safe }}); MapLocationInit("{{id}}", {{ map_options|safe }});
</script> </script>
</div> </div>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 128 KiB

After

Width:  |  Height:  |  Size: 135 KiB

View File

@@ -6,7 +6,7 @@ with open('README.md', 'r') as f:
setuptools.setup( setuptools.setup(
name='django-map-location', name='django-map-location',
description='Django Map-Location Field', description='Django Map-Location Field',
version='0.9.1', version='0.9.2',
author='relikd', author='relikd',
license='MIT', license='MIT',
long_description=long_description, long_description=long_description,