add legend / color key API endpoint
This commit is contained in:
parent
839d4beb7c
commit
d49b6d6645
4 changed files with 65 additions and 4 deletions
|
@ -2,6 +2,7 @@ import json
|
||||||
from typing import Annotated, Union
|
from typing import Annotated, Union
|
||||||
|
|
||||||
from django.core.serializers.json import DjangoJSONEncoder
|
from django.core.serializers.json import DjangoJSONEncoder
|
||||||
|
from django.db.models import Prefetch
|
||||||
from django.shortcuts import redirect
|
from django.shortcuts import redirect
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from ninja import Query
|
from ninja import Query
|
||||||
|
@ -15,14 +16,16 @@ from c3nav.api.exceptions import API404, APIPermissionDenied, APIRequestValidati
|
||||||
from c3nav.api.schema import BaseSchema
|
from c3nav.api.schema import BaseSchema
|
||||||
from c3nav.api.utils import NonEmptyStr
|
from c3nav.api.utils import NonEmptyStr
|
||||||
from c3nav.mapdata.api.base import api_etag, api_stats, can_access_geometry
|
from c3nav.mapdata.api.base import api_etag, api_stats, can_access_geometry
|
||||||
from c3nav.mapdata.models import Source
|
from c3nav.mapdata.models import Source, Theme, Area, Space
|
||||||
from c3nav.mapdata.models.locations import DynamicLocation, LocationRedirect, Position
|
from c3nav.mapdata.models.geometry.space import ObstacleGroup, Obstacle
|
||||||
|
from c3nav.mapdata.models.locations import DynamicLocation, LocationRedirect, Position, LocationGroup
|
||||||
|
from c3nav.mapdata.render.theme import ColorManager
|
||||||
from c3nav.mapdata.schemas.filters import BySearchableFilter, RemoveGeometryFilter
|
from c3nav.mapdata.schemas.filters import BySearchableFilter, RemoveGeometryFilter
|
||||||
from c3nav.mapdata.schemas.model_base import AnyLocationID, AnyPositionID, CustomLocationID
|
from c3nav.mapdata.schemas.model_base import AnyLocationID, AnyPositionID, CustomLocationID
|
||||||
from c3nav.mapdata.schemas.models import (AnyPositionStatusSchema, FullListableLocationSchema, FullLocationSchema,
|
from c3nav.mapdata.schemas.models import (AnyPositionStatusSchema, FullListableLocationSchema, FullLocationSchema,
|
||||||
LocationDisplay, ProjectionPipelineSchema, ProjectionSchema,
|
LocationDisplay, ProjectionPipelineSchema, ProjectionSchema,
|
||||||
SlimListableLocationSchema, SlimLocationSchema, all_location_definitions,
|
SlimListableLocationSchema, SlimLocationSchema, all_location_definitions,
|
||||||
listable_location_definitions)
|
listable_location_definitions, LegendSchema, LegendItemSchema)
|
||||||
from c3nav.mapdata.schemas.responses import LocationGeometry, WithBoundsSchema
|
from c3nav.mapdata.schemas.responses import LocationGeometry, WithBoundsSchema
|
||||||
from c3nav.mapdata.utils.locations import (get_location_by_id_for_request, get_location_by_slug_for_request,
|
from c3nav.mapdata.utils.locations import (get_location_by_id_for_request, get_location_by_slug_for_request,
|
||||||
searchable_locations_for_request, visible_locations_for_request)
|
searchable_locations_for_request, visible_locations_for_request)
|
||||||
|
@ -329,3 +332,40 @@ def get_projection(request):
|
||||||
'rotation_matrix': settings.PROJECTION_ROTATION_MATRIX,
|
'rotation_matrix': settings.PROJECTION_ROTATION_MATRIX,
|
||||||
})
|
})
|
||||||
return obj
|
return obj
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
|
Legend
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
@map_api_router.get('/legend/{theme_id}/', summary="get legend",
|
||||||
|
description="Get legend / color key fo theme",
|
||||||
|
response={200: LegendSchema, **API404.dict(), **auth_responses})
|
||||||
|
@api_etag(permissions=True)
|
||||||
|
def legend_for_theme(request, theme_id: int):
|
||||||
|
try:
|
||||||
|
manager = ColorManager.for_theme(theme_id or None)
|
||||||
|
except Theme.DoesNotExist:
|
||||||
|
raise API404()
|
||||||
|
locationgroups = LocationGroup.qs_for_request(request).filter(in_legend=True).prefetch_related(
|
||||||
|
Prefetch('areas', Area.qs_for_request(request))
|
||||||
|
).prefetch_related(
|
||||||
|
Prefetch('spaces', Space.qs_for_request(request))
|
||||||
|
)
|
||||||
|
obstaclegroups = ObstacleGroup.objects.filter(
|
||||||
|
pk__in=set(Obstacle.qs_for_request(request).filter(group__isnull=False).values_list('group', flat=True)),
|
||||||
|
)
|
||||||
|
return LegendSchema(
|
||||||
|
base=[],
|
||||||
|
groups=[item for item in (LegendItemSchema(title=group.title,
|
||||||
|
fill=manager.locationgroup_fill_color(group),
|
||||||
|
border=manager.locationgroup_border_color(group))
|
||||||
|
for group in locationgroups if group.areas.all() or group.spaces.all())
|
||||||
|
if item.fill or item.border],
|
||||||
|
obstacles=[item for item in (LegendItemSchema(title=group.title,
|
||||||
|
fill=manager.obstaclegroup_fill_color(group),
|
||||||
|
border=manager.obstaclegroup_border_color(group))
|
||||||
|
for group in obstaclegroups)
|
||||||
|
if item.fill or item.border],
|
||||||
|
)
|
||||||
|
|
|
@ -8,6 +8,8 @@ def forwards_func(apps, schema_editor):
|
||||||
for group in LocationGroup.objects.all():
|
for group in LocationGroup.objects.all():
|
||||||
group.in_legend = bool(group.color and (group.can_describe or group.can_search))
|
group.in_legend = bool(group.color and (group.can_describe or group.can_search))
|
||||||
group.save()
|
group.save()
|
||||||
|
ObstacleGroup = apps.get_model('mapdata', 'ObstacleGroup')
|
||||||
|
ObstacleGroup.objects.filter(color__isnull=False).update(in_legend=True)
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
@ -27,5 +29,10 @@ class Migration(migrations.Migration):
|
||||||
name='data',
|
name='data',
|
||||||
field=models.JSONField(default=dict, verbose_name='Measurement list'),
|
field=models.JSONField(default=dict, verbose_name='Measurement list'),
|
||||||
),
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='obstaclegroup',
|
||||||
|
name='in_legend',
|
||||||
|
field=models.BooleanField(default=False, verbose_name='show in legend (if color set)'),
|
||||||
|
),
|
||||||
migrations.RunPython(forwards_func, migrations.RunPython.noop),
|
migrations.RunPython(forwards_func, migrations.RunPython.noop),
|
||||||
]
|
]
|
|
@ -13,7 +13,7 @@ from shapely.geometry import CAP_STYLE, JOIN_STYLE, mapping
|
||||||
|
|
||||||
from c3nav.mapdata.fields import GeometryField, I18nField
|
from c3nav.mapdata.fields import GeometryField, I18nField
|
||||||
from c3nav.mapdata.grid import grid
|
from c3nav.mapdata.grid import grid
|
||||||
from c3nav.mapdata.models import Space
|
from c3nav.mapdata.models import Space, Level
|
||||||
from c3nav.mapdata.models.access import AccessRestrictionMixin
|
from c3nav.mapdata.models.access import AccessRestrictionMixin
|
||||||
from c3nav.mapdata.models.base import SerializableMixin, TitledMixin
|
from c3nav.mapdata.models.base import SerializableMixin, TitledMixin
|
||||||
from c3nav.mapdata.models.geometry.base import GeometryMixin
|
from c3nav.mapdata.models.geometry.base import GeometryMixin
|
||||||
|
@ -182,6 +182,7 @@ class Ramp(SpaceGeometryMixin, models.Model):
|
||||||
|
|
||||||
class ObstacleGroup(TitledMixin, models.Model):
|
class ObstacleGroup(TitledMixin, models.Model):
|
||||||
color = models.CharField(max_length=32, null=True, blank=True)
|
color = models.CharField(max_length=32, null=True, blank=True)
|
||||||
|
in_legend = models.BooleanField(default=False, verbose_name=_('show in legend (if color set)'))
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = _('Obstacle Group')
|
verbose_name = _('Obstacle Group')
|
||||||
|
|
|
@ -805,6 +805,7 @@ class ProjectionPipelineSchema(BaseSchema):
|
||||||
example='+proj=utm +zone=33 +ellps=GRS80 +units=m +no_defs'
|
example='+proj=utm +zone=33 +ellps=GRS80 +units=m +no_defs'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class ProjectionSchema(ProjectionPipelineSchema):
|
class ProjectionSchema(ProjectionPipelineSchema):
|
||||||
proj4: NonEmptyStr = APIField(
|
proj4: NonEmptyStr = APIField(
|
||||||
title='proj4 string',
|
title='proj4 string',
|
||||||
|
@ -836,3 +837,15 @@ class ProjectionSchema(ProjectionPipelineSchema):
|
||||||
0, 0, 0, 1
|
0, 0, 0, 1
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class LegendItemSchema(BaseSchema):
|
||||||
|
title: NonEmptyStr = APIField()
|
||||||
|
fill: str | None
|
||||||
|
border: str | None
|
||||||
|
|
||||||
|
|
||||||
|
class LegendSchema(BaseSchema):
|
||||||
|
base: list[LegendItemSchema]
|
||||||
|
groups: list[LegendItemSchema]
|
||||||
|
obstacles: list[LegendItemSchema]
|
Loading…
Add table
Add a link
Reference in a new issue