start building source positioning wizard for superusers
This commit is contained in:
parent
ed0d35a105
commit
6f25708f46
3 changed files with 231 additions and 5 deletions
|
@ -8,8 +8,8 @@ from django.conf import settings
|
|||
from django.core.cache import cache
|
||||
from django.core.exceptions import FieldDoesNotExist
|
||||
from django.db.models import Q
|
||||
from django.forms import (BooleanField, CharField, ChoiceField, Form, ModelChoiceField, ModelForm, MultipleChoiceField,
|
||||
Select, ValidationError)
|
||||
from django.forms import (BooleanField, CharField, ChoiceField, DecimalField, Form, ModelChoiceField, ModelForm,
|
||||
MultipleChoiceField, Select, ValidationError)
|
||||
from django.forms.widgets import HiddenInput
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from shapely.geometry.geo import mapping
|
||||
|
@ -52,6 +52,26 @@ class EditorFormBase(I18nModelFormMixin, ModelForm):
|
|||
all_names = set(os.listdir(settings.SOURCES_ROOT))
|
||||
self.fields['name'].widget = Select(choices=tuple((s, s) for s in sorted(all_names-used_names)))
|
||||
|
||||
self.fields['fixed_x'] = DecimalField(label='fixed x', required=False,
|
||||
max_digits=7, decimal_places=3, initial=0)
|
||||
self.fields['fixed_y'] = DecimalField(label='fixed y', required=False,
|
||||
max_digits=7, decimal_places=3, initial=0)
|
||||
self.fields['scale_x'] = DecimalField(label='scale x (m/px)', required=False,
|
||||
max_digits=7, decimal_places=3, initial=1)
|
||||
self.fields['scale_y'] = DecimalField(label='scale y (m/px)', required=False,
|
||||
max_digits=7, decimal_places=3, initial=1)
|
||||
self.fields['lock_aspect'] = BooleanField(label='lock aspect ratio', required=False, initial=True)
|
||||
self.fields['lock_scale'] = BooleanField(label='lock scale (for moving)', required=False, initial=True)
|
||||
|
||||
self.fields.move_to_end('lock_scale', last=False)
|
||||
self.fields.move_to_end('lock_aspect', last=False)
|
||||
self.fields.move_to_end('scale_y', last=False)
|
||||
self.fields.move_to_end('scale_x', last=False)
|
||||
self.fields.move_to_end('fixed_y', last=False)
|
||||
self.fields.move_to_end('fixed_x', last=False)
|
||||
self.fields.move_to_end('access_restriction', last=False)
|
||||
self.fields.move_to_end('name', last=False)
|
||||
|
||||
if self._meta.model.__name__ == 'AccessRestriction':
|
||||
AccessRestrictionGroup = self.request.changeset.wrap_model('AccessRestrictionGroup')
|
||||
|
||||
|
|
|
@ -52,7 +52,7 @@ body:not(.map-enabled) #sidebar {
|
|||
padding:12px 12px 0;
|
||||
margin:auto;
|
||||
}
|
||||
#sidebar .content form .form-group:last-child {
|
||||
#sidebar .content form>.form-group:last-child {
|
||||
margin-bottom:0;
|
||||
padding:0 0 12px;
|
||||
position:sticky;
|
||||
|
@ -61,6 +61,18 @@ body:not(.map-enabled) #sidebar {
|
|||
background-color: #ffffff;
|
||||
box-shadow: 0 0 10px 10px #ffffff;
|
||||
}
|
||||
#sidebar .form-group-group {
|
||||
display: flex;
|
||||
}
|
||||
#sidebar .form-group-group .form-group {
|
||||
flex-grow: 1;
|
||||
}
|
||||
#sidebar .form-group-group .form-group:not(:last-child) {
|
||||
margin-right: 15px;
|
||||
}
|
||||
#sidebar form:not(.show-source-wizard) .source-wizard {
|
||||
display: none;
|
||||
}
|
||||
#noscript {
|
||||
font-weight:bold;
|
||||
color:red;
|
||||
|
|
|
@ -9,7 +9,7 @@ editor = {
|
|||
renderer: L.svg({ padding: 2 }),
|
||||
zoom: 2,
|
||||
maxZoom: 10,
|
||||
minZoom: 0,
|
||||
minZoom: -5,
|
||||
crs: L.CRS.Simple,
|
||||
editable: true,
|
||||
zoomSnap: 0
|
||||
|
@ -150,6 +150,51 @@ editor = {
|
|||
$('#navbar-collapse').find('.nav').html(nav.html());
|
||||
}
|
||||
|
||||
if (editor._source_image_layer) {
|
||||
editor._source_image_layer.remove();
|
||||
editor._source_image_layer = null;
|
||||
}
|
||||
|
||||
var group;
|
||||
if (content.find('[name=fixed_x]')) {
|
||||
$('[name=name]').change(editor._source_name_selected).change();
|
||||
if (!content.find('[data-new]').length) {
|
||||
var bounds = [[parseFloat(content.find('[name=left]').val()), parseFloat(content.find('[name=bottom]').val())], [parseFloat(content.find('[name=right]').val()), parseFloat(content.find('[name=top]').val())]];
|
||||
bounds = L.GeoJSON.coordsToLatLngs(bounds);
|
||||
editor.map.fitBounds(bounds, {padding: [30, 50]});
|
||||
}
|
||||
|
||||
group = $('<div class="form-group-group source-wizard">');
|
||||
group.insertBefore(content.find('[name=fixed_x]').closest('.form-group'));
|
||||
group.append(content.find('[name=fixed_x]').closest('.form-group'));
|
||||
group.append(content.find('[name=fixed_y]').closest('.form-group'));
|
||||
|
||||
group = $('<div class="form-group-group source-wizard">');
|
||||
group.insertBefore(content.find('[name=scale_x]').closest('.form-group'));
|
||||
group.append(content.find('[name=scale_x]').closest('.form-group'));
|
||||
group.append(content.find('[name=scale_y]').closest('.form-group'));
|
||||
|
||||
content.find('[name=left], [name=bottom], [name=right], [name=top]').change(editor._source_image_bounds_changed);
|
||||
content.find('[name=scale_x], [name=scale_y]').change(editor._source_image_scale_changed);
|
||||
content.find('[name=left], [name=bottom], [name=right], [name=top]').each(function() { $(this).data('oldval', $(this).val()); });
|
||||
|
||||
content.find('[name=lock_aspect], [name=lock_scale]').closest('.form-group').addClass('source-wizard');
|
||||
|
||||
var source_width = (parseFloat(content.find('[name=right]').val()) || 0) - (parseFloat(content.find('[name=left]').val()) || 0),
|
||||
source_height = (parseFloat(content.find('[name=top]').val()) || 0) - (parseFloat(content.find('[name=bottom]').val()) || 0);
|
||||
editor._source_aspect_ratio = source_width/(source_height || 1);
|
||||
}
|
||||
if (content.find('[name=left]')) {
|
||||
group = $('<div class="form-group-group">');
|
||||
group.insertBefore(content.find('[name=left]').closest('.form-group'));
|
||||
group.append(content.find('[name=left]').closest('.form-group'));
|
||||
group.append(content.find('[name=top]').closest('.form-group'));
|
||||
group = $('<div class="form-group-group">');
|
||||
group.insertBefore(content.find('[name=right]').closest('.form-group'));
|
||||
group.append(content.find('[name=right]').closest('.form-group'));
|
||||
group.append(content.find('[name=bottom]').closest('.form-group'));
|
||||
}
|
||||
|
||||
content.find('[data-toggle="tooltip"]').tooltip();
|
||||
|
||||
var modal_close = content.find('[data-modal-close]');
|
||||
|
@ -292,6 +337,148 @@ editor = {
|
|||
$.post(action, data, editor._sidebar_loaded).fail(editor._sidebar_error);
|
||||
},
|
||||
|
||||
_source_image_orig_width: 0,
|
||||
_source_image_orig_height: 0,
|
||||
_source_image_aspect_ratio: 0,
|
||||
_source_image_untouched: 0,
|
||||
_source_image_layer: null,
|
||||
_source_name_selected: function() {
|
||||
if (editor._source_image_layer) {
|
||||
editor._source_image_layer.remove();
|
||||
editor._source_image_layer = null;
|
||||
}
|
||||
$('<img src="/editor/sourceimage/'+$(this).val()+'">').on('load', editor._source_name_selected_ajax_callback);
|
||||
$('#sidebar form').removeClass('show-source-wizard');
|
||||
$('body').removeClass('map-enabled');
|
||||
},
|
||||
_source_name_selected_ajax_callback: function() {
|
||||
if ($(this).attr('src').endsWith($('#sidebar [name=name]').val())) {
|
||||
$('#sidebar form').addClass('show-source-wizard');
|
||||
$(this).appendTo('body').hide();
|
||||
editor._source_image_orig_width = $(this).width();
|
||||
editor._source_image_orig_height = $(this).height();
|
||||
$(this).remove();
|
||||
$('body').addClass('map-enabled');
|
||||
var content = $('#sidebar');
|
||||
if (content.find('[data-new]').length || isNaN(parseFloat(content.find('[name=right]').val())) || isNaN(parseFloat(content.find('[name=left]').val())) || isNaN(parseFloat(content.find('[name=top]').val())) || isNaN(parseFloat(content.find('[name=bottom]').val()))) {
|
||||
editor._source_aspect_ratio = $(this).width()/$(this).height();
|
||||
content.find('[name=left]').val(0).data('oldval', 0);
|
||||
content.find('[name=bottom]').val(0).data('oldval', 0);
|
||||
var factor = 1;
|
||||
while(factor < 1000 && (editor._source_image_orig_width/factor)>1500) {
|
||||
factor *= 10;
|
||||
}
|
||||
var width = (editor._source_image_orig_width/factor).toFixed(2),
|
||||
height = (editor._source_image_orig_height/factor).toFixed(2);
|
||||
content.find('[name=right]').val(width).data('oldval', width);
|
||||
content.find('[name=top]').val(height).data('oldval', height);
|
||||
content.find('[name=scale_x]').val(1/factor);
|
||||
content.find('[name=scale_y]').val(1/factor);
|
||||
} else {
|
||||
editor._source_image_calculate_scale();
|
||||
}
|
||||
editor._source_image_repositioned();
|
||||
}
|
||||
},
|
||||
_source_image_repositioned: function() {
|
||||
var content = $('#sidebar');
|
||||
if (isNaN(parseFloat(content.find('[name=right]').val())) || isNaN(parseFloat(content.find('[name=left]').val())) || isNaN(parseFloat(content.find('[name=top]').val())) || isNaN(parseFloat(content.find('[name=bottom]').val()))) {
|
||||
return;
|
||||
}
|
||||
var bounds = [[parseFloat(content.find('[name=left]').val()), parseFloat(content.find('[name=bottom]').val())], [parseFloat(content.find('[name=right]').val()), parseFloat(content.find('[name=top]').val())]];
|
||||
bounds = L.GeoJSON.coordsToLatLngs(bounds);
|
||||
|
||||
editor._set_max_bounds(bounds);
|
||||
if (editor._source_image_layer) {
|
||||
editor._source_image_layer.setBounds(bounds)
|
||||
} else {
|
||||
editor._source_image_layer = L.imageOverlay('/editor/sourceimage/'+content.find('[name=name]').val(), bounds, {opacity: 0.3, zIndex: 10000});
|
||||
editor._source_image_layer.addTo(editor.map);
|
||||
if (content.find('[data-new]').length) {
|
||||
editor.map.fitBounds(bounds, {padding: [30, 50]});
|
||||
}
|
||||
}
|
||||
},
|
||||
_source_image_calculate_scale: function() {
|
||||
var content = $('#sidebar');
|
||||
var source_width = parseFloat(content.find('[name=right]').val()) - parseFloat(content.find('[name=left]').val()),
|
||||
source_height = parseFloat(content.find('[name=top]').val()) - parseFloat(content.find('[name=bottom]').val());
|
||||
if (isNaN(source_width) || isNaN(source_height)) return;
|
||||
var scale_x = (source_width/editor._source_image_orig_width).toFixed(3),
|
||||
scale_y = (source_height/editor._source_image_orig_height).toFixed(3);
|
||||
content.find('[name=scale_x]').val(scale_x);
|
||||
content.find('[name=scale_y]').val(scale_y);
|
||||
if (scale_x !== scale_y) {
|
||||
content.find('[name=lock_aspect]').prop('checked', false);
|
||||
}
|
||||
},
|
||||
_source_image_bounds_changed: function() {
|
||||
var content = $('#sidebar'),
|
||||
lock_scale = content.find('[name=lock_scale]').prop('checked'),
|
||||
oldval = $(this).data('oldval'),
|
||||
newval = $(this).val(),
|
||||
diff = parseFloat(newval)-parseFloat(oldval);
|
||||
$(this).data('oldval', newval);
|
||||
if (lock_scale) {
|
||||
if (!isNaN(diff)) {
|
||||
var other_field_name = {left: 'right', right: 'left', top: 'bottom', bottom: 'top'}[$(this).attr('name')],
|
||||
other_field = content.find('[name='+other_field_name+']'),
|
||||
other_val = parseFloat(other_field.val());
|
||||
if (!isNaN(other_val)) {
|
||||
other_field.val((other_val+diff).toFixed(2)).data('oldval', other_val);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
editor._source_image_calculate_scale();
|
||||
}
|
||||
editor._source_image_repositioned();
|
||||
},
|
||||
_source_image_scale_changed: function() {
|
||||
var content = $('#sidebar'),
|
||||
lock_aspect = content.find('[name=lock_scale]').prop('checked');
|
||||
if (lock_aspect) {
|
||||
var other_field_name = {scale_x: 'scale_y', scale_y: 'scale_x'}[$(this).attr('name')],
|
||||
other_field = content.find('[name='+other_field_name+']');
|
||||
other_field.val($(this).val());
|
||||
}
|
||||
var f_scale_x = content.find('[name=scale_x]'),
|
||||
f_scale_y = content.find('[name=scale_y]'),
|
||||
scale_x = f_scale_x.val(),
|
||||
scale_y = f_scale_y.val(),
|
||||
fixed_x = parseFloat(content.find('[name=fixed_x]').val()),
|
||||
fixed_y = parseFloat(content.find('[name=fixed_y]').val()),
|
||||
left = parseFloat(content.find('[name=left]').val()),
|
||||
bottom = parseFloat(content.find('[name=bottom]').val()),
|
||||
right = parseFloat(content.find('[name=right]').val()),
|
||||
top = parseFloat(content.find('[name=top]').val());
|
||||
|
||||
scale_x = parseFloat(scale_x);
|
||||
scale_y = parseFloat(scale_y);
|
||||
|
||||
if (isNaN(scale_x) || isNaN(scale_y) || isNaN(fixed_x) || isNaN(fixed_y) || isNaN(left) || isNaN(bottom) || isNaN(right) || isNaN(top)) return;
|
||||
|
||||
var fixed_x_relative = (fixed_x-left)/(right-left),
|
||||
fixed_y_relative = (fixed_y-bottom)/(top-bottom),
|
||||
width = editor._source_image_orig_width*scale_x,
|
||||
height = editor._source_image_orig_height*scale_y,
|
||||
left = fixed_x-(width*fixed_x_relative),
|
||||
bottom = fixed_y-(height*fixed_y_relative),
|
||||
right = left+width,
|
||||
top = bottom+height;
|
||||
|
||||
left = left.toFixed(2);
|
||||
bottom = bottom.toFixed(2);
|
||||
right = right.toFixed(2);
|
||||
top = top.toFixed(2);
|
||||
|
||||
content.find('[name=left]').val(left).data('oldval', left);
|
||||
content.find('[name=bottom]').val(bottom).data('oldval', bottom);
|
||||
content.find('[name=right]').val(right).data('oldval', right);
|
||||
content.find('[name=top]').val(top).data('oldval', top);
|
||||
|
||||
editor._source_image_repositioned();
|
||||
},
|
||||
|
||||
// geometries
|
||||
geometrystyles: {},
|
||||
_loading_geometry: false,
|
||||
|
@ -314,6 +501,7 @@ editor = {
|
|||
_arrow_colors: [],
|
||||
_last_vertex: null,
|
||||
_orig_vertex_pos: null,
|
||||
_max_bounds: null,
|
||||
init_geometries: function () {
|
||||
// init geometries and edit listeners
|
||||
editor._highlight_layer = L.layerGroup().addTo(editor.map);
|
||||
|
@ -376,13 +564,18 @@ editor = {
|
|||
editor.geometrystyles = geometrystyles;
|
||||
$.getJSON('/api/editor/bounds/', function(bounds) {
|
||||
bounds = L.GeoJSON.coordsToLatLngs(bounds.bounds);
|
||||
editor.map.setMaxBounds(bounds);
|
||||
editor._max_bounds = bounds;
|
||||
editor._set_max_bounds();
|
||||
editor.map.fitBounds(bounds, {padding: [30, 50]});
|
||||
editor.init_sidebar();
|
||||
});
|
||||
});
|
||||
editor.get_sources();
|
||||
},
|
||||
_set_max_bounds: function(bounds) {
|
||||
bounds = bounds ? L.latLngBounds(editor._max_bounds[0], editor._max_bounds[1]).extend(bounds) : editor._max_bounds;
|
||||
editor.map.setMaxBounds(bounds);
|
||||
},
|
||||
_last_geometry_url: null,
|
||||
load_geometries: function (geometry_url, highlight_type, editing_id) {
|
||||
// load geometries from url
|
||||
|
@ -400,6 +593,7 @@ editor = {
|
|||
editor._graph_edges_from = {};
|
||||
editor._graph_edges_to = {};
|
||||
|
||||
editor._set_max_bounds();
|
||||
$.getJSON(geometry_url, function(geometries) {
|
||||
editor.map.removeLayer(editor._highlight_layer);
|
||||
editor._highlight_layer.clearLayers();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue