add AreaOfInterest and GroupOfInterest
This commit is contained in:
parent
52958ec5fc
commit
9c202ab6cd
11 changed files with 194 additions and 13 deletions
|
@ -61,6 +61,10 @@ class MapitemFormMixin(ModelForm):
|
|||
# set field_name
|
||||
self.fields['levels'].to_field_name = 'name'
|
||||
|
||||
if 'groups' in self.fields:
|
||||
# set field_name
|
||||
self.fields['groups'].to_field_name = 'name'
|
||||
|
||||
if 'geometry' in self.fields:
|
||||
# hide geometry widget
|
||||
self.fields['geometry'].widget = HiddenInput()
|
||||
|
@ -94,12 +98,17 @@ class MapitemFormMixin(ModelForm):
|
|||
if 'geometry' in self.fields:
|
||||
if not self.cleaned_data.get('geometry'):
|
||||
raise ValidationError('Missing geometry.')
|
||||
|
||||
if hasattr(self.instance, 'titles') and not any(self.titles.values()):
|
||||
raise ValidationError(
|
||||
_('You have to select a title in at least one language.')
|
||||
)
|
||||
super().clean()
|
||||
|
||||
|
||||
def create_editor_form(mapitemtype):
|
||||
possible_fields = ['name', 'package', 'altitude', 'level', 'intermediate', 'levels', 'geometry',
|
||||
'elevator', 'button', 'crop_to_level', 'width']
|
||||
'elevator', 'button', 'crop_to_level', 'width', 'groups']
|
||||
existing_fields = [field for field in possible_fields if hasattr(mapitemtype, field)]
|
||||
|
||||
class EditorForm(MapitemFormMixin, ModelForm):
|
||||
|
|
|
@ -29,7 +29,7 @@ form button.invisiblesubmit {
|
|||
display: block;
|
||||
}
|
||||
|
||||
.leaflet-control-layers-toggle {
|
||||
.leaflet-container .leaflet-control-layers-toggle {
|
||||
color:#000000 !important;
|
||||
font-size:14px;
|
||||
text-align:center;
|
||||
|
@ -38,7 +38,7 @@ form button.invisiblesubmit {
|
|||
background-image:none;
|
||||
padding:0 8px;
|
||||
}
|
||||
.leaflet-control-layers-expanded {
|
||||
.leaflet-container .leaflet-control-layers-expanded {
|
||||
min-width:75px;
|
||||
}
|
||||
.leaflet-levels {
|
||||
|
|
|
@ -281,7 +281,8 @@ editor = {
|
|||
'elevatorlevel': '#9EF8FB',
|
||||
'levelconnector': '#FFFF00',
|
||||
'shadow': '#000000',
|
||||
'stair': '#FF0000'
|
||||
'stair': '#FF0000',
|
||||
'areaofinterest': '#0099FF'
|
||||
},
|
||||
_line_draw_geometry_style: function(style) {
|
||||
style.stroke = true;
|
||||
|
@ -300,12 +301,19 @@ editor = {
|
|||
},
|
||||
_get_mapitem_type_style: function (mapitem_type) {
|
||||
// get styles for a specific mapitem
|
||||
return {
|
||||
var result = {
|
||||
stroke: false,
|
||||
fillColor: editor._geometry_colors[mapitem_type],
|
||||
fillOpacity: 0.6,
|
||||
fillOpacity: (mapitem_type == 'areaofinterest') ? 0.2 : 0.6,
|
||||
smoothFactor: 0
|
||||
};
|
||||
if (mapitem_type == 'areaofinterest') {
|
||||
result.fillOpacity = 0.02;
|
||||
result.color = result.fillColor;
|
||||
result.stroke = true;
|
||||
result.weight = 1;
|
||||
}
|
||||
return result;
|
||||
},
|
||||
_register_geojson_feature: function (feature, layer) {
|
||||
// onEachFeature callback for GeoJSON loader – register all needed events
|
||||
|
|
|
@ -13,7 +13,8 @@
|
|||
</tr>
|
||||
{% endif %}
|
||||
<tr data-name="{{ item.name }}">
|
||||
<td>{{ item.name }}</td>
|
||||
|
||||
<td>{% if item.title != item.name %}{{ item.title }} <small>{{ item.name }}</small>{% else %}{{ item.name }}{% endif %}</td>
|
||||
{% if has_elevator %}
|
||||
<td><a href="{% url 'editor.mapitems.edit' mapitem_type='elevator' name=item.elevator.name %}">{{ item.elevator }}</a></td>
|
||||
{% endif %}
|
||||
|
|
63
src/c3nav/mapdata/migrations/0018_auto_20161212_1205.py
Normal file
63
src/c3nav/mapdata/migrations/0018_auto_20161212_1205.py
Normal file
|
@ -0,0 +1,63 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.10.4 on 2016-12-12 12:05
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import c3nav.mapdata.fields
|
||||
import c3nav.mapdata.models.interest
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('mapdata', '0017_auto_20161208_2039'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='AreaOfInterest',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.SlugField(unique=True, verbose_name='Name')),
|
||||
('geometry', c3nav.mapdata.fields.GeometryField()),
|
||||
('titles', c3nav.mapdata.fields.JSONField()),
|
||||
],
|
||||
options={
|
||||
'default_related_name': 'areasofinterest',
|
||||
'verbose_name_plural': 'Areas of Interest',
|
||||
'verbose_name': 'Area of Interest',
|
||||
},
|
||||
bases=(models.Model, c3nav.mapdata.models.interest.MapItemOfInterestMixin),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='GroupOfInterest',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.SlugField(unique=True, verbose_name='Name')),
|
||||
('titles', c3nav.mapdata.fields.JSONField()),
|
||||
('package', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='groupsofinterest', to='mapdata.Package', verbose_name='map package')),
|
||||
],
|
||||
options={
|
||||
'default_related_name': 'groupsofinterest',
|
||||
'verbose_name_plural': 'Groups of Interest',
|
||||
'verbose_name': 'Group of Interest',
|
||||
},
|
||||
bases=(models.Model, c3nav.mapdata.models.interest.MapItemOfInterestMixin),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='areaofinterest',
|
||||
name='groups',
|
||||
field=models.ManyToManyField(blank=True, related_name='areasofinterest', to='mapdata.GroupOfInterest', verbose_name='Groups of Interest'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='areaofinterest',
|
||||
name='level',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='areasofinterest', to='mapdata.Level', verbose_name='level'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='areaofinterest',
|
||||
name='package',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='areasofinterest', to='mapdata.Package', verbose_name='map package'),
|
||||
),
|
||||
]
|
|
@ -3,3 +3,4 @@ from .package import Package # noqa
|
|||
from .source import Source # noqa
|
||||
from .collections import Elevator # noqa
|
||||
from .geometry import GeometryMapItemWithLevel, GEOMETRY_MAPITEM_TYPES # noqa
|
||||
from .interest import AreaOfInterest, GroupOfInterest # noqa
|
||||
|
|
|
@ -3,6 +3,7 @@ from collections import OrderedDict
|
|||
from django.db import models
|
||||
from django.db.models.base import ModelBase
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.utils.translation import get_language
|
||||
|
||||
from c3nav.mapdata.lastupdate import set_last_mapdata_update
|
||||
|
||||
|
@ -23,6 +24,15 @@ class MapItem(models.Model, metaclass=MapItemMeta):
|
|||
|
||||
EditorForm = None
|
||||
|
||||
@property
|
||||
def title(self):
|
||||
if not hasattr(self, 'titles'):
|
||||
return self.name
|
||||
lang = get_language()
|
||||
if lang in self.titles:
|
||||
return self.titles[lang]
|
||||
return next(iter(self.titles.values())) if self.titles else self.name
|
||||
|
||||
@classmethod
|
||||
def get_path_prefix(cls):
|
||||
return cls._meta.default_related_name + '/'
|
||||
|
|
|
@ -32,10 +32,6 @@ class GeometryMapItem(MapItem, metaclass=GeometryMapItemMeta):
|
|||
class Meta:
|
||||
abstract = True
|
||||
|
||||
@property
|
||||
def title(self):
|
||||
return self.name
|
||||
|
||||
@classmethod
|
||||
def fromfile(cls, data, file_path):
|
||||
kwargs = super().fromfile(data, file_path)
|
||||
|
|
82
src/c3nav/mapdata/models/interest.py
Normal file
82
src/c3nav/mapdata/models/interest.py
Normal file
|
@ -0,0 +1,82 @@
|
|||
from collections import OrderedDict
|
||||
|
||||
from django.db import models
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from c3nav.mapdata.fields import JSONField
|
||||
from c3nav.mapdata.models.base import MapItem
|
||||
from c3nav.mapdata.models.geometry import GeometryMapItemWithLevel
|
||||
|
||||
|
||||
# noinspection PyUnresolvedReferences
|
||||
class MapItemOfInterestMixin:
|
||||
def get_geojson_properties(self):
|
||||
result = super().get_geojson_properties()
|
||||
result['titles'] = OrderedDict(sorted(self.titles.items()))
|
||||
return result
|
||||
|
||||
@classmethod
|
||||
def fromfile(cls, data, file_path):
|
||||
kwargs = super().fromfile(data, file_path)
|
||||
|
||||
if 'titles' not in data:
|
||||
raise ValueError('missing titles.')
|
||||
titles = data['titles']
|
||||
if not isinstance(titles, dict):
|
||||
raise ValueError('Invalid titles format.')
|
||||
if any(not isinstance(lang, str) for lang in titles.keys()):
|
||||
raise ValueError('titles: All languages have to be strings.')
|
||||
if any(not isinstance(title, str) for title in titles.values()):
|
||||
raise ValueError('titles: All titles have to be strings.')
|
||||
if any(not title for title in titles.values()):
|
||||
raise ValueError('titles: Titles must not be empty strings.')
|
||||
kwargs['titles'] = titles
|
||||
return kwargs
|
||||
|
||||
def tofile(self):
|
||||
result = super().tofile()
|
||||
result['titles'] = OrderedDict(sorted(self.titles.items()))
|
||||
return result
|
||||
|
||||
|
||||
class GroupOfInterest(MapItem, MapItemOfInterestMixin):
|
||||
titles = JSONField()
|
||||
|
||||
class Meta:
|
||||
verbose_name = _('Group of Interest')
|
||||
verbose_name_plural = _('Groups of Interest')
|
||||
default_related_name = 'groupsofinterest'
|
||||
|
||||
|
||||
class AreaOfInterest(GeometryMapItemWithLevel, MapItemOfInterestMixin):
|
||||
titles = JSONField()
|
||||
groups = models.ManyToManyField(GroupOfInterest, verbose_name=_('Groups of Interest'), blank=True)
|
||||
|
||||
geomtype = 'polygon'
|
||||
|
||||
class Meta:
|
||||
verbose_name = _('Area of Interest')
|
||||
verbose_name_plural = _('Areas of Interest')
|
||||
default_related_name = 'areasofinterest'
|
||||
|
||||
@classmethod
|
||||
def fromfile(cls, data, file_path):
|
||||
kwargs = super().fromfile(data, file_path)
|
||||
|
||||
groups = data.get('groups', [])
|
||||
if not isinstance(groups, list):
|
||||
raise TypeError('groups has to be a list')
|
||||
kwargs['groups'] = groups
|
||||
|
||||
return kwargs
|
||||
|
||||
def get_geojson_properties(self):
|
||||
result = super().get_geojson_properties()
|
||||
result['groups'] = tuple(self.groups.all().order_by('name').values_list('name', flat=True))
|
||||
return result
|
||||
|
||||
def tofile(self):
|
||||
result = super().tofile()
|
||||
result['groups'] = sorted(self.groups.all().order_by('name').values_list('name', flat=True))
|
||||
result.move_to_end('geometry')
|
||||
return result
|
|
@ -1,7 +1,8 @@
|
|||
from c3nav.mapdata.models import Level, Package, Source
|
||||
from c3nav.mapdata.models import AreaOfInterest, GroupOfInterest, Level, Package, Source
|
||||
from c3nav.mapdata.models.collections import Elevator
|
||||
from c3nav.mapdata.models.geometry import (Building, Door, ElevatorLevel, Hole, LevelConnector, LineObstacle, Obstacle,
|
||||
Outside, Room, Stair)
|
||||
|
||||
ordered_models = (Package, Level, LevelConnector, Source, Building, Room, Outside, Door, Obstacle, Hole)
|
||||
ordered_models += (Elevator, ElevatorLevel, LineObstacle, Stair)
|
||||
ordered_models += (GroupOfInterest, AreaOfInterest)
|
||||
|
|
|
@ -7,7 +7,7 @@ from collections import OrderedDict
|
|||
from django.conf import settings
|
||||
from django.core.management import CommandError
|
||||
|
||||
from c3nav.mapdata.models import Elevator, Level, Package
|
||||
from c3nav.mapdata.models import AreaOfInterest, Elevator, GroupOfInterest, Level, Package
|
||||
from c3nav.mapdata.models.geometry import LevelConnector
|
||||
from c3nav.mapdata.packageio.const import ordered_models
|
||||
|
||||
|
@ -165,6 +165,11 @@ class ReaderItem:
|
|||
levels = [self.reader.saved_items[Level][name].obj.pk for name in self.data['levels']]
|
||||
self.data.pop('levels')
|
||||
|
||||
groups = []
|
||||
if self.model == AreaOfInterest:
|
||||
groups = [self.reader.saved_items[GroupOfInterest][name].obj.pk for name in self.data['groups']]
|
||||
self.data.pop('groups')
|
||||
|
||||
# Change name references to the referenced object
|
||||
for name, model in self.relations.items():
|
||||
if name in self.data:
|
||||
|
@ -186,3 +191,8 @@ class ReaderItem:
|
|||
self.obj.levels.clear()
|
||||
for level in levels:
|
||||
self.obj.levels.add(level)
|
||||
|
||||
if groups:
|
||||
self.obj.groups.clear()
|
||||
for group in groups:
|
||||
self.obj.groups.add(group)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue