Skip to content

Commit

Permalink
feat(landing): use attribution polygon for layer intersections if we …
Browse files Browse the repository at this point in the history
…have them
  • Loading branch information
blacha committed Sep 20, 2024
1 parent 4bc33ff commit 23a5ef0
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 28 deletions.
28 changes: 16 additions & 12 deletions packages/landing/src/attribution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,24 @@ export class MapAttributionState {
/** Rendering process needs synch access */
_attrsSync: Map<string, Attribution> = new Map();

getAttribution(layerKey: string, loadUrl: string): Promise<Attribution | null> {
const attrs = this._attrs.get(layerKey);
if (attrs) return attrs;
const attrLoad = Attribution.load(loadUrl)
.then((a) => {
if (a == null) return null;
a.isIgnored = this.isIgnored;
this._attrsSync.set(layerKey, a);
return a;
})
.catch(() => null);
this._attrs.set(layerKey, attrLoad);
return attrLoad;
}

/** Load a attribution from a url, return a cached copy if we have one */
getCurrentAttribution(): Promise<Attribution | null> {
const cacheKey = Config.map.layerKeyTms;
let attrs = this._attrs.get(cacheKey);
if (attrs == null) {
attrs = Attribution.load(Config.map.toTileUrl(MapOptionType.Attribution)).catch(() => null);
this._attrs.set(cacheKey, attrs);
void attrs.then((a) => {
if (a == null) return;
a.isIgnored = this.isIgnored;
this._attrsSync.set(Config.map.layerKeyTms, a);
});
}
return attrs;
return this.getAttribution(Config.map.layerKeyTms, Config.map.toTileUrl(MapOptionType.Attribution));
}

/** Filter the attribution to the map bounding box */
Expand Down
31 changes: 26 additions & 5 deletions packages/landing/src/components/layer.switcher.dropdown.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import { Bounds, GoogleTms, Projection } from '@basemaps/geo';
import { Wgs84 } from '@linzjs/geojson';
import { ChangeEventHandler, Component, ReactNode } from 'react';
import Select from 'react-select';

import { MapAttrState } from '../attribution.js';
import { Config, GaEvent, gaEvent } from '../config.js';
import { LayerInfo, MapConfig } from '../config.map.js';
import { MapOptionType } from '../url.js';

type CategoryMap = Map<string, { label: string; options: { label: string; value: string }[] }>;

Expand Down Expand Up @@ -48,7 +51,12 @@ export class LayerSwitcherDropdown extends Component<unknown, LayerSwitcherDropd
}

override componentDidMount(): void {
this.setState({ zoomToExtent: true, currentLayer: Config.map.layerKey });
this.setState({ zoomToExtent: false, currentLayer: Config.map.layerKey, filterToExtent: true });
// Trigger a map load
void MapAttrState.getAttribution(
'all',
Config.map.toTileUrl(MapOptionType.Attribution, GoogleTms, 'all', undefined),
).then(() => this.forceUpdate());

void Config.map.layers.then((layers) => {
this.setState({ layers });
Expand Down Expand Up @@ -194,22 +202,35 @@ export class LayerSwitcherDropdown extends Component<unknown, LayerSwitcherDropd

let current: Option | null = null;

const allLayers = MapAttrState._attrsSync.get('all');

for (const layer of this.state.layers.values()) {
if (ignoredLayers.has(layer.id)) continue;
if (!layer.projections.has(Config.map.tileMatrix.projection.code)) continue;
total++;
// Always show the current layer
if (layer.id !== currentLayer) {
// Limit all other layers to the extent if requested
if (filterToExtent && !doesLayerIntersect(bounds, layer)) {
hidden++;
continue;
if (filterToExtent) {
if (!doesLayerIntersect(bounds, layer)) {
hidden++;
continue;
}
if (allLayers) {
const currentLayer = allLayers.attributions.filter((f) => f.collection.title === layer.title);
const latLng = Projection.get(GoogleTms).boundsToWgs84BoundingBox(bounds);
// console.log(latLng, Wgs84.bboxToMultiPolygon(latLng));
if (currentLayer.length === 1 && !currentLayer[0].intersection(Wgs84.bboxToMultiPolygon(latLng))) {
hidden++;
continue;
}
}
}
}

const layerId = layer.category ?? 'Unknown';
const layerCategory = categories.get(layerId) ?? { label: layerId, options: [] };
const opt = { value: layer.id, label: layer.name.replace(` ${layer.category}`, '') };
const opt = { value: layer.id, label: layer.title.replace(` ${layer.category}`, '') };
layerCategory.options.push(opt);
categories.set(layerId, layerCategory);
if (layer.id === currentLayer) current = opt;
Expand Down
2 changes: 1 addition & 1 deletion packages/landing/src/components/layout.header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export class Header extends Component<unknown, HeaderState> {
}

override componentDidMount(): void {
this.setState({ isMenuOpen: false });
this.setState({ isMenuOpen: true });
this._events.push(Config.map.on('change', () => this.forceUpdate()));
this._events.push(Config.map.on('filter', () => this.renderLinksTiles()));

Expand Down
26 changes: 16 additions & 10 deletions packages/landing/src/config.map.ts
Original file line number Diff line number Diff line change
Expand Up @@ -275,10 +275,16 @@ export class MapConfig extends Emitter<MapConfigEvents> {
}

export interface LayerInfo {
/** Layer id to use when fetching tiles */
/**
* URL friendly Layer id to use when fetching tiles
* @example "scanned-aerial-imagery-post-1989-12-31"
*/
id: string;
/** Layer name */
name: string;
/**
* Human friendly name of the layer,
* @example "Scanned Aerial Imagery post 31 December 1989"
*/
title: string;
/** Layer category */
category?: string;
/* Bounding box */
Expand Down Expand Up @@ -331,15 +337,15 @@ async function loadAllLayers(): Promise<Map<string, LayerInfo>> {
if (upperLeft == null || lowerRight == null || upperLeft.length !== 2) continue;
allLayers.push({
id,
name: title.replace('aerial ', ''),
title: title.replace('aerial ', ''),
upperLeft,
lowerRight,
projections,
category,
} as LayerInfo);
}

allLayers.sort((a, b) => a.name.localeCompare(b.name));
allLayers.sort((a, b) => a.title.localeCompare(b.title));
addDefaultLayers(output);
for (const l of allLayers) output.set(l.id, l);
return output;
Expand All @@ -355,21 +361,21 @@ function addDefaultLayers(output: Map<string, LayerInfo>): void {
const layers: LayerInfo[] = [
{
id: 'aerial',
name: 'Aerial Imagery',
title: 'Aerial Imagery',
projections: new Set([EpsgCode.Nztm2000, EpsgCode.Google]),
category: 'Basemaps',
},

{
id: 'topographic::topographic',
name: 'Topographic',
title: 'Topographic',
projections: new Set([EpsgCode.Google]),
category: 'Basemaps',
},

{
id: 'elevation',
name: 'Elevation',
title: 'Elevation',
projections: new Set([EpsgCode.Google]),
category: 'Basemaps',
pipeline: 'terrain-rgb',
Expand All @@ -378,14 +384,14 @@ function addDefaultLayers(output: Map<string, LayerInfo>): void {

{
id: 'scanned-aerial-imagery-pre-1990-01-01',
name: 'Scanned Aerial Imagery pre 1 January 1990',
title: 'Scanned Aerial Imagery pre 1 January 1990',
projections: new Set([EpsgCode.Nztm2000, EpsgCode.Google]),
category: 'Scanned Aerial Imagery Basemaps',
},

{
id: 'scanned-aerial-imagery-post-1989-12-31',
name: 'Scanned Aerial Imagery post 31 December 1989',
title: 'Scanned Aerial Imagery post 31 December 1989',
projections: new Set([EpsgCode.Nztm2000, EpsgCode.Google]),
category: 'Scanned Aerial Imagery Basemaps',
},
Expand Down

0 comments on commit 23a5ef0

Please sign in to comment.