Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 32 additions & 1 deletion ohmg/api/schemas.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import json
import logging
from datetime import datetime
from typing import Any, List, Literal, Optional
from typing import TYPE_CHECKING, Any, List, Literal, Optional

import humanize
from avatar.templatetags.avatar_tags import avatar_url
Expand All @@ -23,6 +23,9 @@
SessionLock,
)

if TYPE_CHECKING:
from ohmg.core.models import LayerSet

logger = logging.getLogger(__name__)


Expand Down Expand Up @@ -504,6 +507,34 @@ def resolve_name(obj):
return str(obj.category)


class LayerSetDisplaySchema(Schema):
map_id: str
category: str
extent: Optional[tuple]
layers_tilejson: list[dict]
is_mosaic: bool

@staticmethod
def resolve_category(obj):
return str(obj.category)

@staticmethod
def resolve_layers_tilejson(obj: "LayerSet"):
layers_tilejson = []
if obj.mosaic_geotiff:
layers_tilejson.append(obj.tilejson)
else:
for layer in natsorted(obj.get_layers(), key=lambda k: k.title):
tilejson = layer.tilejson
tilejson["mask"] = json.loads(layer.mask.geojson) if layer.mask else None
layers_tilejson.append(tilejson)
return layers_tilejson

@staticmethod
def resolve_is_mosaic(obj):
return True if obj.mosaic_geotiff else False


class PlaceSchema(Schema):
"""very lightweight serialization of a Place with its Maps"""

Expand Down
71 changes: 42 additions & 29 deletions ohmg/frontend/svelte_components/src/components/Viewer.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,21 @@

import XYZ from 'ol/source/XYZ';
import VectorSource from 'ol/source/Vector';
import TileJSON from 'ol/source/TileJSON';

import GeoJSON from 'ol/format/GeoJSON';

import TileLayer from 'ol/layer/Tile';
import VectorLayer from 'ol/layer/Vector';
import LayerGroup from 'ol/layer/Group';

import { makeTitilerXYZUrl, makeLayerGroupFromLayerSet } from '../lib/utils';
import { MapViewer } from '../lib/viewers';
import Modal, { getModal } from './modals/BaseModal.svelte';
import Link from './common/Link.svelte';
import MapboxLogoLink from './common/MapboxLogoLink.svelte';

import Crop from 'ol-ext/filter/Crop';

export let CONTEXT;
export let PLACE;
export let MAPS;
Expand Down Expand Up @@ -90,29 +95,33 @@

let mainGroup;
let mosaicType;
if (vol.main_layerset.layers.length > 0 && vol.main_layerset.extent) {

if (vol.main_layerset.layers_tilejson.length > 0) {
const mainExtent = transformExtent(vol.main_layerset.extent, 'EPSG:4326', 'EPSG:3857');
extend(homeExtent, mainExtent);
if (vol.main_layerset.mosaic_cog_url) {
mainGroup = new TileLayer({
source: new XYZ({
transition: 0,
url: makeTitilerXYZUrl({
host: CONTEXT.titiler_host,
url: vol.main_layerset.mosaic_cog_url,
}),

mainGroup = new LayerGroup();

vol.main_layerset.layers_tilejson.forEach((tilejson) => {
const lyr = new TileLayer({
source: new TileJSON({
tileJSON: tilejson,
tileSize: 512,
}),
extent: transformExtent(vol.main_layerset.multimask_extent, 'EPSG:4326', 'EPSG:3857'),
extent: transformExtent(tilejson.bounds, 'EPSG:4326', 'EPSG:3857'),
});
mosaicType = 'gt';
} else {
mainGroup = makeLayerGroupFromLayerSet({
layerSet: vol.main_layerset,
zIndex: 400 + n,
titilerHost: CONTEXT.titiler_host,
applyMultiMask: true,
});
}
if (tilejson.mask) {
const feature = new GeoJSON().readFeature(tilejson.mask);
feature.getGeometry().transform('EPSG:4326', 'EPSG:3857');
const crop = new Crop({
feature: feature,
wrapX: true,
inner: false,
});
lyr.addFilter(crop);
}
mainGroup.getLayers().push(lyr);
});
}

let opacity = 0;
Expand All @@ -128,12 +137,15 @@

const volumeObj = {
id: vol.identifier,
summaryUrl: vol.urls.summary,
summaryUrl: `/map/${vol.identifier}`,
displayName: vol.volume_number ? `${vol.year} vol. ${vol.volume_number}` : vol.year,
progress: vol.progress,
unprepared_ct: vol.unprepared_ct,
prepared_ct: vol.prepared_ct,
layer_ct: vol.layer_ct,
completion_pct: vol.completion_pct,
mainLayer: mainGroup,
mainLayerO: opacity,
mosaicType: mosaicType,
mosaicType: vol.main_layerset.is_mosaic ? "gt" : null,
};
volumeIds.push(vol.identifier);
volumeLookup[vol.identifier] = volumeObj;
Expand Down Expand Up @@ -346,7 +358,7 @@
}

function getCompletedStr(id) {
return `${volumeLookup[id].progress.georef_ct}/${volumeLookup[id].progress.unprep_ct + volumeLookup[id].progress.prep_ct + volumeLookup[id].progress.georef_ct}`;
return `${volumeLookup[id].layer_ct}/${volumeLookup[id].unprepared_ct + volumeLookup[id].prepared_ct + volumeLookup[id].layer_ct}`;
}
</script>

Expand All @@ -372,7 +384,7 @@
In early 2022, participants in a <Link href="https://digitalcommons.lsu.edu/gradschool_theses/5641/" external={true}
>crowdsourcing project</Link
> georeferenced all of the Louisiana maps you see here, eventually creating these seamless mosaic overlays. These comprise
1,500 individual sheets from 270 different Sanborn atlases, covering of over <Link href="/browse"
1,500 individual sheets from 270 different Sanborn atlases, covering of over <Link href="/search"
>130 different locations</Link
>.
</p>
Expand Down Expand Up @@ -468,7 +480,7 @@
<div {id} class="volume-detail">
<div>
<span title="{getCompletedStr(id)} georeferenced">
{volumeLookup[id].progress.percent}&percnt; ({getCompletedStr(id)})
{volumeLookup[id].completion_pct}&percnt; ({getCompletedStr(id)})
</span>
{#if volumeLookup[id].mosaicType}
<span
Expand All @@ -490,12 +502,12 @@
{/each}
{:else}
<div class="volume-item">
<p>No volumes for this place. <Link href="/browse" title="Back to browse">Back to browse &rarr;</Link></p>
<p>No volumes for this place. <Link href="/search" title="Back to browse">Back to browse &rarr;</Link></p>
</div>
{/if}
</div>
<div class="control-panel-footer">
<Link title="Find another city" href="/browse" classes={['white']}>&larr; switch city</Link>
<Link title="Find another city" href="/search" classes={['white']}>&larr; switch city</Link>
<span>|</span>
<Link title="Go to home page" href="/" classes={['white']}>home</Link>
<span>|</span>
Expand Down Expand Up @@ -577,7 +589,7 @@
top: 0.5em;
right: 0.5em;
max-width: 100%;
min-width: 250px;
min-width: 300px;
background: var(--primary-background-color);
border-radius: 4px;
border: 1px solid #333333;
Expand Down Expand Up @@ -739,6 +751,7 @@
bottom: 3em;
margin-right: auto;
margin-left: auto;
width: 100%;
}
}
</style>
12 changes: 5 additions & 7 deletions ohmg/places/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
from natsort import natsorted

from ohmg.api.schemas import (
LayerSetSchema,
MapFullSchema,
LayerSetDisplaySchema,
MapListSchema2,
PlaceFullSchema,
)
from ohmg.conf.http import generate_ohmg_context
Expand Down Expand Up @@ -37,15 +37,13 @@ def get(self, request, place):
class Viewer(View):
@xframe_options_sameorigin
def get(self, request, place):
place_data = {}
maps = []

place_data = place.serialize()
maps = []
for map in Map.objects.filter(locales__id__exact=place.id, hidden=False).prefetch_related():
map_json = MapFullSchema.from_orm(map).dict()
map_json = MapListSchema2.from_orm(map).dict()
ls = map.get_layerset("main-content")
if ls:
map_json["main_layerset"] = LayerSetSchema.from_orm(ls).dict()
map_json["main_layerset"] = LayerSetDisplaySchema.from_orm(ls).dict()
maps.append(map_json)

maps_sorted = natsorted(maps, key=lambda x: x["title"], reverse=True)
Expand Down
9 changes: 6 additions & 3 deletions scripts/deploy_frontend.sh
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,13 @@ pnpm run build
cd $CURRENT_DIR

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

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

echo "update build number"
$VIRTUAL_ENV/bin/python $PROJECT_ROOT/manage.py update_build
uv run $PROJECT_ROOT/manage.py update_build

echo "touch wsgi.py to reset uwsgi"
touch ohmg/conf/wsgi.py