Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(shared): update wmts titles to use imagery title and category #2285

Merged
merged 10 commits into from
Jul 1, 2022
Merged
7 changes: 4 additions & 3 deletions packages/lambda-tiler/src/__tests__/wmts.capability.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,10 +131,10 @@ o.spec('WmtsCapabilities', () => {
apiKey,
}).toXml();

o(xml).deepEquals('<?xml version="1.0"?>\n' + raw?.toString());
o(xml.split('\n')).deepEquals(['<?xml version="1.0" encoding="utf-8"?>', ...raw?.toString().split('\n')]);

o(createHash('sha256').update(Buffer.from(xml)).digest('base64')).equals(
'beknYyMt8v74vK4p84AS3c1OnBSJ+ZE0kan+mMVQS1A=',
o(createHash('sha256').update(Buffer.from(xml)).digest('base64url')).equals(
'eUuSQ9tje2v4yIFbHZ8Y-TWCBznCF8X14BFgxQH4VNU',
);
});

Expand Down Expand Up @@ -171,6 +171,7 @@ o.spec('WmtsCapabilities', () => {
'ows:Title',
'ows:Abstract',
'ows:Identifier',
'ows:Keywords',
'ows:BoundingBox',
'ows:BoundingBox',
'ows:WGS84BoundingBox',
Expand Down
11 changes: 5 additions & 6 deletions packages/lambda-tiler/src/__tests__/xyz.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { ConfigProvider, StyleJson } from '@basemaps/config';
import { GoogleTms, Nztm2000QuadTms, TileMatrixSets } from '@basemaps/geo';
import { Config, Env, LogConfig, VNodeParser } from '@basemaps/shared';
import { Config, Env, LogConfig } from '@basemaps/shared';
import { round } from '@basemaps/test/build/rounding.js';
import o from 'ospec';
import sinon from 'sinon';
Expand Down Expand Up @@ -146,7 +146,7 @@ o.spec('LambdaXyz', () => {
o('should 304 if a xml is not modified', async () => {
delete process.env[Env.PublicUrlBase];
o.timeout(1000);
const key = 'NuirTK8fozzCJV1iG1FznmdHhKvk6WaWuDhhEA1d40c=';
const key = 'jYlhOJ0d9y7cO58ELT2GniwMiPjycpngtdUI910iEh8=';
const request = mockRequest('/v1/tiles/WMTSCapabilities.xml', 'get', {
'if-none-match': key,
...apiKeyHeader,
Expand Down Expand Up @@ -175,12 +175,11 @@ o.spec('LambdaXyz', () => {

const body = Buffer.from(res.body ?? '', 'base64').toString();
o(body.slice(0, 100)).equals(
'<?xml version="1.0"?>\n' + '<Capabilities xmlns="http://www.opengis.net/wmts/1.0" xmlns:ows="http://www.op',
'<?xml version="1.0" encoding="utf-8"?>\n' + '<Capabilities xmlns="http://www.opengis.net/wmts/1.0" xmlns:o',
);

const vdom = await VNodeParser.parse(body);
const url = vdom.tags('ResourceURL').next().value;
o(url?.toString()).equals(
const url = body.split('\n').find((f) => f.trim().startsWith('<ResourceURL'));
o(url?.trim()).equals(
'<ResourceURL format="image/jpeg" resourceType="tile" ' +
`template="https://tiles.test/v1/tiles/aerial@beta/{TileMatrixSet}/{TileMatrix}/{TileCol}/{TileRow}.jpeg?api=${apiKey}" />`,
);
Expand Down
6 changes: 5 additions & 1 deletion packages/lambda-tiler/src/tile.set.raster.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ export class TileSetRaster {
components: TileSetNameComponents;
tileSet: ConfigTileSetRaster;

keywords: string[] = [];

constructor(name: string, tileMatrix: TileMatrixSet) {
this.components = TileSetNameParser.parse(name);
this.tileMatrix = tileMatrix;
Expand Down Expand Up @@ -213,9 +215,11 @@ export class TileSetRaster {
child.tileSet = { ...this.tileSet };
child.tileSet.background = undefined;
const title = this.tileSet?.title ?? this.tileSet?.name;
child.tileSet.title = `${title} ${titleizeImageryName(image.name)}`;
child.tileSet.title = image.title ?? `${title} ${titleizeImageryName(image.name)}`;
child.extentOverride = Bounds.fromJson(image.bounds);

if (image.category) child.keywords.push(image.category);

const layer: ConfigLayer = { name: image.name, minZoom: 0, maxZoom: 100 };
layer[this.tileMatrix.projection.code] = image.id;

Expand Down
10 changes: 9 additions & 1 deletion packages/lambda-tiler/src/wmts.capability.ts
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ export class WmtsCapabilities {
V('ows:Title', firstLayer.title),
V('ows:Abstract', firstLayer.description),
V('ows:Identifier', firstLayer.fullName),
this.buildKeywords(firstLayer),
...layers.map((layer) => this.buildBoundingBox(layer.tileMatrix, layer.extent)),
this.buildWgs84BoundingBox(layers),
this.buildStyle(),
Expand All @@ -169,6 +170,13 @@ export class WmtsCapabilities {
]);
}

buildKeywords(layer: TileSetRaster): VNodeElement {
return V(
'ows:Keywords',
layer.keywords.map((keyword) => V('ows:Keyword', keyword)),
);
}

buildStyle(): VNodeElement {
return V('Style', { isDefault: 'true' }, [V('ows:Title', 'Default Style'), V('ows:Identifier', 'default')]);
}
Expand Down Expand Up @@ -204,6 +212,6 @@ export class WmtsCapabilities {
}

toXml(): string {
return '<?xml version="1.0"?>\n' + this.toVNode().toString();
return '<?xml version="1.0" encoding="utf-8"?>\n' + this.toVNode().toString();
}
}
4 changes: 1 addition & 3 deletions packages/landing/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@
"@basemaps/shared": "^6.29.0",
"@linzjs/lui": "^10.11.3",
"@servie/events": "^3.0.0",
"@splitsoftware/splitio": "^10.16.1",
"@types/geojson": "^7946.0.7",
"@types/proj4": "^2.5.0",
"maplibre-gl": "^1.14.1-rc.2",
Expand Down Expand Up @@ -83,8 +82,7 @@
"entry": "src/index.tsx",
"env": {
"GOOGLE_ANALYTICS": null,
"TILE_HOST": null,
"SPLIT_IO_KEY": null
"TILE_HOST": null
},
"platform": "browser"
},
Expand Down
47 changes: 15 additions & 32 deletions packages/landing/src/components/layer.switcher.dropdown.tsx
Original file line number Diff line number Diff line change
@@ -1,32 +1,19 @@
import { Component, ComponentChild, Fragment } from 'preact';
import { Config, GaEvent, gaEvent } from '../config.js';
import { LayerInfo, MapConfig } from '../config.map.js';
import { SplitIo } from '../split.js';

export interface LayerSwitcherDropdownState {
layers?: Map<string, LayerInfo>;
/** Is the layer switcher turned on */
isEnabled?: boolean;
/** Can users select individual aerial imagery layers */
isIndividualEnabled?: boolean;
/** Can users select the basic style */
isBasicStyleEnabled?: boolean;

currentLayer: string;
}
export class LayerSwitcherDropdown extends Component<unknown, LayerSwitcherDropdownState> {
_events: (() => boolean)[] = [];
componentWillMount(): void {
SplitIo.getClient().then((f) => {
const isEnabled = f?.getTreatment('layer-switcher-dropdown') === 'on';
const isIndividualEnabled = f?.getTreatment('layer-switcher-individual-layers') === 'on';
const isBasicStyleEnabled = f?.getTreatment('layer-switcher-basic') === 'on';
this.setState({ ...this.state, isEnabled, isIndividualEnabled, isBasicStyleEnabled });
/** Load all the map config layers */
if (isEnabled) Config.map.layers.then((layers) => this.setState({ ...this.state, layers }));
});

this.setState({ ...this.state, currentLayer: Config.map.layerKey });

Config.map.layers.then((layers) => this.setState({ ...this.state, layers }));

this._events.push(
Config.map.on('layer', () => this.setState({ ...this.state, currentLayer: Config.map.layerKey })),
Config.map.on('tileMatrix', () => this.setState(this.state)),
Expand Down Expand Up @@ -55,15 +42,13 @@ export class LayerSwitcherDropdown extends Component<unknown, LayerSwitcherDropd
};

render(): ComponentChild {
if (this.state.isEnabled !== true) return;
return (
<div class="LuiDeprecatedForms">
<h6>Layers</h6>
<select onChange={this.onChange} value={this.state.currentLayer}>
<optgroup label="Basemaps">
<option value="aerial"> Aerial Imagery</option>
<option value="topographic::topographic">Topographic</option>
{this.state.isBasicStyleEnabled ? <option value="topographic::basic">Basic</option> : undefined}
</optgroup>
{this.renderAerialLayers()}
</select>
Expand All @@ -72,26 +57,24 @@ export class LayerSwitcherDropdown extends Component<unknown, LayerSwitcherDropd
}

renderAerialLayers(): ComponentChild {
if (this.state.isIndividualEnabled !== true) return;
if (this.state.layers == null || this.state.layers.size === 0) return;

const rural: ComponentChild[] = [];
const urban: ComponentChild[] = [];
const categories: Map<string, ComponentChild[]> = new Map();

for (const layer of this.state.layers.values()) {
if (!layer.projections.has(Config.map.tileMatrix.projection.code)) continue;
const layerCategory = categories.get(layer.category ?? 'Unknown') ?? [];
layerCategory.push(<option value={layer.id}>{layer.name.replace(` ${layer.category}`, '')}</option>);
categories.set(layer.category ?? 'Unknown', layerCategory);
}

if (categories.size === 0) return;

const node = <option value={layer.id}>{layer.name}</option>;
if (layer.name.toLowerCase().includes(' rural ')) rural.push(node);
else urban.push(node);
const output: ComponentChild[] = [];
for (const [layerName, layers] of categories.entries()) {
if (layers.length === 0) continue;
output.push(<optgroup label={layerName}>{...layers}</optgroup>);
}

if (rural.length === 0 || urban.length === 0) return;
return (
<Fragment>
<optgroup label="Aerial Imagery - Urban">{...urban}</optgroup>;
<optgroup label="Aerial Imagery - Rural">{...rural}</optgroup>;
</Fragment>
);
return <Fragment>{output}</Fragment>;
}
}
6 changes: 1 addition & 5 deletions packages/landing/src/components/layout.header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { Component, ComponentChild } from 'preact';
import { Fragment } from 'preact/jsx-runtime';
import { Config, GaEvent, gaEvent } from '../config.js';
import { LayerInfo } from '../config.map.js';
import { SplitIo } from '../split.js';
import { MapOptionType } from '../url.js';
import { Copyable } from './copyable.js';
import { LayerSwitcherDropdown } from './layer.switcher.dropdown.js';
Expand All @@ -18,10 +17,7 @@ export class Header extends Component<unknown, { isMenuOpen: boolean; layers?: M
this._events.push(Config.map.on('change', () => this.setState(this.state)));

// If individual layers are on, we need the layer info to determine if they can use NZTM2000Quad WMTS
SplitIo.getClient().then((f) => {
const isIndividualEnabled = f?.getTreatment('layer-switcher-individual-layers') === 'on';
if (isIndividualEnabled) Config.map.layers.then((layers) => this.setState({ ...this.state, layers }));
});
Config.map.layers.then((layers) => this.setState({ ...this.state, layers }));
}
componentWillUnmount(): void {
for (const e of this._events) e();
Expand Down
6 changes: 0 additions & 6 deletions packages/landing/src/components/map.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import maplibre from 'maplibre-gl';
import { Component, ComponentChild } from 'preact';
import { MapAttribution } from '../attribution.js';
import { Config } from '../config.js';
import { SplitIo } from '../split.js';
import { getTileGrid, locationTransform } from '../tile.matrix.js';
import { WindowUrl } from '../url.js';
import { Debug } from './debug.js';
Expand Down Expand Up @@ -122,11 +121,6 @@ export class Basemaps extends Component<unknown, { isLayerSwitcherEnabled: boole

this.updateStyle();
});

SplitIo.getClient().then((f) => {
const isEnabled = f?.getTreatment('layer-switcher-button') === 'on';
this.setState({ isLayerSwitcherEnabled: isEnabled });
});
}

_events: (() => boolean)[] = [];
Expand Down
13 changes: 12 additions & 1 deletion packages/landing/src/config.map.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,8 @@ export interface LayerInfo {
id: string;
/** Layer name */
name: string;
/** Layer category */
category?: string;
/* Bounding box */
upperLeft: [number, number];
lowerRight: [number, number];
Expand Down Expand Up @@ -189,6 +191,8 @@ async function loadAllLayers(): Promise<Map<string, LayerInfo>> {
if (title == null || id == null) continue;
if (title === 'aerial') continue;

const category = layer.getElementsByTagName('ows:Keyword').item(0)?.textContent;

const boundEl = layer.getElementsByTagName('ows:WGS84BoundingBox').item(0);
const upperLeft = boundEl?.getElementsByTagName('ows:UpperCorner').item(0)?.textContent?.split(' ').map(Number);
const lowerRight = boundEl?.getElementsByTagName('ows:LowerCorner').item(0)?.textContent?.split(' ').map(Number);
Expand All @@ -202,7 +206,14 @@ async function loadAllLayers(): Promise<Map<string, LayerInfo>> {
}

if (upperLeft == null || lowerRight == null || upperLeft.length !== 2) continue;
allLayers.push({ id, name: title.replace('aerial ', ''), upperLeft, lowerRight, projections } as LayerInfo);
allLayers.push({
id,
name: title.replace('aerial ', ''),
upperLeft,
lowerRight,
projections,
category,
} as LayerInfo);
}

allLayers.sort((a, b) => a.name.localeCompare(b.name));
Expand Down
3 changes: 0 additions & 3 deletions packages/landing/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,6 @@ export const Config = {
get Version(): string {
return process.env.GIT_VERSION ?? '';
},
get SplitApiKey(): string {
return process.env.SPLIT_IO_KEY ?? '';
},
map: new MapConfig(),
};

Expand Down
4 changes: 1 addition & 3 deletions packages/landing/src/global.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import { SplitIo } from './split.js';
export {};

declare global {
interface Window {
// Google analytics
dataLayer: any[];
gtag(...args: any[]): void;

splitIo: typeof SplitIo;
}
}
49 changes: 0 additions & 49 deletions packages/landing/src/split.ts

This file was deleted.

1 change: 1 addition & 0 deletions packages/shared/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
"@linzjs/geojson": "^6.28.1",
"@linzjs/metrics": "^6.28.1",
"aws-sdk": "^2.890.0",
"entities": "^4.3.0",
"pino": "^7.5.0",
"proj4": "^2.6.2",
"sax": "^1.2.4",
Expand Down
Loading