diff --git a/ohmg/api/schemas.py b/ohmg/api/schemas.py index 84d7083e..39f5a59a 100644 --- a/ohmg/api/schemas.py +++ b/ohmg/api/schemas.py @@ -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 @@ -23,6 +23,9 @@ SessionLock, ) +if TYPE_CHECKING: + from ohmg.core.models import LayerSet + logger = logging.getLogger(__name__) @@ -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""" diff --git a/ohmg/frontend/svelte_components/src/components/Viewer.svelte b/ohmg/frontend/svelte_components/src/components/Viewer.svelte index 17daaa11..8eb3274b 100644 --- a/ohmg/frontend/svelte_components/src/components/Viewer.svelte +++ b/ohmg/frontend/svelte_components/src/components/Viewer.svelte @@ -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; @@ -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; @@ -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; @@ -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}`; } @@ -372,7 +384,7 @@ In early 2022, participants in a crowdsourcing project 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 130 different locations.
@@ -468,7 +480,7 @@No volumes for this place. Back to browse →
+No volumes for this place. Back to browse →