Skip to content

Commit 542708b

Browse files
authored
Merge pull request #421 from WHOIGit/417-configurable-start-position-for-map
417: Allow default map settings to be configurable
2 parents 59771a6 + 4f97698 commit 542708b

File tree

10 files changed

+290
-80
lines changed

10 files changed

+290
-80
lines changed

ifcbdb/assets/js/site.js

+42-29
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,49 @@
1-
// TODO: Move default location to settings
2-
var defaultLat = 41.5507768;
3-
var defaultLng = -70.6593102;
4-
var minLatitude = -180;
5-
var minLongitude = -180;
6-
var zoomLevel = 6;
7-
var GPS_PRECISION = 4;
8-
var DEPTH_PRECISION = 1;
9-
var PLOT_X_DEFAULT = "roi_x";
10-
var PLOT_Y_DEFAULT = "roi_y";
11-
var MAX_SELECTABLE_IMAGES = 25;
12-
var _binFilterMode = "timeline";
13-
14-
$(function(){
15-
$("#dataset-switcher").change(function(){
1+
// These values are populated from app settings
2+
let defaultLat = undefined;
3+
let defaultLng = undefined;
4+
let zoomLevel = undefined;
5+
6+
// Constants
7+
const minLatitude = -180;
8+
const minLongitude = -180;
9+
const GPS_PRECISION = 4;
10+
const DEPTH_PRECISION = 1;
11+
const PLOT_X_DEFAULT = "roi_x";
12+
const PLOT_Y_DEFAULT = "roi_y";
13+
const MAX_SELECTABLE_IMAGES = 25;
14+
15+
let _binFilterMode = "timeline";
16+
17+
function initDashboard(appSettings) {
18+
defaultLat = appSettings.default_latitude;
19+
defaultLng = appSettings.default_longitude;
20+
zoomLevel = appSettings.default_zoom_level;
21+
22+
$('[data-toggle="tooltip"]').tooltip();
23+
24+
$('.navbar-toggler').on('click', function () {
25+
$('.animated-burger').toggleClass('open');
26+
});
27+
28+
// hide navbar after a bit of scrolling
29+
$(window).scroll(function (e) {
30+
var scroll = $(window).scrollTop();
31+
if (scroll >= 150) {
32+
$('.navbar').addClass("navbar-hide");
33+
} else {
34+
$('.navbar').removeClass("navbar-hide");
35+
}
36+
});
37+
38+
$("#dataset-switcher").change(function () {
1639
location.href = "/timeline?dataset=" + $(this).val();
1740
});
1841

19-
$("#go-to-bin").click(function(){
42+
$("#go-to-bin").click(function () {
2043
goToBin($("#go-to-bid-pid").val());
2144
});
2245

23-
$("#go-to-bid-pid").keypress(function(e){
46+
$("#go-to-bid-pid").keypress(function (e) {
2447
if (e.which == 13 /* Enter */) {
2548
goToBin($(this).val());
2649
}
@@ -33,7 +56,7 @@ $(function(){
3356
$('[data-toggle="popover"]').popover('hide');
3457
}
3558
});
36-
})
59+
}
3760

3861
function isKnownLocation(lat, lng) {
3962
return parseFloat(lat) >= minLatitude && parseFloat(lng) >= minLongitude;
@@ -339,17 +362,6 @@ function changeImage(img, src, blobImg, outlineImg){
339362
});
340363
}
341364

342-
/* Deprecated */
343-
/*
344-
function buildColorArray(dataPoints, index) {
345-
var colors = $.map(dataPoints, function(){ return "#1f77b4"; });
346-
if (index >= 0 && index < dataPoints.length)
347-
colors[index] = "#bb0000";
348-
349-
return colors;
350-
}
351-
*/
352-
353365
function highlightSelectedBinByDate() {
354366
if (_binTimestamp == null)
355367
return;
@@ -566,6 +578,7 @@ function isFilteringUsed() {
566578
if (_sampleType != "" && _sampleType != "null")
567579
return true;
568580
}
581+
569582
$(function () {
570583
$('#dataset-popover').popover({
571584
container: 'body',
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# Generated by Django 4.2.14 on 2024-11-01 19:46
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
('dashboard', '0036_datadirectory_unique_path'),
10+
]
11+
12+
operations = [
13+
migrations.CreateModel(
14+
name='AppSettings',
15+
fields=[
16+
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
17+
('default_latitude', models.FloatField(default=41.5507768)),
18+
('default_longitude', models.FloatField(default=-70.6593102)),
19+
('default_zoom_level', models.IntegerField(default=6)),
20+
],
21+
),
22+
]

ifcbdb/dashboard/models.py

+12
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,12 @@
4444
FILL_VALUE = -9999999
4545
SRID = 4326
4646

47+
# The default latitude and longitude reference original values that were set prior to the ability to customize the
48+
# default values. The location is, roughly, Woods Hole Oceanographic Institution
49+
DEFAULT_LATITUDE = 41.5507768
50+
DEFAULT_LONGITUDE = -70.6593102
51+
DEFAULT_ZOOM_LEVEL = 6
52+
4753
def do_nothing(*args, **kw):
4854
pass
4955

@@ -905,3 +911,9 @@ def __str__(self):
905911
else:
906912
return self.content
907913

914+
# settings
915+
916+
class AppSettings(models.Model):
917+
default_latitude = models.FloatField(blank=False, null=False, default=DEFAULT_LATITUDE)
918+
default_longitude = models.FloatField(blank=False, null=False, default=DEFAULT_LONGITUDE)
919+
default_zoom_level = models.IntegerField(blank=False, null=False, default=DEFAULT_ZOOM_LEVEL)

ifcbdb/dashboard/templatetags/nav.py

+15-1
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,24 @@
1+
import json
12
from django import template
23
from django.shortcuts import reverse
4+
from django.utils.html import mark_safe
35

4-
from dashboard.models import Dataset, Instrument, Tag, bin_query
6+
from dashboard.models import Dataset, Instrument, Tag, bin_query, AppSettings, \
7+
DEFAULT_LATITUDE, DEFAULT_LONGITUDE, DEFAULT_ZOOM_LEVEL
58

69
register = template.Library()
710

11+
@register.simple_tag(takes_context=False)
12+
def app_settings():
13+
app_settings = AppSettings.objects.first()
14+
15+
settings = json.dumps({
16+
"default_latitude": app_settings.default_latitude if app_settings else DEFAULT_LATITUDE,
17+
"default_longitude": app_settings.default_longitude if app_settings else DEFAULT_LONGITUDE,
18+
"default_zoom_level": app_settings.default_zoom_level if app_settings else DEFAULT_ZOOM_LEVEL,
19+
})
20+
21+
return mark_safe(settings)
822

923
@register.inclusion_tag('dashboard/_dataset_switcher.html')
1024
def dataset_switcher():

ifcbdb/secure/forms.py

+57-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,20 @@
11
import re, os
22
from django import forms
33

4-
from dashboard.models import Dataset, Instrument, DataDirectory
4+
from dashboard.models import Dataset, Instrument, DataDirectory, AppSettings, \
5+
DEFAULT_LATITUDE, DEFAULT_LONGITUDE, DEFAULT_ZOOM_LEVEL
6+
7+
8+
MIN_LATITUDE = -90
9+
MAX_LATITUDE = 90
10+
MIN_LONGITUDE = -180
11+
MAX_LONGITUDE = 180
12+
13+
# Leaflet does not limit the zoom level, but appears to start having issues with very large numbers. Here, it's limited
14+
# to 13 because that appears to be the limit of the basemap that's being used. Any higher than that, and it produces
15+
# "map not available" errors
16+
MIN_ZOOM_LEVEL = 0
17+
MAX_ZOOM_LEVEL = 13
518

619

720
class DatasetForm(forms.ModelForm):
@@ -168,3 +181,46 @@ class Meta:
168181

169182
class MetadataUploadForm(forms.Form):
170183
file = forms.FileField(label="Choose file", widget=forms.ClearableFileInput(attrs={"class": "custom-file-input"}))
184+
185+
186+
class AppSettingsForm(forms.ModelForm):
187+
188+
def __init__(self, *args, **kwargs):
189+
super().__init__(*args, **kwargs)
190+
191+
self.fields["default_latitude"].required = True
192+
self.fields["default_longitude"].required = True
193+
self.fields["default_zoom_level"].required = True
194+
195+
def clean_default_latitude(self):
196+
data = self.cleaned_data.get("default_latitude")
197+
198+
if data < MIN_LATITUDE or data > MAX_LATITUDE:
199+
raise forms.ValidationError(f"Default Latitude must be between {MIN_LATITUDE} and {MAX_LATITUDE}")
200+
201+
return data
202+
203+
def clean_default_longitude(self):
204+
data = self.cleaned_data.get("default_longitude")
205+
206+
if data < MIN_LONGITUDE or data > MAX_LONGITUDE:
207+
raise forms.ValidationError(f"Default Longitude must be between {MIN_LONGITUDE} and {MAX_LONGITUDE}")
208+
209+
return data
210+
211+
def clean_default_zoom_level(self):
212+
data = self.cleaned_data.get("default_zoom_level")
213+
214+
if data < MIN_ZOOM_LEVEL or data > MAX_ZOOM_LEVEL:
215+
raise forms.ValidationError(f"Default Zoom Level must be between {MIN_ZOOM_LEVEL} and {MAX_ZOOM_LEVEL}")
216+
217+
return data
218+
219+
class Meta:
220+
model = AppSettings
221+
fields = ["default_latitude", "default_longitude", "default_zoom_level", ]
222+
widgets = {
223+
"default_latitude": forms.TextInput(attrs={"class": "form-control form-control-sm"}),
224+
"default_longitude": forms.TextInput(attrs={"class": "form-control form-control-sm"}),
225+
"default_zoom_level": forms.TextInput(attrs={"class": "form-control form-control-sm"}),
226+
}

ifcbdb/secure/urls.py

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
path('upload-metadata', views.upload_metadata, name='upload-metadata'),
1616
path('directory-management/<int:dataset_id>', views.directory_management, name='directory-management'),
1717
path('edit-directory/<int:dataset_id>/<int:id>', views.edit_directory, name='edit-directory'),
18+
path('app-settings', views.app_settings, name='app-settings'),
1819

1920
# Paths used for AJAX requests specifically for returning data formatted for DataTables
2021
path('api/dt/datasets', views.dt_datasets, name='datasets_dt'),

0 commit comments

Comments
 (0)