Skip to main content
Version: 2.0.0

Modlet

The GIS modlet is designed such that map rendering engines can be swapped without having to change the usage of the web components. This is achieved by having web components that interfact with the rendering engine through a standardized interface.

GIS Modlet Components

Types

The GIS modlet exports its types under the Gis namespace, you can find this file in src/lib/aoh/gis/types.d.ts.

When referring to types in this documentation, you will often see the them prefixed with the "Gis" namespace, for example, Gis.GeoEntityType - this refers to types that can be found in the file mentioned above.

Components

Under the src/lib/aoh/gis/components folder, you'll find these ready-to-use Svelte components.

note

Other components you find here that are not mentioned in these documentation are either still in-development and not ready for use, or meant for internal use only, you may however use them at your own risk.

Map Component

The Map component is the heart of the GIS modlet, it contains all the glue to tie the Map components to the rendering engine. The map must always be wrapped with an engine provider. At present, we only have one engine provider (CesiumMapEngineProvider).

A bindable Gis.GisMap object is exposed if you need to get a reference to the map if necessary, but we recommend you create more Svelte Components that get the Gis.GisMap from the Svelte context instead if you want to write reusable components that could be contributed to the GIS modlet in the future.

+page.svelte
<script lang="ts">
import Map from "$lib/aoh/gis/components/Map/index.svelte";
import CesiumMapEngineProvider from "$lib/aoh/gis/components/engines/CesiumMapEngineProvider/index.svelte";

let map: Gis.GisMap;

...
</script>

<CesiumMapEngineProvider>
<Map bind:map {...} >
...
</Map>
</CesiumMapEngineProvider>

Example

Map Component
<Map
initial_camera_view={{
position: [103.8189, 1.3521] // position of Singapore
zoom: 8 // see `Gis.ZoomLevel` for more information
}}
rtus_seh_url={"http://rtus-seh.example.com"}
rtus_map_name={"gis"}
user_id={data.user?.sub}
tenant_id={data.user?.active_tenant?.tenant_id}
>
...
</Map>

initial_camera_view

This property expects a Gis.CameraView, which contains all the necessary information to position and point a camera in the map.

rtus_seh_url

The URL to the RTUS - SEH service - this for the SSE connection that will continually update the map with entities.

rtus_map_name

The name of the RTUS map that stores all the GIS state: this is the same map name as what you have declared in the GIS service.

See gis.rtus.map_name and PUBLIC_GIS_RTUS_MAP_NAME

user_id

Currently not actually used for any purpose but checked during map initialization for legacy reasons. Must not be a falsy value for the map to be initialized. Just pass in any truthy value to proceed.

tenant_id

The tenant_id of the RTUS map to subscribe to - you should be using the tenant_id of the user for this property.


CesiumMapEngineProvider Component

The implementation of the interface can be found within the src/lib/aoh/gis/components/engines folder. We currently support the CesiumJS render.


MapBaseLayerProvider Component

The MapBaseLayerProvider provides the map with base layers. This component expects one or more base layer sources to be provided as children. See MapXyzSourceProvider.

Examples:

MapBaseLayerProvider Component
<MapBaseLayerProvider layer_name="Street" is_visible={true} options={{ brightness: 0.5 }}>
<MapXyzSourceProvider url={`https://tile.openstreetmap.org/{z}/{x}/{y}.png`}></MapXyzSourceProvider>
</MapBaseLayerProvider>

You can group multiple sources under one layer to control their visiblity together. These sources will all appear as just one layer in the Layer Manager UI. The order that they appear will be based on the order they are instantiated in code here.

MapBaseLayerProvider with multiple source providers
<MapBaseLayerProvider layer_name="Street" is_visible={true} options={{ brightness: 0.5 }}>
<MapXyzSourceProvider
url={`https://api.maptiler.com/tiles/hillshade/{z}/{x}/{y}.webp?key=0123456789`}
></MapXyzSourceProvider>
<MapXyzSourceProvider url={`https://tile.openstreetmap.org/{z}/{x}/{y}.png`}></MapXyzSourceProvider>
</MapBaseLayerProvider>

layer_name

The name of the layer, this is used by the MapLayerManager as a label for toggling the visibility.

is_visible

A boolean true or false value to determine if the layer is visible by default.

brightness

A brightness modifier to darken the layer. This is particularly useful for controlling translucent layers or to make certain layers stand out.

This property is scopes under an options object:


MapXyzSourceProvider Component

The MapXyzSourceProvider allows you to add an XYZ source URL that serves map tiles in the XYZ (a.k.a Slippy Map Tilenames) format.

url

The tile source URL to connect to. The varies based on different flavours of servers, but a sample that uses an API key for authentication would look like this:

https://maptiles.p.rapidapi.com/local/osm/v1/zoom/x/y.png?rapidapi-key=YOUR-KEY

MapEntityLayerProvider Component

The MapEntityLayerProvider represents a layer that may contain one or more entity (and entity kinds). You need to also pass in a MapEntityProvider as a child snippet to provide the necessary information for to render entities in this layer.

Examples:

MapEntityLayerProvider Component
<MapEntityLayerProvider layer_name="Aircraft" is_visible>
<MapEntityProvider kind={"aircraft"}>...</MapEntityProvider>
</MapEntityLayerProvider>

layer_name

The name of the layer, this is used by the MapLayerManager as a label for toggling the visibility.

is_visible

A boolean true or false value to determine if the layer is visible by default.


MapEntityProvider Component

The MapEntityProvider requires a snippet to be supplied for a chosen "kind".

In the following example, for all geoentities of kind "example", a floating, red <div> that shows the value of example_property gets rendered. You can supply any snippet you want, and you can reference the geoentity's properties via the snippet's parameters. The snippet will get rendered at the position of the entity.geojson.geometry.coordinates (this is for Point features).

MapEntityProvider Component (Point Geometry)
<MapEntityLayerProvider layer_name="Example Layer">
<MapEntityProvider kind={"example"}>
{#snippet children(entity: Gis.MapEntity<{example_property: string}>)}
{#if entity.geojson.type === "Feature"}
<div class="p-4 bg-red-500">{entity.geojson.properties.example_property}</div>
{/if}
{/snippet}
</MapEntityProvider>
</MapEntityLayerProvider>

For lines, polygons etc. (shapes more complex than points) "geom" information needs to be specified for the renderer.

MapEntityProvider Component (Polygon Geometry)
<MapEntityLayerProvider layer_name="Airport">
<MapEntityProvider
kind={"airport"}
geom_style={{
fill: "#999999",
"fill-opacity": 0.5,
stroke: "#FF0000",
"stroke-opacity": 1,
}}
on_geom_click={(map_entity: Gis.MapEntity<Record<string, unknown>>) => {
if (!map_entity.set_entity_style) {
return;
}

map_entity.set_entity_style({
fill: `rgb(${Math.floor(Math.random() * 255)} ${Math.floor(Math.random() * 255)} ${Math.floor(
Math.random() * 255
)})`,
"fill-opacity": 0.5,
stroke: "#FF0000",
"stroke-opacity": 1,
});
}}
on_geom_hover={(map_entity: Gis.MapEntity<Record<string, unknown>>) => {
if (!map_entity.set_entity_style) {
return;
}

map_entity.set_entity_style({
fill: `rgb(${Math.floor(Math.random() * 255)} ${Math.floor(Math.random() * 255)} ${Math.floor(
Math.random() * 255
)})`,
"fill-opacity": 0.5,
stroke: "#FF0000",
"stroke-opacity": 1,
});
}}
></MapEntityProvider>
</MapEntityLayerProvider>

MapLayerManager Component

The MapLayerManager is a prebuilt UI component that adds map layer controls as a UI overlay.

It expects to be passed a child snippet which will be used as the button to open the manager. The following example shows the child snippet with a <Button> component:

Example
<MapLayerManager>
<Button>Layers</Button>
</MapLayerManager>
MapLayerManager UI

MapBookmarkManager Component

The MapBookmarkManager is a prebuilt UI component that adds controls to add and delete bookmarks.

It expects to be passed a child snippet which will be used as the button to open the manager. It also expects an array of Gis.MapBookmarks to render on initialization.

The following example shows the child snippet with a <Button> component:

Example
<MapBookmarkManager {bookmarks}>
<Button>Bookmarks</Button>
</MapBookmarkManager>
MapBookmarkManager UI

Example Page

A full example page, complete with server functions in use is installed by default as an example at:

  • src/routes/(private)/aoh/gis/+page.server.ts
  • src/routes/(private)/aoh/gis/+page.svelte