Generic 3D viewer for Digital Twin purposes.
An initiative by Geodan and Provincie Zeeland.
Create a copy of .env.example and name it .env. Fill in the required environment variables.
npm install
npm run devdocker build -t 3d-viewer .
docker run -p 3000:3000 3d-viewernpm run buildThe default build will create a build which can be served with node and cannot be served statically because the build proccess automatically picks up server side scripts such as ./routes/+layour.server.ts.
Before building, it is important to configure the environment variable APP_URL in .env. Make sure this variable points to the base path of your application, for example https://site.com/some/path/.
Run the static build with:
npm run build --adapter=staticOutput of the static build can be found in the ./build directory.
svelt.config.js is configured to be able to run the 'normal' and static build, the static build will use a different routes folder routes-static which contains an altered version of +layout.svelte and does not include +layout.server.ts.
With the static build there are 2 ways to load a configuration.
- Start the viewer with
?url=http://host.com/some_config.json, the viewer will try to load the configuration from URL - Place a file named config.json in the root directory of the build. When ?url is supplied the local file will not be used.
An example config is stored in ./static/example.config.json.
Base configuration for the viewer such as start position, UI colors.
| value | description | type |
|---|---|---|
| startPosition | Startposition of the camera | startPosition |
| startCameraMode3D | Choose to start the camera in 2D or 3D mode | boolean |
| startToolOpen | Choose the id of the map tool you want the viewer to start with already opened. Current support: layermanager, stories |
string |
| colors | Colors to use in de app, for more info check Carbon Design | colors |
| title | The title shown in the top bar of the viewer | string |
| subTitle | Subtitle shown in the top bar after the title | string |
| logo | URL for the image to show in the top left corner of the header | string |
| logoMarginLeft | Margin string for left margin of header logo | string |
| logoMarginRight | Margin string for right margin of header logo | string |
"viewer": {
"startPosition": ...,
"colors": ...,
"title": "Digital Twin",
"subTitle": "Example",
"logo": "http://host.nl/my_image.png"
}The start position of the camera. Since we are using a 3D viewer we need more than just an x, y and z position. An easy way to interactively get all the parameters for your preferred startPosition is by using the dt-generic-viewer. Open the settings from the left menu bar and enable the option Camera position. When moving the view you will see the camera settings appear in a box. You can copy these settings to the startPosition configuration. Note: pitch is always overwritten with -90 degrees if startCameraMode3D is set to false.
| value | description | type |
|---|---|---|
| x | Longitude position of the camera | number |
| y | Latitude position of the camera | number |
| z | Height of the camera in meters | number |
| heading | Heading of the camera (Rotation) | number |
| pitch | Pitch of the camera (up/down) where -90 is looking down, 0 is forward, 90 is up | number |
| duration | Time to fly to the location in seconds | number |
"startPosition": {
"x": 4.55009,
"y": 51.93289,
"z": 1108.00411,
"heading": 344.23744,
"pitch": -44.5522,
"duration": 0
}Colors for the GUI.
| value | description | type |
|---|---|---|
| header-color | Background color of the header bar | string |
| title-color | Color of the title text in the header | string |
| sub-title-color | Color of the subtitle text in the header | string |
| ui-background | Default page background | string |
| interactive-01 | Primary interactive color. Primary buttons | string |
| interactive-02 | Secondary interactive color. Secondary button | string |
| interactive-03 | Tertiary button | string |
| interactive-04 | Selected elements. Active elements. Accent icons | string |
| ui-01 | Primary container background, Secondary page background | string |
| ui-02 | Primary page background, Secondary container background | string |
| ui-03 | Subtle border, Tertiary background color | string |
| ui-04 | 3:1 AA element contrast, Medium contrast border | string |
| ui-05 | 4.5:1 AA element contrast, High contrast border, Emphasis elements | string |
| text-01 | Primary text, Body copy, Headers, Hover text color for text-02 | string |
| text-02 | Secondary text, Input labels, Help text | string |
| text-03 | Placeholder text | string |
| text-04 | Text on interactive colors | string |
| link-01 | Primary links, Ghost button | string |
| icon-01 | Primary icons | string |
| icon-02 | Secondary icons | string |
| icon-03 | Tertiary icons, Icons on interactive colors, Icons on non-ui colors | string |
| field-01 | Default input fields, Field color on $ui-backgrounds | string |
| field-02 | Input field color on $ui-02 backgrounds | string |
| inverse-01 | Inverse text color, Inverse icon color | string |
| inverse-02 | High contrast backgrounds, High contrast elements | string |
| support-01 | Error | string |
| support-02 | Success | string |
| support-03 | Warning | string |
| support-04 | Information | string |
| inverse-support-01 | Danger in high contrast moments | string |
| inverse-support-02 | Success in high contrast moments | string |
| inverse-support-03 | Warning in high contrast moments | string |
| inverse-support-04 | Information in high contrast moments | string |
| overlay-01 | Background overlay | string |
| interaction-tokens | Focus border, Focus underline | string |
| hover-primary | interactive-01 hover | string |
| hover-primary-text | interactive-01 text hover | string |
| hover-secondary | interactive-02 hover | string |
| hover-tertiary | interactive-03 hover, $inverse-01 hover | string |
| hover-ui | ui-01 hover, $ui-02 hover, Transparent background hover | string |
| hover-selected-ui | Selected row hover | string |
| hover-danger | Danger hover, $support-01 hover | string |
| hover-row | Row hover | string |
| active-primary | interactive-01 active | string |
| active-secondary | $interactive-02 active, $inverse-01 active | string |
| active-tertiary | interactive-03 active | string |
| active-ui | $ui-01 active, $ui-02 active | string |
| active-danger | Danger active, $support-01 active | string |
| selected-ui | Selected UI elements | string |
| highlight | interactive-01 highlight | string |
| skeleton-01 | Skeleton state of graphics | string |
| skeleton-02 | Skeleton state of texts | string |
| visited-link | Visited links | string |
| disabled-01 | Disabled fields, Disabled backgrounds, Disabled border | string |
| disabled-02 | Disabled elements on $disabled-01, Disabled text on $disabled-01, Disabled icons, Disabled border | string |
| disabled-03 | Disabled text on $disabled-02, Disabled icons on $disabled-02 | string |
"colors": {
"ui-background": "#ffffff",
"interactive-01": "#214170",
"interactive-02": "#171717",
"interactive-03": "#0062ff",
"interactive-04": "#0062ff",
"ui-01": "#f3f3f3",
"ui-02": "#ffffff",
"ui-03": "#dcdcdc",
"ui-04": "#8c8c8c",
"ui-05": "#171717",
"text-01": "#171717",
"text-02": "#565656",
"text-03": "#8c8c8c",
"text-04": "#ffffff",
"link-01": "#0062ff",
"icon-01": "#171717",
"icon-02": "#565656",
"icon-03": "#ffffff",
"field-01": "#f3f3f3",
"field-02": "#ffffff",
"inverse-01": "#ffffff",
"inverse-02": "#3d3d3d",
"support-01": "#da1e28",
"support-02": "#24a148",
"support-03": "#fdd13a",
"support-04": "#054ada",
"inverse-support-01": "#fb4b53",
"inverse-support-02": "#3dbb61",
"inverse-support-03": "#fdd13a",
"inverse-support-04": "#408bfc",
"overlay-01": "#171717CC",
"interaction-tokens": "#0062ff",
"hover-primary": "#376dbc",
"hover-primary-text": "#054ada",
"hover-secondary": "#4c4c4c",
"hover-tertiary": "#4cabd8",
"hover-ui": "#e5e5e5",
"hover-selected-ui": "#cacaca",
"hover-danger": "#ba1b23",
"hover-row": "#e5e5e5",
"active-primary": "#376dbc",
"active-secondary": "#6f6f6f",
"active-tertiary": "#0530ad",
"active-ui": "#bebebe",
"active-danger": "#750e13",
"selected-ui": "#dcdcdc",
"highlight": "#C9deff",
"skeleton-01": "#e5e5e5",
"skeleton-02": "#bebebe",
"visited-link": "#'Visited links'",
"disabled-01": "#f3f3f3",
"disabled-02": "#bebebe",
"disabled-03": "#8c8c8c"
}List of groups, these groups are used for grouping layers in the layer library, there is no limit on how many child groups there can be. The root parent should be on top.
| value | description | type |
|---|---|---|
| id | Unique identifier for the group | string |
| title | Display title in the UI | string |
| parentId | If this is a child group, set the parentId with the id of the parent group | string |
"groups": [
{
"id": "1329651495370",
"title": "My Layers",
"parentId": ""
},
{
"id": "1669651495322",
"title": "My Layers Child Group",
"parentId": "1329651495370"
},
{
"id": "8658756230497",
"title": "Nature",
"parentId": ""
}
]An array of layer definitions.
Layer definition
| value | description | type |
|---|---|---|
| id | Unique layer id | string |
| type | Layer type, supported layer types:basiskaart, wms, wmts, tms, vectortiles, 3dtiles, geojson, modelanimation, custom |
string |
| title | Layer title | string |
| groupId | Id of the group where this layer belongs to or empty string, will be placed under uncategorized in library | string |
| description | Simple text field in which a layer description can be provided | string |
| imageUrl | URL of an example image of layer, will be shown in layer library | string |
| legendEnabled | Choose whether legend image is shown or not (default false) | boolean |
| legendUrl | URL of legend image or empty string. Use an empty string if you intend to get dynamic legends for wms layers using the style switcher tool |
string |
| isBackground | Set to true to use this as a background layer, background layers are separated from the thematic layers in the layer manager and only 1 background layer can be active at a time | boolean |
| defaultAddToManager | True if layer should be inmediately available in the layer manager tool on startup | boolean |
| defaultOn | True if this layer should be visible at start up, use this together with defaultAddToManager | boolean |
| attribution | Attribution for the layer data, to be displayed at at layer information page | string |
| metadata | An array of {"key":"somekey","value":"somevalue"} pairs, to store custom metadata which is shown in the layer library | array[KeyValue] |
| metadataUrl | URL of a metadata document for the layer. The layer library parses it and shows its contents, and falls back to a link to the document when no metadata entries are set; the layer manager and the zonal statistics panel show an information icon that opens the URL in a new tab |
string |
| transparent | True if layer can be transparent | boolean |
| disablePopup | True if the feature info popup should be turned off | boolean |
| opacity | Number between 0 (opaque) and 100 (transparent) | number |
| cameraPosition | Default camera position, when set a zoom to icon is displayed for the layer in the layer manager | cameraPosition, same as parameters for startPosition |
| settings | Technical settings for the layer, this can differ between layer types, see LayerSettings below | LayerSettings |
| value | description | default | type |
|---|---|---|---|
| url | base URL for the layer service | string | |
| featureName | Name of feature or wms layer, can be found in WMS GetCapabilities | string | |
| contenttype | The http content type for the map data to be retrieved | image/png | string |
| webMercator | Use the Web Mercator tiling scheme for EPSG:3857 WMS services. If omitted or false, Cesium's geographic tiling scheme is used. | false | boolean |
{
"id": "1665483575374",
"type": "wms",
"title": "Beheer vlakken RWS (WMS)",
"groupId": "1658756230497",
"description": "Ook wel bekend als KernGIS Nat",
"legendUrl": "https://geo.rijkswaterstaat.nl/services/ogc/gdr/beheerkaart_nat/ows?service=WMS&request=GetLegendGraphic&format=image%2Fpng&width=20&height=20&layer=beheer_vlakken",
"isBackground": false,
"defaultAddToManager": true,
"defaultOn": false,
"transparent": true,
"opacity": 0,
"cameraPosition": {
"x": 4.55017,
"y": 51.94717,
"z": 10.1657,
"heading": 336.80053,
"pitch": -20.82619,
"duration": 1.5
},
"settings": {
"url": "https://geo.rijkswaterstaat.nl/services/ogc/gdr/beheerkaart_nat/ows?service=WMS&&version=1.3.0",
"featureName": "beheer_vlakken",
"contenttype": "image/png",
"tools": {
"styleSwitcher": {
"enabled": true
}
}
}
}- styleSwitcher: Automatically retrieve a list of available styles from the GetCapabilities that you can switch between. Also dynamically updates the legend
| value | description | default | type |
|---|---|---|---|
| enabled | Enable the tool | false | boolean |
LayerSettings
| value | description | default | type |
|---|---|---|---|
| url | Base URL for the layer service | string | |
| featureName | Name of feature of wmts layer, can be found in WMTS GetCapabilities | string | |
| contentType | The http content type for the map data to be retrieved | image/png | string |
| matrixids | List matrix ids to be used by this wmts layer | EPSG:3857:0...EPSG:3857:19 | array of string |
| tileMatrixSetID | Name of the matrixset | EPSG:3857 | string |
| tileWidth | Pixel width of tile | 256 | number |
| tileHeigth | Pixel height of tile | 256 | number |
| maximumLevel | Maximum zoom levers of layer | amount items in matrixids - 1 | number |
"layers":[
{
"id": "1637484989545",
"type": "wmts",
"title": "Luchtfoto Actueel HR (WMTS)",
"groupId": "",
"legendUrl": "",
"isBackground": true,
"defaultAddToManager": true,
"defaultOn": true,
"transparent": true,
"opacity": 0,
"settings": {
"url": "https://service.pdok.nl/hwh/luchtfotorgb/wmts/v1_0",
"featureName": "Actueel_orthoHR",
"contentType": "image/jpeg",
"matrixids": ["00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19"],
"tileMatrixSetID": "EPSG:3857"
}
}
]| value | description | default | type |
|---|---|---|---|
| url | URL to tileset.json for the 3D Tiles layer | string | |
| shadows | If shadows casting & receiving is enabled or disabled | true | boolean |
| tilesetHeight | 3D tiles layer height (z position) can be changed, supply the change in meters here | 0 | number |
| enableHeightControl | Allows the user to set the tilesetHeight using an input element. The tileset height is taken as the input element's initial value. | false | boolean |
| defaultTheme | If a layer has themes, you can set the default theme to use here | First in the list if not set | string |
| style | A cesium 3D Tiles style object as defined in the documentation. For pointclouds, this is where you set the pointSize attribute. |
Object | |
| themes | List of type theme, themes can be used to style features in 3D Tiles | Array<Theme> | |
| filter | Filter to apply to the 3D Tiles layer. | 3D Tiles Filter |
{
"id": "1536985650335",
"type": "3dtiles",
"title": "BAG3D op NAP 0m (3D tile)",
"groupId": "1669651495370",
"legendUrl": "",
"isBackground": false,
"defaultAddToManager": true,
"defaultOn": true,
"transparent": false,
"opacity": 0,
"settings": {
"url": "https://storage.googleapis.com/ahp-research/maquette/cesium/buildings/tileset.json",
"defaultTheme": "",
"themes": [
...
]
}
}It is possible to style 3D tiles based on properties of a feature, we call this a theme. It's possible to add multiple themes for a 3D Tiles layer, the themes will be displayed when a 3D tiles layer is expanded from the layer manager. See the Cesium documentation on Conditions here on how to use a condition. There is currently only support for color conditions.
| value | description | type |
|---|---|---|
| title | Display title of the Theme, be sure to make this one unique within the list of themes for a layer | string |
| conditions | An array defining a series of conditions, see here for more info | Array<[string, string]> |
| legend | The legend that is displayed for the selected theme in the layer manager, user can hover and select entries from the legend to show/hide features | Array<{ color: string, label: string } |
In the next example we have a layer with building features containing a label property with values ranging from A++++ to G. The following config colors the buildings according to their energy label.
"themes": [
{
"title": "Energy",
"conditions": [
...,
[
"${label} === \"A\"",
"color(\"#009037\")"
],
[
"${label} === \"B\"",
"color(\"#55ab26\")"
],
[
"${label} === \"C\"",
"color(\"#c8d100\")"
],
....
],
"legend": [
...,
{
"color": "#009037",
"label": "a"
},
{
"color": "#55ab26",
"label": "b"
},
{
"color": "#c8d100",
"label": "c"
},
...,
[
"true",
"color(\"#fff\")"
]
]
}
]It is possible to filter 3D tiles based on properties of a feature. The value of the "filter" in the settings of a 3D Tiles layer should have the following structure:
| value | description | default | type |
|---|---|---|---|
| filterAttribute | The attribute in the 3D Tiles to filter on | string | |
| classMapping | The class mapping, mapping the attribute values to the corresponding class labels. See the example below. | Object |
"filter": {
"filterAttribute": "Classification",
"classMapping": {
"0": "Class 0",
"1": "Class 1",
"2": "Class 2"
}
}| value | description | default | type |
|---|---|---|---|
| url | URL to the GeoJSON file | string | |
| clampToGround | Choose to clamp the layer to the terrain | true | boolean |
| style | If it is a string, it points to the property of the GeoJSON to base the styling on. If it is an object, it can contain a stroke (HEX-string), strokeWidth (number) and fill (HEX-string). |
string or object | |
| classMapping | Optional value-to-color map for class-based styling of the style attribute. Keys are attribute values, values are HEX colors. The layer manager's color randomizer overrides these with random colors on demand. |
object | |
| tools | Selection of GeoJSON tools available in the layer manager | tool |
- extrude: Makes the layer polygons 3D, controlled by a height slider.
Note: the geojson should have Z-coordinates for the polygons to be extruded. The extrusion will be relative to the mean Z-value per entity in the GeoJSON.
| value | description | default | type |
|---|---|---|---|
| slider_min | Height slider minimum | 0 | number |
| slider_max | Height slider maximum | 10 | number |
| slider_step | Height slider interval | 1 | number |
| slider_default | Height slider default value | 0 | number |
| slider_label | Label for the slider | " meter (NAP)" | string |
{
"id": "1",
"type": "geojson",
"title": "GeoJSON layer",
"groupId": "1",
"isBackground": false,
"defaultAddToManager": true,
"defaultOn": true,
"settings": {
"url": "https://some-site.nl/file.geojson",
"style": {
"stroke": "#0000ff",
"strokeWidth": 10,
"fill": "#ff0000"
},
"clampToGround": true,
"tools": {
"extrude": {
"slider_min": 0,
"slider_max": 10,
"slider_step": 1
}
}
}
},{
"id": "2",
"type": "geojson",
"title": "GeoJSON layer 2",
"groupId": "1",
"isBackground": false,
"defaultAddToManager": true,
"defaultOn": true,
"settings": {
"url": "https://some-site.nl/file.geojson",
"style": "label",
"classMapping": {
"A": "#44ce1b",
"B": "#bbdb44",
"C": "#f7e379",
"D": "#f2a134",
"E": "#e51f1f"
},
"clampToGround": true,
"tools": {
"extrude": {
"slider_min": 0,
"slider_max": 10,
"slider_step": 1
}
}
}
}| value | description | default | type |
|---|---|---|---|
| url | URL to data file for the animation in GeoJSON format. Should be a FeatureCollection of Points with the time specified in the properties | string | |
| modelUrl | URL to the .glb or .gltf file of the 3D model to be used for the animation | string | |
| timeKey | Key of the parameter in the GeoJSON properties that holds the time value (e.g.: '2022-08-01T12:25:11Z') | string | |
| orientationKey | Optional: Key of the parameter in the GeoJSON properties that specifies the orientation of the model in degrees relative to north | string | |
| clampToTerrain | True if the model should be clamped to the terrain. If false, the model will move over the ellipsoid | true | boolean |
{
"id": "1",
"type": "modelanimation",
"title": "Animated model X",
"groupId": "1",
"defaultAddToManager": true,
"defaultOn": true,
"settings": {
"url": "https://some-site.nl/file.geojson",
"modelUrl": "https://some-site.nl/model.glb",
"timeKey": "timestamplast",
"orientationKey": "cog",
"clampToTerrain": true
}
}Multiple tools can be enabled and configured for the viewer trough the config file.
| value | description | type |
|---|---|---|
| tools | Array of tools to show/configure for the viewer | Array |
"tools": [
...
]| value | description | type |
|---|---|---|
| id | Id of the tool to configure | string |
| enabled | Boolean to enable/disable the tool | boolean |
| settings | Tool specific settings, see below | ToolSettings |
{
"id": "layerlibrary",
"enabled": true,
"settings": {
...
}
}Library with layers from the config with an option to add connectors to other systems, there is currently only a connector for CKAN available. From the layer library, a user can view additional information about a layer and add or remove layers to the map.
| value | description | type | |
|---|---|---|---|
| alias | Optional: Different name for the tool showing in the viewer | string | |
| position | Optional: Change the default position of the tool in the top left toolbar. Max value must be equal to the number of enabled tools | integer | |
| connectors | type | Type of connector, currently supported ckan |
string |
| url | URL to the service/file | string | |
| organizations | Optional: Array of strings defining which CKAN organizations (organization names) to retrieve the layers from |
Array | |
| groups | Optional: Array of strings defining which CKAN groups (group names) to retrieve the layers from |
Array | |
| packages | Optional: Array of strings defining which CKAN packages (package names) to retrieve |
Array | |
| backgroundLayers | Optional: Resources (resource names or resource ids) that should be treated as background layers |
Array | |
| layersAddedOn | Optional: Resources (resource names or resource ids) that should be added to the layer manager upon opening the viewer and turned on |
Array | |
| layersAddedOff | Optional: Resources (resource names or resource ids) that should be added to the layer manager upon opening the viewer and turned off |
Array | |
| useTags | Optional: If set to true, it is possible to filter datasets in the Library based on their tags. Default: false |
boolean |
{
"id": "layerlibrary",
"enabled": true,
"settings": {
"alias": "Mylibrary",
"position": 1
"connectors": [{
"type": "ckan",
"url": "https://data.beta.geodan.nl",
"organizations": ["rijkswaterstaat", "pdok"],
"groups": ["group_name_1", "group_name_2", "group_name_3"],
"packages": ["package_name_1", "package_name_2"],
"specialResources": {
"backgroundLayers": ["resource_name_1", "fd1126fd-c557-47e6-9d95-e60d5897eeb0"],
"layersAddedOn": ["7f7b7023-225f-4018-ae4a-3381c79c7248"],
"layersAddedOff": ["resource_name_2"]
}
}],
"useTags": true
}
}Layer manager to show the layers that are added to the map. From this tool a user can switch background layers, enable/disable layers and use more layer-specific functions such as switching themes, zooming to a pre-set camera location, changing opacity and more. There are currently no extra settings to be configured for the layerManager.
| value | description | type |
|---|---|---|
| alias | Optional: Different name for the tool showing in the viewer | string |
| position | Optional: Change the default position of the tool in the top left toolbar. Max value must be equal to the number of enabled tools | integer |
{
"id": "layermanager",
"enabled": true,
"settings": {
"alias": "My layers",
"position": 2
}
}Tool to show a feature info popup when a user clicks on the map. In the fields part of the settings it is possible to define a handler for a field returned from a layer. In the below JSON example the Feature Info box will make the value of a field/attribute with the name 'image', 'document' and 'plot' clickable. When the value is clicked the value is handled by a handler. In this case, when a user clicks the value of the image field a zoomable image will pop up in the viewer, when the value of a document field is clicked, a pdf will open, and when the value of a plot field is clicked, a timeseries chart will open.
Currently supported handlers: image, pdf and chart.
For image and pdf, the handler expects the value to be an URL.
For chart, the handler expects an array of objects (data points) in the format [{x: datestring, y: value}, {x: datestring, y: value}, ...] where the y key can be a custom name.
{
"id": "featureinfo",
"enabled": true,
"settings": {
"fields": [{
"field": "image",
"handler": "image"
},
{
"field": "document",
"handler": "pdf"
},
{
"field": "plot",
"handler": "chart"
}
]
}
}The info tool will display attribution from used libraries in the viewer and some additional viewer title and description if configured.
| value | description | type |
|---|---|---|
| title | Title of the viewer | string |
| description | Some information about the viewer | string (HTML supported) |
{
"id": "info",
"enabled": true,
"settings": {
"title": "Viewer title",
"description": "Some additional information, supports <b>HTML</b>"
}
}Geocoder tool, located at the right corner of the header instead of the toolbar. The user can search for locations using and zoom to locations using this tool. By default the Dutch Locatieserver geocoder is used: https://geodata.nationaalgeoregister.nl/locatieserver/v3. For international geocoding, OSM's Nominatim can be used: https://nominatim.openstreetmap.org.
| value | description | type |
|---|---|---|
| name | Geocoder name. Currently supporting locatieserver (Dutch), geolocation (Belgian) and nominatim (worldwide) | string |
{
"id": "geocoder",
"enabled": true,
"settings": {
"name": "locatieserver"
}
}Mode switcher tool, located at the right corner of the header instead of the toolbar, the user can toggle between 3D and 2D mode using this tool. This disables tilting in the viewer, locks the pitch angle at -90, and turns the terrain off. Defaults to 3D mode.
{
"id": "modeswitcher",
"enabled": true,
"settings": {}
}Tool where the user can change settings of the Cesium viewer. Settings can be used to change the viewer default values.
| value | description | default | type |
|---|---|---|---|
| dateTime | Date and time, determines the sun position | 1657450800 (10-07-2022 11:00:00) | unix timestamp |
| shadows | Shadows enabled/disabled | false | boolean |
| showMouseCoordinates | Debug window in viewer to show coordinates for mouse position | false | boolean |
| showCameraPosition | Debug window to show the current camera position, updates on move | false | boolean |
| showLoadingWidget | Show a small bar on the bottom of the viewer showing the loading progress of layers | false | boolean |
| fxaa | FXAA enabled | true | Boolean |
| msaa | MSAA samples | 1 | number |
| lighting | Enable lighting the globe with the scene's light source | true | boolean |
| animate | Enable when displaying animated models else animations only update when the viewer refreshes it's view such as when panning/zooming | false | boolean |
| resolutionScale | Gets or sets a scaling factor for rendering resolution. Values less than 1.0 can improve performance on less powerful devices while values greater than 1.0 will render at a higher resolution and then scale down, resulting in improved visual fidelity | window.devicePixelRatio | number |
| maximumScreenSpaceError | The maximum screen space error used to drive level of detail refinement. for 3D tile layers | 1.2 | number |
| groundAtmosphere | Ground atmosphere enabled | true | boolean |
| fog | Fog enabled | true | boolean |
| highDynamicRange | HDR enabled | false | boolean |
| pointCloudAttenuation | 3D Tile Point Cloud Attenuation enabled, Perform point attenuation based on geometric error | true | boolean |
| pointCloudAttenuationMaximum | 3D Tile Point Cloud Maximum point attenuation in pixels. If undefined, the Cesium3DTileset's maximumScreenSpaceError will be used | 0 | number |
| pointCloudAttenuationErrorScale | Scale to be applied to the geometric error before computing attenuation | 1 | number |
| pointCloudAttenuationBaseResolution | Average base resolution for the dataset in meters. Used in place of geometric error when the geometric error is 0. If undefined, an approximation will be computed for each tile that has a geometric error of 0 | 0 | number |
| pointCloudEDL | Eye Dome Lighting enabled, Use eye dome lighting when drawing with point attenuation Requires support for EXT_frag_depth, OES_texture_float, and WEBGL_draw_buffers extensions in WebGL 1.0, otherwise eye dome lighting is ignored | true | boolean |
| pointCloudEDLStrength | Eye dome lighting strength (apparent contrast) | 1 | number |
| pointCloudEDLRadius | Thickness of contours from eye dome lighting | 1 | number |
| globeOpacity | Opacity percentage of the globe | 100 | number |
| enableCollisionDetection | Prevent the camera from moving below the terrain/surface. Set to true to prevent going subsurface |
false | boolean |
| terrainProviders | Array of terrain providers, first in list is activated by default, leave out URL to create empty provider (see example below) | - | Terrain Provider |
{
"id": "cesium",
"enabled": true,
"settings": {
"fxaa": true,
"shadows": false,
"animate": false,
"resolutionScale": 1,
"maximumScreenSpaceError": 16,
"groundAtmosphere": true,
"lighting": true,
"skyAtmosphere": true,
"fog": true,
"highDynamicRange": false,
"enableCollisionDetection": false,
"pointCloudAttenuationMaximum": 2,
"terrainProviders": [
{
"title": "25gn1",
"url": "https://api.pdok.nl/kadaster/3d-basisvoorziening/ogc/v1_0/collections/digitaalterreinmodel/quantized-mesh",
"vertexNormals": true
},
{
"title": "Uit"
}
]
}
}The help tool can be opend from the toolbar or configured to open on startup of the viewer. The help tool presents basic information on how to use the viewer and supports additional information to show in the introduction tab.
Next to the always visible tabs (introduction, movement and library), tabs are shown for the flooding, stories, isochrones and zonalStatistics tools when those tools are enabled.
| value | description | type |
|---|---|---|
| showOnStart | Show the popup on opening the viewer, can be disabled by the user after the first time | boolean |
| introSettings | Optional: Custom settings for the intro tab. Includes a custom description and download button. | object |
{
"id": "help",
"enabled": true,
"settings": {
"showOnStart": true,
"introSettings": {
"customDescription": "<div>This is a custom HTML description.</div>",
"downloadButton": {
"enabled": true,
"url": "https://www.example.com/myfile.pdf",
"label": "Download PDF Data"
}
}
}
}The config switcher tool can be used to switch between different configurations for the viewer. The user can select a different configuration from a pop-up after clicking the icon in the tool menu. The configuration files should be served by the config server, a simple Node/ExpressJS server. The viewer will automatically load the configuration file when selected.
In order for the config switcher to work, you must configure the environment variable CONFIG_SERVER_URL. This URL should point to the base URL of the config server, including environment specification (e.g. 'http://localhost:3000/acc').
Note: in order to always be able to switch back and forth between configurations, all configuration files on the server should have the config switcher tool enabled.
| value | description | default | type |
|---|---|---|---|
| fullReload | Whether to reload the entire page on switching configs, which will change the URL of the page. If false, only some components will be reloaded. | false | boolean |
{
"id": "config_switcher",
"enabled": true,
"settings": {
"fullReload": false
}
},This tool can be used to add bookmarks to the viewer, the bookmarks set trough the config are not removable by the user. Users are able to add their own bookmarks which are stored in local-storage.
| value | description | type | |
|---|---|---|---|
| alias | Optional: Different name for the tool showing in the viewer | string | |
| position | Optional: Change the default position of the tool in the top left toolbar. Max value must be equal to the number of enabled tools | integer | |
| bookmarks | title | The title of the bookmark | string |
| description | The description of the bookmark | string | |
| x | Longitude position of the camera | number | |
| y | Latitude position of the camera | number | |
| z | Height of the camera in meters | number | |
| heading | Heading of the camera (Rotation) | number | |
| pitch | Pitch of the camera (up/down) where -90 is looking down, 0 is forward, 90 is up | number | |
| duration | Time to fly to the locaton in seconds | number |
{
"id": "bookmarks",
"enabled": true,
"settings": {
"alias": "My bookmarks",
"position": 3,
"bookmarks": [
{
"title": "3DNL Urmond",
"description": "Cyclomedia",
"x": 5.81753,
"y": 51.02999,
"z": 224.50458,
"heading": 199.27162,
"pitch": -21.6787,
"duration": 2
},
{
"title": "Zonneboiler",
"description": "I3S",
"x": 4.55017,
"y": 51.94717,
"z": 10.1657,
"heading": 336.80053,
"pitch": -20.82619,
"duration": 1.5
}
]
}
}This tool can be used to add projects with project-specific layers. The project will be cut-out from the viewer according to the input polygon. The openProject option can be set to directly open a project when loading the viewer.
| value | description | type | |
|---|---|---|---|
| alias | Optional: Different name for the tool showing in the viewer | string | |
| position | Optional: Change the default position of the tool in the top left toolbar. Max value must be equal to the number of enabled tools | integer | |
| openProject | The name of the project you want to open when loading the viewer. Leave this empty if you don't want to open a project by default. | string | |
| projects | name | The name of the project | string |
| description | A description for the project | string | |
| polygon | An array of coordinates describing the project delimitation | array of [lon: number, lat: number] | |
| layers | An array of layer objects to be shown for the project | array of { id: string, on: boolean, tileset?: string } | |
| cameraPosition | The default camera position | cameraLocation |
{
"id": "projects",
"enabled": true,
"settings": {
"alias":"My projects",
"position": 4,
"openProject": "My project name",
"projects": [
{
"name": "My project name",
"description": "Short description of my project",
"polygon": [
[
4.9000,
52.39961
],
[
4.91807,
52.39961
],
[
4.9193,
52.38107
],
[
4.9000,
52.38575
]
],
"layers": [
{
"id": "DTB 3D",
"on": true
},
{
"id": "3D BAG",
"on": false
},
{
"id": "GeoTOP",
"on": false,
"tileset": "https://virtueel.zeeland.nl/tiles_other/geotop_middelburg/3dtiles/tileset.json"
}
],
"cameraPosition": {
"x": 4.94802,
"y": 52.35647,
"z": 2176.53646,
"heading": 326.85260,
"pitch": -24.10943,
"duration": 1.50
}
}
]
}
}, Measuring tool accessible through the toolbar, with this tool the user can add 3d measurements to the viewer. No additional settings are needed. Measurements are stored in local storage.
| value | description | type |
|---|---|---|
| alias | Optional: Different name for the tool showing in the viewer | string |
| position | Optional: Change the default position of the tool in the top left toolbar. Max value must be equal to the number of enabled tools | integer |
{
"id": "measure",
"enabled": true,
"settings": {
"alias": "Measure (distance) π",
"position": 5
}
}Tool for storymapping. Create and show multiple stories in the viewer. Each story can contain multiple chapters with steps which the user can click through. Each chapter has an id, title, button text (shorthand for longer titles) and steps. Each step has a title and description (HTML), a fly-to location, and a set of layers with their settings (id, style, opacity, showOpacitySlider). A story can be opened directly in the viewer through the 'story' search parameter, for example: "https://some-site.nl/?story=mystoryname".
| value | description | type | |
|---|---|---|---|
| alias | Optional: Different name for the tool showing in the viewer | string | |
| position | Optional: Change the default position of the tool in the top left toolbar. Max value must be equal to the number of enabled tools | integer | |
| showOnMap | Optional: Show story markers on the map initially. The visibility can also be changed with the Stories tool toggle, which is available both in the story overview and at the bottom of an opened story. Defaults to true |
boolean | |
| stories | name | The name of the story | string |
| description | A short description to describe the story | string | |
| width | The width of the story menu | string | |
| forceCameraMode | Forces the camera into a fixed mode while the story is open and prevents users from switching camera mode. Accepts "2D" or "3D". On opening the story the camera switches to the given mode if needed; on closing it reverts to the previous mode if it was changed |
string | |
| staticCamera | Keeps camera location the same after drawing and between steps | boolean | |
| requestPolygonArea | Adds a polygon drawing tool that requests data in each story step from a WMS layer if a WCS layer with an identical name exists. Define whether the tool is enabled and what API should be used (if enabled) | object | |
| baseLayerId | ID of a base layer that can be toggled on or off and can be seen in each story step | string | |
| chapters | Structure of storysteps within chapters. Each chapter has a chapter id and a list of steps. See the example below | object | |
| chapterGroups | Groups the chapter ids refer to | object |
Each layer within a step's layers array supports these settings:
| value | description | default | type |
|---|---|---|---|
| id | ID of the layer to add in this step | - | string |
| opacity | Initial opacity percentage of the layer | 100 | number |
| style | Style/theme to apply to the layer | - | string |
| showOpacitySlider | Whether the transparency slider is shown for this layer in the story step | true | boolean |
Each story step can also define markerCoordinates. The marker label shows the story, chapter, and step name. Clicking a marker opens the story directly on its step. Use x for longitude and y for latitude. A step can have one coordinate object or a list of coordinate objects. While a story is open only that story's markers are shown, so they can be used to jump between its steps; hide them with the toggle at the bottom of the story.
| value | description | type |
|---|---|---|
| markerCoordinates | Optional: Location or locations of markers for this story step | object or array[object] |
| x | Longitude of the story marker | number |
| y | Latitude of the story marker | number |
{
"id": "stories",
"enabled": true,
"settings": {
"alias":"My Stories",
"position": 6,
"showOnMap": true,
"stories": [
{
"name": "My Story",
"description": "Description of my story",
"width": "600px",
"forceCameraMode": "2D",
"staticCamera": false,
"requestPolygonArea": {
"enabled": false,
"statisticsApi": "https://virtueel.dev.zeeland.nl/ko_api/analyze"
},
"baseLayerId": "001",
"chapters": [
{
"id": "1",
"steps": [
{
"title": "Signaalkaart",
"html": "<div>Content of the step.</div>",
"globeOpacity": 100,
"terrain": "PDOK Terrain",
"markerCoordinates": [{
"x": 5.23907,
"y": 52.20004
}],
"camera": {
"x": 5.23907,
"y": 52.20004,
"z": 13130.05823,
"heading": 335.10694,
"pitch": -30.69127,
"duration": 1.5
},
"layers": [
{
"id": "002",
"opacity": 50
},
{
"id": "19747667-ddb2-4162-99f6-a37d5aaa15ea",
"style": "Bouwjaar",
"showOpacitySlider": false
}
//etc. You can add as many layers as you want per step
] },
//etc. You can add as many steps as you want per chapter
]
},
//etc. You can add as many chapters as you want per story
],
"chapterGroups": [
{
"id": "1",
"title": "Bebouwing",
"buttonText": "Ch.1"
},
//etc. These are the groups your chapter ids refer to
]
},
//etc. You can add as many stories as you want
]
}
}Tool to calculate and visualize car isochrones (travel-time areas) around an economic development location and use accounted population growth data to calculate the net migration surplus in the affected area.
| value | description | type |
|---|---|---|
| apiUrl | OpenRouteService isochrones endpoint URL | string |
| accountedPopulationGrowthLayerId | Layer id used to retrieve accounted population growth data | string |
| accountedPopulationGrowthAttribute | Attribute name in the configured layer that contains the accounted population growth value | string |
{
"id": "isochrones",
"enabled": true,
"settings": {
"apiUrl": "https://virtueel.zeeland.nl/ors/v2/isochrones/driving-car",
"accountedPopulationGrowthLayerId": "053",
"accountedPopulationGrowthAttribute": "at_woonplekken"
}
}Generic tool to inspect statistics per zone (e.g. per postcode area). The user clicks one or more zone geometries on the map and a floating table appears with one row per data layer added to the table and one or more configurable columns per selected zone. What the map shows and what the table shows are independent: in the tool panel each configured data layer gets a card with a radio button that makes it the layer whose values are painted on the zones (so it is always clear which layer you are looking at), while its data is added to the table with the + button on the same card (which turns into a red trash-can button to remove the row again). Removing and re-adding a layer immediately updates the rows for the already selected zones; a newly added row briefly flashes blue so it is easy to spot. All layers in the tool are drawn with one shared colour scheme: the classMapping on the zoneLayerId layer (keyed on that layer's style attribute) is applied to every configured data layer, so the same value always gets the same colour instead of each GeoJSON layer picking random colours. Because the data layers are attribute joins on the zone code, they all share the zone layer's geometry: the zones are drawn once and only recoloured when another layer is selected, and the data layers themselves are never drawn as map layers at all β only their attributes and colours are read β so adding more layers to the tool does not slow the map down or grow its memory use. The opacity slider on a layer's card sets the fill transparency while that layer is selected. The tool opens with the first configured data layer shown on the map and as the table's first row; when the table has no layers it shows a hint instead of rows and exports are disabled. Data layers are only downloaded when they are actually used: on viewer start just the zone layer is loaded, and each other layer is fetched (one at a time) the first time it is selected on the map or added to the table, with a spinner on its panel card while that happens. The zone boundaries are outlined in black for as long as the tool is open, whichever layer is selected; the zones in the table get a thicker yellow outline and the zone currently focused in the table a thicker blue one. Closing the tool empties the table and restores the zone layer to the visibility it had before the tool was opened. Each column reads an attribute from the row-layer's feature, so the tool can show categorical labels (colour-styled), numeric statistics, or any mix. Hovering a zone highlights it on the map; selected zones are tinted (the zone currently focused in the table gets the strongest tint), a live count of the selected zones is shown, and export progress is indicated while a PNG, JPEG, PDF or CSV is generated. Each selected zone's table column header has a zoom button that flies the camera to frame that zone. The table can be exported as PNG, JPEG, PDF or CSV; the tooltipAttribute description text is included in every export (a description column in the PDF and CSV, and rendered inline in the PNG/JPEG). The PNG/JPEG exports use a dedicated A4-portrait-width sheet where each selected zone is a separate table stacked vertically (rather than the wide side-by-side on-screen table), so the image fits on A4 pages. In the tool panel (left menu) each configured data layer gets a compact card with the radio button and the add/remove-from-table button, plus an opacity slider behind a chevron. The tool ships no built-in colours or branding β everything is config-driven.
| value | description | type |
|---|---|---|
| zoneLayerId | Id of the layer holding the clickable zone geometries. This is the only layer of the tool that is actually drawn: it is switched on while the tool is open and every data layer's values are painted onto it. Its settings.classMapping (keyed on its settings.style attribute) is applied to every data layer, so all layers in the tool share one colour scheme |
string |
| zoneCodeAttribute | Attribute on a zone feature that holds its code (e.g. a postcode). Defaults to postcode. Because the data layers are separate datasets joined on this code, codes are matched ignoring case and whitespace ("4331 ab" and "4331AB" are the same zone); values from classMapping are matched ignoring case too |
string |
| layers | Data layers selectable in the panel; each can be added to the table as a row. Each entry is { id, title?, columns? }; title defaults to the layer's config title, and columns overrides the source attribute names this layer reads for one or more columns (see below). The first entry is shown on the map and added to the table when the tool opens. Data layers are attribute joins on zoneCodeAttribute and are drawn on the zoneLayerId geometry, so a zone the layer has no feature for is left blank. They are never added to the map as layers themselves: only the zoneLayerId layer is loaded on viewer start, and each data layer's GeoJSON is downloaded one at a time β the first time it is selected or added to the table β to read its attributes and colours |
array |
| columns | Columns rendered per selected zone. Each entry is { key?, attribute, label?, hideInTable?, hideInImageExport?, decimals?, tooltipAttribute?, styled? }. attribute is the default source attribute name and key is the stable id a layer's columns override refers to (defaults to attribute); label defaults to attribute; hideInTable hides the column in the interactive table; hideInImageExport hides the column in the image export; decimals (integer 0-20) rounds numeric values of that column to a fixed number of decimals in the table and in every export (omit it to show the raw value); tooltipAttribute adds a hover description (and a description column in the PDF and CSV exports, rendered inline in image exports); styled: true colours the cell using valueStyles |
array |
| valueStyles | Optional value-to-colour map for styled columns. Each entry is { value, color, label? }. Drives styled cell backgrounds, the legend and PDF cell fills (PDF fills require HEX colours; other CSS colours render plain in the PDF). The text colour is derived automatically (black or white, whichever contrasts best with color) |
array |
| exportTitle | Optional title used for exports. Defaults to the tool title/alias | string |
| exportFileName | Optional file-name prefix for exports. Defaults to the tool title/alias | string |
| pdfFooterText | Optional footer text drawn on exported PDFs | string |
| pdfLogo | Optional left logo image path for exported PDFs | string |
{
"id": "zonalStatistics",
"enabled": true,
"settings": {
"alias": "Labelpaspoort",
"zoneLayerId": "999a",
"zoneCodeAttribute": "Pc6",
"exportTitle": "Klimaatlabels",
"exportFileName": "Klimaatlabels",
"pdfFooterText": "Provincie Zeeland - Klimaatlabels",
"pdfLogo": "/images/Zeeland_logo.png",
"columns": [
{ "key": "huidig", "attribute": "label", "label": "Huidig", "tooltipAttribute": "category", "styled": true },
{ "key": "ambitie", "attribute": "ambitie_label", "label": "Ambitie", "tooltipAttribute": "ambitie_category", "styled": true, "hideInTable": true},
{ "attribute": "Shape_area", "label": "Oppervlakte (mΒ²)", "hideInTable": true, "hideInImageExport": true, "decimals": 0 }
],
"valueStyles": [
{ "value": "A", "color": "#44ce1b" },
{ "value": "B", "color": "#bbdb44" },
{ "value": "C", "color": "#f7e379" },
{ "value": "D", "color": "#f2a134" },
{ "value": "E", "color": "#e51f1f" }
],
"layers": [
{ "id": "999a" },
{ "id": "999b", "columns": { "ambitie": { "attribute": "label_ca", "tooltipAttribute": "category_ca" } } }
]
}
}Source datasets do not always use the same attribute names for the same logical
column β one may call the ambition label ambitie_label, another label_ca.
Give the column a stable key and let the deviating layer override the source
attribute name it uses for that key:
"columns": [
{ "key": "ambitie", "attribute": "ambitie_label", "label": "Ambitie", "tooltipAttribute": "ambitie_category" }
],
"layers": [
{ "id": "999a" },
{ "id": "999c", "columns": { "ambitie": { "attribute": "label_ca" } } }
]Both layers then fill the same Ambitie column. Notes:
- Layers without a
columnsoverride keep using the column'sattribute, so existing configs need no change. attributeandtooltipAttributeare overridden independently; omitting one keeps the column's default.{ "ambitie": "label_ca" }is accepted as shorthand for overriding only the value attribute.- The override also applies to the shared colour scheme: the zone layer's
classMappingis looked up on each layer's own name for the class column, so a layer that names it differently still gets coloured instead of rendering as bare outlines.
The panel lists the configured data layers as a flat set of cards, in config order. Above them a header row shows how many layers are in the table (N / M) and two icon buttons add every configured layer to the table at once or empty the table again.
Header tool to enable switching between different languages. If this tool is not included or disabled, Dutch is used.
| value | description | type |
|---|---|---|
| startLanguage | Defines which language the viewer should open with. If not defined, the selected language will be remembered between sessions. Currently supports en, nl, and fr. |
string |
{
"id": "language",
"enabled": true,
"settings": {
"startLanguage": "en"
}
}Header tool to enable a link to the GitHub project page.
{
"id": "github",
"enabled": true
}Tool for navigation. With this tool the user is able to have free roam around the map by selecting either an aerial POV or ground POV.
{
"id": "flyCamera",
"enabled": true
}