Skip to content

Commit

Permalink
feat: Introduce multiple and conditional legends (#1491)
Browse files Browse the repository at this point in the history
* feat: enable multiple and conditional legends

* dispatch layerconfig changes in the layercontrol

* fix: legends rendering scenarios

* fix: adjust layer-legend rendering logic

* test: added a multi legends test
  • Loading branch information
A-Behairi authored Jan 20, 2025
1 parent 8e4014d commit 919ea60
Show file tree
Hide file tree
Showing 10 changed files with 500 additions and 80 deletions.
25 changes: 19 additions & 6 deletions elements/layercontrol/src/components/layer-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@ import { dataChangeMethod, applyUpdatedStyles } from "../methods/layer-config";
import { when } from "lit/directives/when.js";
import _throttle from "lodash.throttle";
import "./layer-legend";
/**
* @typedef {Partial<import("./layer-legend").LegendConfig> & {
* boundTo?:{key: string;value: string|number|boolean}
* domainProperties: string[]
* }} layerConfigLegend
**/

/**
* `EOxLayerControlLayerConfig` is a component that handles configuration options for layers using eox-jsonform.
* It allows users to input data, modify layer settings, and update the UI based on those settings.
Expand Down Expand Up @@ -74,12 +81,9 @@ export class EOxLayerControlLayerConfig extends LitElement {
* @type {{
* schema: Record<string,any>;
* element: string;
* type?:"tileUrl"|"style";
* style?:import("ol/layer/WebGLTile").Style
* legend?: Partial<import("./layer-legend").LegendConfig> & {
* range:string[];
* domainProperties:string[]
* }
* type?: "tileUrl" | "style";
* style?: import("ol/layer/WebGLTile").Style
* legend?: layerConfigLegend | layerConfigLegend[]
* }}
*/
this.layerConfig = null;
Expand Down Expand Up @@ -131,6 +135,15 @@ export class EOxLayerControlLayerConfig extends LitElement {
this,
);
}
this.dispatchEvent(
new CustomEvent("layerConfig:change", {
bubbles: true,
detail: {
jsonformValue: e.detail,
layer: this.layer,
},
}),
);
this.requestUpdate();
}

Expand Down
98 changes: 67 additions & 31 deletions elements/layercontrol/src/components/layer-legend.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { LitElement, html, css } from "lit";
import { LitElement, html, css, nothing } from "lit";
import { when } from "lit/directives/when.js";
import { ifDefined } from "lit/directives/if-defined.js";

/**
* Legend configurations
*
Expand Down Expand Up @@ -50,13 +49,6 @@ export class EOxLayerControlLayerLegend extends LitElement {
*/
this.noShadow = false;

/**
* Legend configurations
* @type {LegendConfig}
* @see {@link https://clhenrick.github.io/color-legend-element/}
*/
this.layerLegend = null;

/**
* The native OL layer
*
Expand All @@ -65,6 +57,38 @@ export class EOxLayerControlLayerLegend extends LitElement {
*/
this.layer = null;
}
/** @type {(LegendConfig & {id:string})[]}} */
#layerLegend = [];

get layerLegend() {
if (this.#layerLegend) {
return this.#layerLegend.length > 1
? this.#layerLegend
: this.#layerLegend[0];
} else {
return null;
}
}
/**
* Legend configurations
* @param {LegendConfig | LegendConfig[]} value
* @see {@link https://clhenrick.github.io/color-legend-element/}
**/
set layerLegend(value) {
if (Array.isArray(value)) {
this.#layerLegend = value.map((config, idx) => ({
id: (this.layer?.get("id") ?? "") + idx,
...config,
}));
} else {
this.#layerLegend = [
{
id: (this.layer?.get("id") ?? "") + 0,
...value,
},
];
}
}

/**
* Overrides createRenderRoot to handle shadow DOM creation based on the noShadow property.
Expand All @@ -74,19 +98,21 @@ export class EOxLayerControlLayerLegend extends LitElement {
}

firstUpdated() {
// if the width is explicitly set, don't auto-update
if (!this.layerLegend.width) {
if (this.layerLegend) {
new ResizeObserver(() => {
if (this.offsetWidth !== this.layerLegend.width) {
this.layerLegend.width = this.offsetWidth;
this.requestUpdate();
}
this.#layerLegend = this.#layerLegend?.map((config) => {
if (this.offsetWidth !== config.width) {
config.width = this.offsetWidth;
}
return { ...config };
});
this.requestUpdate();
}).observe(this.renderRoot.querySelector(".legend-container"));
}
}

/**
* Renders a Time Control for datetime options of a layer.
* Renders color legends based on the layerLegend property.
*/
render() {
if (!customElements.get("color-legend")) {
Expand All @@ -105,28 +131,38 @@ export class EOxLayerControlLayerLegend extends LitElement {
() => html`
<div class="legend-container">
<!-- Render color-legend-->
<color-legend
id="${this.layer.get("id")}"
width=${this.layerLegend.width ?? 325}
scaleType="${ifDefined(this.layerLegend.scaleType)}"
markType="${ifDefined(this.layerLegend.markType)}"
titleText="${ifDefined(this.layerLegend.title)}"
.range=${this.layerLegend.range}
.domain=${this.layerLegend.domain}
tickFormat="${ifDefined(this.layerLegend.tickFormat)}"
.ticks=${this.layerLegend.ticks ?? 5}
.tickValues=${this.layerLegend.tickValues}
.marginLeft=${0}
.marginRight=${0}
>
</color-legend>
${this.#layerLegend.map(
(legend, idx, configs) => html`
<color-legend
id="${legend.id}"
width=${legend.width ?? 325}
scaleType="${ifDefined(legend.scaleType)}"
markType="${ifDefined(legend.markType)}"
titleText="${ifDefined(legend.title)}"
.range=${legend.range}
.domain=${legend.domain}
tickFormat="${ifDefined(legend.tickFormat)}"
.ticks=${legend.ticks ?? 5}
.tickValues=${legend.tickValues}
.marginLeft=${0}
.marginRight=${0}
>
</color-legend>
${idx !== configs.length - 1
? html`<div class="separator"></div>`
: nothing}
`,
)}
</div>
`,
)}
`;
}

#styleBasic = css`
.separator {
margin: 0 0 24px 0;
}
color-legend {
--cle-background: transparent;
--cle-font-family: inherit;
Expand Down
1 change: 1 addition & 0 deletions elements/layercontrol/src/enums/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,5 @@ export {
STORIES_LAYER_VESSEL_DENSITY_CARGO,
STORIES_LAYER_CROPOMHUSC2,
STORIES_LAYER_SEE,
STORIES_LAYER_POLARIS,
} from "./stories";
135 changes: 135 additions & 0 deletions elements/layercontrol/src/enums/stories/assets/polaris-style.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
{
"variables": {
"ship_class": "nis",
"type_of_ice": "standard",
"type_of_visualisation": "polaris",
"combined_prop": "polaris_standard_pc_nis_rio"
},
"fill-color": [
"case",
["==", ["var", "type_of_visualisation"], "WMO Concentration"],
[
"match",
["get", "wmo_concentration"],
"Ice Free",
[0, 100, 255, 1],
"Open Water (< 1/10 ice)",
[150, 200, 255, 1],
"Bergy Water",
[150, 200, 255, 1],
"1/10",
[140, 255, 159, 1],
"2/10",
[140, 255, 159, 1],
"3/10",
[140, 255, 159, 1],
"4/10",
[255, 255, 0, 1],
"5/10",
[255, 255, 0, 1],
"6/10",
[255, 255, 0, 1],
"7/10",
[255, 125, 7, 1],
"8/10",
[255, 125, 7, 1],
"9/10",
[255, 0, 0, 1],
"10/10",
[255, 0, 0, 1],
"9/10 to 10/10 ice, 9+/10",
[255, 0, 0, 1],
"Unknown/Undetermined",
[255, 255, 255, 1],
[255, 255, 255, 1]
],
["==", ["var", "type_of_visualisation"], "WMO Stage of Development"],
[
"match",
["get", "wmo_stage_of_development"],
"Ice Free",
[0, 100, 255, 1],
"Brash Ice",
[0, 0, 0, 0],
"No stage of development",
[0, 0, 0, 0],
"New Ice",
[240, 210, 250, 1],
"Nilas Ice Rind (<10 cm)",
[255, 100, 255, 1],
"Young Ice (10 to 30 cm)",
[0, 0, 0, 0],
"Grey Ice",
[135, 60, 215, 1],
"Grey-White Ice",
[220, 80, 235, 1],
"First Year Ice (>30 cm) or Brash Ice",
[255, 255, 0, 1],
"Thin First Year Ice (30 to 70 cm)",
[155, 210, 0, 1],
"Medium First Year Ice (70 to 120 cm)",
[0, 200, 20, 1],
"Thick First Year Ice (>120 cm)",
[0, 120, 0, 1],
"Old Ice",
[180, 100, 50, 1],
"Second-Year Ice",
[255, 120, 10, 1],
"Multi-Year Ice",
[200, 0, 0, 1],
"Bergy Water",
[255, 255, 255, 1],
"Unknown/Undetermined",
[255, 255, 255, 1],
[0, 0, 0, 0]
],
["==", ["var", "type_of_visualisation"], "polaris"],
[
"case",
["==", ["get", "polygon_type"], "Ice Free"],
[0, 100, 255],
["==", ["get", ["var", "combined_prop"]], "RIO > 20: Normal Operation"],
[54, 122, 74, 1],
[
"==",
["get", ["var", "combined_prop"]],
">= 10 RIO < 20: Normal Operation"
],
[62, 150, 85, 1],
[
"==",
["get", ["var", "combined_prop"]],
">= 0 RIO < 10: Normal Operation"
],
[102, 188, 118, 1],
[
"==",
["get", ["var", "combined_prop"]],
">= -10 RIO < 0: Operation subject to special consideration"
],
[252, 251, 1, 1],
[
"==",
["get", ["var", "combined_prop"]],
">= -20 RIO < -10: Operation subject to special consideration"
],
[227, 108, 9, 1],
[
"==",
["get", ["var", "combined_prop"]],
"RIO < -20: Operation subject to special consideration"
],
[188, 1, 6, 1],
[
"==",
["get", ["var", "combined_prop"]],
"<= -10 RIO < 0: Elevated operational risk"
],
[252, 251, 1, 1],
[0, 0, 0, 1]
],
[0, 0, 0, 0]
],
"stroke-color": "black",
"stroke-width": 1
}
Loading

0 comments on commit 919ea60

Please sign in to comment.