Skip to content

Commit d432bac

Browse files
authored
Merge pull request #359 from ohmg-dev/viewer_performance
Viewer performance
2 parents 403a562 + d5bbf7b commit d432bac

4 files changed

Lines changed: 85 additions & 40 deletions

File tree

ohmg/api/schemas.py

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import json
22
import logging
33
from datetime import datetime
4-
from typing import Any, List, Literal, Optional
4+
from typing import TYPE_CHECKING, Any, List, Literal, Optional
55

66
import humanize
77
from avatar.templatetags.avatar_tags import avatar_url
@@ -23,6 +23,9 @@
2323
SessionLock,
2424
)
2525

26+
if TYPE_CHECKING:
27+
from ohmg.core.models import LayerSet
28+
2629
logger = logging.getLogger(__name__)
2730

2831

@@ -504,6 +507,34 @@ def resolve_name(obj):
504507
return str(obj.category)
505508

506509

510+
class LayerSetDisplaySchema(Schema):
511+
map_id: str
512+
category: str
513+
extent: Optional[tuple]
514+
layers_tilejson: list[dict]
515+
is_mosaic: bool
516+
517+
@staticmethod
518+
def resolve_category(obj):
519+
return str(obj.category)
520+
521+
@staticmethod
522+
def resolve_layers_tilejson(obj: "LayerSet"):
523+
layers_tilejson = []
524+
if obj.mosaic_geotiff:
525+
layers_tilejson.append(obj.tilejson)
526+
else:
527+
for layer in natsorted(obj.get_layers(), key=lambda k: k.title):
528+
tilejson = layer.tilejson
529+
tilejson["mask"] = json.loads(layer.mask.geojson) if layer.mask else None
530+
layers_tilejson.append(tilejson)
531+
return layers_tilejson
532+
533+
@staticmethod
534+
def resolve_is_mosaic(obj):
535+
return True if obj.mosaic_geotiff else False
536+
537+
507538
class PlaceSchema(Schema):
508539
"""very lightweight serialization of a Place with its Maps"""
509540

ohmg/frontend/svelte_components/src/components/Viewer.svelte

Lines changed: 42 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -27,16 +27,21 @@
2727
2828
import XYZ from 'ol/source/XYZ';
2929
import VectorSource from 'ol/source/Vector';
30+
import TileJSON from 'ol/source/TileJSON';
31+
32+
import GeoJSON from 'ol/format/GeoJSON';
3033
3134
import TileLayer from 'ol/layer/Tile';
3235
import VectorLayer from 'ol/layer/Vector';
36+
import LayerGroup from 'ol/layer/Group';
3337
34-
import { makeTitilerXYZUrl, makeLayerGroupFromLayerSet } from '../lib/utils';
3538
import { MapViewer } from '../lib/viewers';
3639
import Modal, { getModal } from './modals/BaseModal.svelte';
3740
import Link from './common/Link.svelte';
3841
import MapboxLogoLink from './common/MapboxLogoLink.svelte';
3942
43+
import Crop from 'ol-ext/filter/Crop';
44+
4045
export let CONTEXT;
4146
export let PLACE;
4247
export let MAPS;
@@ -90,29 +95,33 @@
9095
9196
let mainGroup;
9297
let mosaicType;
93-
if (vol.main_layerset.layers.length > 0 && vol.main_layerset.extent) {
98+
99+
if (vol.main_layerset.layers_tilejson.length > 0) {
94100
const mainExtent = transformExtent(vol.main_layerset.extent, 'EPSG:4326', 'EPSG:3857');
95101
extend(homeExtent, mainExtent);
96-
if (vol.main_layerset.mosaic_cog_url) {
97-
mainGroup = new TileLayer({
98-
source: new XYZ({
99-
transition: 0,
100-
url: makeTitilerXYZUrl({
101-
host: CONTEXT.titiler_host,
102-
url: vol.main_layerset.mosaic_cog_url,
103-
}),
102+
103+
mainGroup = new LayerGroup();
104+
105+
vol.main_layerset.layers_tilejson.forEach((tilejson) => {
106+
const lyr = new TileLayer({
107+
source: new TileJSON({
108+
tileJSON: tilejson,
109+
tileSize: 512,
104110
}),
105-
extent: transformExtent(vol.main_layerset.multimask_extent, 'EPSG:4326', 'EPSG:3857'),
111+
extent: transformExtent(tilejson.bounds, 'EPSG:4326', 'EPSG:3857'),
106112
});
107-
mosaicType = 'gt';
108-
} else {
109-
mainGroup = makeLayerGroupFromLayerSet({
110-
layerSet: vol.main_layerset,
111-
zIndex: 400 + n,
112-
titilerHost: CONTEXT.titiler_host,
113-
applyMultiMask: true,
114-
});
115-
}
113+
if (tilejson.mask) {
114+
const feature = new GeoJSON().readFeature(tilejson.mask);
115+
feature.getGeometry().transform('EPSG:4326', 'EPSG:3857');
116+
const crop = new Crop({
117+
feature: feature,
118+
wrapX: true,
119+
inner: false,
120+
});
121+
lyr.addFilter(crop);
122+
}
123+
mainGroup.getLayers().push(lyr);
124+
});
116125
}
117126
118127
let opacity = 0;
@@ -128,12 +137,15 @@
128137
129138
const volumeObj = {
130139
id: vol.identifier,
131-
summaryUrl: vol.urls.summary,
140+
summaryUrl: `/map/${vol.identifier}`,
132141
displayName: vol.volume_number ? `${vol.year} vol. ${vol.volume_number}` : vol.year,
133-
progress: vol.progress,
142+
unprepared_ct: vol.unprepared_ct,
143+
prepared_ct: vol.prepared_ct,
144+
layer_ct: vol.layer_ct,
145+
completion_pct: vol.completion_pct,
134146
mainLayer: mainGroup,
135147
mainLayerO: opacity,
136-
mosaicType: mosaicType,
148+
mosaicType: vol.main_layerset.is_mosaic ? "gt" : null,
137149
};
138150
volumeIds.push(vol.identifier);
139151
volumeLookup[vol.identifier] = volumeObj;
@@ -346,7 +358,7 @@
346358
}
347359
348360
function getCompletedStr(id) {
349-
return `${volumeLookup[id].progress.georef_ct}/${volumeLookup[id].progress.unprep_ct + volumeLookup[id].progress.prep_ct + volumeLookup[id].progress.georef_ct}`;
361+
return `${volumeLookup[id].layer_ct}/${volumeLookup[id].unprepared_ct + volumeLookup[id].prepared_ct + volumeLookup[id].layer_ct}`;
350362
}
351363
</script>
352364

@@ -372,7 +384,7 @@
372384
In early 2022, participants in a <Link href="https://digitalcommons.lsu.edu/gradschool_theses/5641/" external={true}
373385
>crowdsourcing project</Link
374386
> georeferenced all of the Louisiana maps you see here, eventually creating these seamless mosaic overlays. These comprise
375-
1,500 individual sheets from 270 different Sanborn atlases, covering of over <Link href="/browse"
387+
1,500 individual sheets from 270 different Sanborn atlases, covering of over <Link href="/search"
376388
>130 different locations</Link
377389
>.
378390
</p>
@@ -468,7 +480,7 @@
468480
<div {id} class="volume-detail">
469481
<div>
470482
<span title="{getCompletedStr(id)} georeferenced">
471-
{volumeLookup[id].progress.percent}&percnt; ({getCompletedStr(id)})
483+
{volumeLookup[id].completion_pct}&percnt; ({getCompletedStr(id)})
472484
</span>
473485
{#if volumeLookup[id].mosaicType}
474486
<span
@@ -490,12 +502,12 @@
490502
{/each}
491503
{:else}
492504
<div class="volume-item">
493-
<p>No volumes for this place. <Link href="/browse" title="Back to browse">Back to browse &rarr;</Link></p>
505+
<p>No volumes for this place. <Link href="/search" title="Back to browse">Back to browse &rarr;</Link></p>
494506
</div>
495507
{/if}
496508
</div>
497509
<div class="control-panel-footer">
498-
<Link title="Find another city" href="/browse" classes={['white']}>&larr; switch city</Link>
510+
<Link title="Find another city" href="/search" classes={['white']}>&larr; switch city</Link>
499511
<span>|</span>
500512
<Link title="Go to home page" href="/" classes={['white']}>home</Link>
501513
<span>|</span>
@@ -577,7 +589,7 @@
577589
top: 0.5em;
578590
right: 0.5em;
579591
max-width: 100%;
580-
min-width: 250px;
592+
min-width: 300px;
581593
background: var(--primary-background-color);
582594
border-radius: 4px;
583595
border: 1px solid #333333;
@@ -739,6 +751,7 @@
739751
bottom: 3em;
740752
margin-right: auto;
741753
margin-left: auto;
754+
width: 100%;
742755
}
743756
}
744757
</style>

ohmg/places/views.py

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
from natsort import natsorted
55

66
from ohmg.api.schemas import (
7-
LayerSetSchema,
8-
MapFullSchema,
7+
LayerSetDisplaySchema,
8+
MapListSchema2,
99
PlaceFullSchema,
1010
)
1111
from ohmg.conf.http import generate_ohmg_context
@@ -37,15 +37,13 @@ def get(self, request, place):
3737
class Viewer(View):
3838
@xframe_options_sameorigin
3939
def get(self, request, place):
40-
place_data = {}
41-
maps = []
42-
4340
place_data = place.serialize()
41+
maps = []
4442
for map in Map.objects.filter(locales__id__exact=place.id, hidden=False).prefetch_related():
45-
map_json = MapFullSchema.from_orm(map).dict()
43+
map_json = MapListSchema2.from_orm(map).dict()
4644
ls = map.get_layerset("main-content")
4745
if ls:
48-
map_json["main_layerset"] = LayerSetSchema.from_orm(ls).dict()
46+
map_json["main_layerset"] = LayerSetDisplaySchema.from_orm(ls).dict()
4947
maps.append(map_json)
5048

5149
maps_sorted = natsorted(maps, key=lambda x: x["title"], reverse=True)

scripts/deploy_frontend.sh

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,13 @@ pnpm run build
1616
cd $CURRENT_DIR
1717

1818
echo "getting static plugin assets"
19-
$VIRTUAL_ENV/bin/python $PROJECT_ROOT/manage.py get-plugins
19+
uv run $PROJECT_ROOT/manage.py get-plugins
2020

2121
echo "running collectstatic"
22-
$VIRTUAL_ENV/bin/python $PROJECT_ROOT/manage.py collectstatic --noinput
22+
uv run $PROJECT_ROOT/manage.py collectstatic --noinput
2323

2424
echo "update build number"
25-
$VIRTUAL_ENV/bin/python $PROJECT_ROOT/manage.py update_build
25+
uv run $PROJECT_ROOT/manage.py update_build
26+
27+
echo "touch wsgi.py to reset uwsgi"
28+
touch ohmg/conf/wsgi.py

0 commit comments

Comments
 (0)