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

Layer legends #303

Merged
merged 13 commits into from
Oct 31, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 2 additions & 1 deletion app-starter/static/app-conf-sidebar.json
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,8 @@
"attribution": "Kindly provided by @ahocevar",
"isBaseLayer": false,
"visible": false,
"displayInLayerList": true
"displayInLayerList": true,
"legend": true
},
{
"type": "IMAGEWMS",
Expand Down
3 changes: 2 additions & 1 deletion app-starter/static/app-conf.json
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,8 @@
"attribution": "Kindly provided by @ahocevar",
"isBaseLayer": false,
"visible": false,
"displayInLayerList": true
"displayInLayerList": true,
"legend": true
},
{
"type": "IMAGEWMS",
Expand Down
3 changes: 3 additions & 0 deletions docs/map-layer-configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ The following properties can be applied to all map layer types
| supportsPermalink | Boolean value, whether the layers state should be considered in permanent links - see also [permalink](wegue-configuration?id=permalink). Defaults to `true`. | `"supportsPermalink": true` |
| attributions | Text or HTML string to be displayed as source attribution in the map. This setting will override the layer attributions declared in the language packs. | `"attributions": "<a href='https://www.pdok.nl' target='_blank'>PDOK</a> by Dutch Kadaster",` |
| previewImage | URL to a preview image for layers to be displayed in the background layer selection control. This option has no effect if the layer is not a background layer - see option `isBaseLayer` | `"previewImage": "static/icon/my-layer-preview.png"` |
| legend | Boolean value, whether a layer legend image should be displayed in the LayerList. Defaults to `false`. | `"legend": true`|
| legendUrl | URL to a legend image. This value is required to produce a legend, if the layer is not a WMS layer. The URL may contain format placeholders corresponding to the parameters `language`, `scale` or any of the additional options given among `legendOptions`. A placeholder is delimited by `{{` and `}}` – i.e. `{{VAR_NAME}}`. | `"legendUrl": "static/icon/my-layer-legend-{{LANGUAGE}}.png"`
| legendOptions | An object, containing additional parameters to request the legend image. Supported options may be vendor specific, e.g. see [GeoServer Docs](https://docs.geoserver.org/latest/en/user/services/wms/get_legend_graphic/index.html) for the options supported for WMS layers in GeoServer. | `"legendOptions": {"transparent": true, "width": 14 }`



Expand Down
4 changes: 3 additions & 1 deletion docs/module-configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,9 @@ Module identifier: `wgu-infoclick`

Module identifier: `wgu-layerlist`

No additional config options besides the general ones.
| Property | Meaning | Example |
|----------------------|:---------:|---------|
| showLegends | Flag to enable/disable rendering of layer legend images in the LayerList. Defaults to `true`. | `"showLegends": false` |

## MeasureTool

Expand Down
20 changes: 20 additions & 0 deletions docs/wegue-configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ This describes the Wegue application configuration, which is modelled as JSON do
| tileGridDefs | Array of tile grid definition objects | See [tileGridDefs](wegue-configuration?id=tilegriddefs) |
| viewAnimation | Configuration object for view animations | See [viewAnimation](wegue-configuration?id=viewAnimation) |
| sidebar | Configuration object for the application sidebar. | See [sidebar](wegue-configuration?id=sidebar) |
| legend | Configuration object containing application wide parameters for layer legends. | See [legend](wegue-configuration?id=legend) |

### colorTheme

Expand Down Expand Up @@ -246,6 +247,25 @@ Below is an example for such a configuration object:
}
```

### legend

Wegue supports rendering of layer legend images, which will be displayed in the [LayerList module](module-configuration?id=LayerList). The optional property `legend` in the main Wegue configuration provides sensible defaults to legend request parameters for all layers in the application. This can be useful e.g. for parameters like fonts, font-sizes and other common options, which you want to share between all legends.

Supported options may be vendor specific, e.g. see [GeoServer Docs](https://docs.geoserver.org/latest/en/user/services/wms/get_legend_graphic/index.html) for the options supported for WMS layers in GeoServer.

Example:
```json
"legend": {
"transparent": true,
"width": 14,
"height": 16,
}
```

Alternatively you can specify legend request parameters on a per layer basis, by assigning a layers `legendOptions` attribute - see [mapLayers](layer-configuration?id=General).
Settings for the individual layers are merged with the application wide option, while the specific layer setting takes precedence.

For information on how to enable and customize legends for specific layers, see the documentation of [mapLayers](layer-configuration?id=General).

### viewAnimation

Expand Down
62 changes: 62 additions & 0 deletions src/components/layerlist/LayerLegendImage.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<template>
<!-- Remarks:
As we need none of the responsive functionality of v-img, we use a simple
HTML img to stop the component from flickering when the image is re-requested.
-->
<img v-if="legendURL" :src="legendURL">
</template>

<script>

import LayerLegend from '../../util/LayerLegend';

/**
* Module for one legend element.
*/
export default {
name: 'wgu-layerlegendimage',
props: {
mapView: { type: Object, required: true },
layer: { type: Object, required: true }
},
data () {
return {
resolution: this.mapView.getResolution(),
viewResolutionChanged: undefined
}
},

/**
* Register for an event to update the legend on resolution change.
*/
created () {
const viewResolutionChanged = function (event) {
JakobMiksch marked this conversation as resolved.
Show resolved Hide resolved
this.resolution = event.target.getResolution();
}.bind(this);

this.mapView.on('change:resolution', viewResolutionChanged);
this.viewResolutionChanged = viewResolutionChanged;
},
/**
* Unregister the event fired on resolution change.
*/
destroyed () {
if (this.viewResolutionChanged) {
this.mapView.un('change:resolution', this.viewResolutionChanged);
}
},
computed: {
/**
* Returns a URL to the layers legend image.
*/
legendURL () {
const options = {
language: this.$i18n.locale,
...this.layer.get('legendOptions')
};
return LayerLegend.getUrl(
this.layer, this.resolution, options, this.layer.get('legendUrl'));
}
}
}
</script>
45 changes: 18 additions & 27 deletions src/components/layerlist/LayerList.vue
Original file line number Diff line number Diff line change
@@ -1,34 +1,28 @@
<template>

<v-list>
<v-list-item class="wgu-layerlist-item"
v-for="layer in displayedLayers"
:key="layer.lid"
@click="onItemClick(layer)">
<v-list-item-action>
<v-checkbox
color="secondary"
hide-details
:input-value="layer.getVisible()"
/>
</v-list-item-action>
<v-list-item-content>
<v-list-item-title>
{{ layer.get('name') }}
</v-list-item-title>
</v-list-item-content>
</v-list-item>
</v-list>

<v-list expand>
<wgu-layerlistitem
v-for="layer in displayedLayers"
:key="layer.get('lid')"
:layer="layer"
:mapView="map.getView()"
:showDetails="showDetails(layer)"
/>
</v-list>
</template>

<script>
import { Mapable } from '../../mixins/Mapable';
import LayerListItem from './LayerListItem'

export default {
name: 'wgu-layerlist',
components: {
'wgu-layerlistitem': LayerListItem
},
mixins: [Mapable],
props: {
showLegends: { type: Boolean, required: true }
},
data () {
return {
Expand All @@ -44,13 +38,10 @@
this.layers = this.map.getLayers().getArray();
},
/**
* Handler for click on item in layer list:
* Toggles the corresponding layer visibility.
*
* @param {Object} layer Layer object
*/
onItemClick (layer) {
layer.setVisible(!layer.getVisible());
* Returns true, if the layer item should show an extension slider with layer details.
**/
showDetails (layer) {
return this.showLegends && !!layer.get('legend');
}
},
computed: {
Expand Down
81 changes: 81 additions & 0 deletions src/components/layerlist/LayerListItem.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
<template>
<!-- Show layer details -->
<v-list-group
v-if="showDetails"
v-model="open"
class="text--primary"
>
<template v-slot:activator>
<v-list-item-action>
<v-checkbox
color="secondary"
hide-details
:input-value="layer.getVisible()"
@click.capture.stop="onItemClick()"
JakobMiksch marked this conversation as resolved.
Show resolved Hide resolved
/>
</v-list-item-action>
<v-list-item-title>
{{ layer.get('name') }}
</v-list-item-title>
</template>
<v-list-item>
<!-- Remarks:
The legend image item is wrapped by an v-if block to avoid unneccesary image
requests when the layer item is not expanded.
-->
<wgu-layerlegendimage v-if="open"
:layer="layer"
:mapView="mapView"
/>
</v-list-item>
</v-list-group>

<!-- Simple layer entry -->
<v-list-item
v-else
class="wgu-layerlist-item"
>
<v-list-item-action>
<v-checkbox
color="secondary"
hide-details
:input-value="layer.getVisible()"
@click.capture.stop="onItemClick(layer)"
/>
</v-list-item-action>
<v-list-item-content>
<v-list-item-title>
{{ layer.get('name') }}
</v-list-item-title>
</v-list-item-content>
</v-list-item>
</template>

<script>
import LayerLegendImage from './LayerLegendImage'

export default {
name: 'wgu-layerlistitem',
components: {
'wgu-layerlegendimage': LayerLegendImage
},
data () {
return {
open: false
}
},
props: {
layer: { type: Object, required: true },
mapView: { type: Object, required: true },
showDetails: { type: Boolean, required: true }
},
methods: {
/**
* Handler for click on layer item, toggles the layer`s visibility.
*/
onItemClick () {
this.layer.setVisible(!this.layer.getVisible());
}
}
};
</script>
7 changes: 5 additions & 2 deletions src/components/layerlist/LayerListWin.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
class="wgu-layerlist"
:icon="icon"
>
<wgu-layerlist />
<wgu-layerlist
:showLegends="showLegends"
/>
</wgu-module-card>

</template>
Expand All @@ -21,7 +23,8 @@
'wgu-layerlist': LayerList
},
props: {
icon: { type: String, required: false, default: 'layers' }
icon: { type: String, required: false, default: 'layers' },
showLegends: { type: Boolean, required: false, default: true }
}
}
</script>
5 changes: 4 additions & 1 deletion src/factory/Layer.js
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,10 @@ export const LayerFactory = {
opacity: lConf.opacity,
zIndex: lConf.zIndex,
confName: lConf.name,
confAttributions: lConf.attributions
confAttributions: lConf.attributions,
legend: lConf.legend,
legendUrl: lConf.legendUrl,
legendOptions: lConf.legendOptions
};
},

Expand Down