The map
API gives you access to Qatium’s map environment, enabling you to create custom visualizations, move the camera, highlight assets, and more.
Map Queries
getCamera()
Returns the current state of the map camera.
Method signature
Returns
An object containing:
zoom: number
Zoom level
pitch: number
Angle towards the horizon measured in degrees with a range between 0 and 85
bearing: number
The direction the camera is facing, measured clockwise as an angle from true north on a compass. This can also be called a heading. In Qatium, north is 0°, east is 90°, south is 180°, and west is 270°
center: {lng: number, lat: number}
The longitude and latitude at which the camera is pointed
getSelectedElement()
Returns a SelectedElement
object representing the currently selected element in the map, or undefined
if nothing is selected. The SelectedElement
object contains the element ID and the type of element.
Example
const selectedElement = sdk . map . getSelectedElement ()
selectedElement . id // The element ID
selectedElement . type // Type in "Pipe", "Junction", "Valve", "Pump", "SupplySource" or "Tank"
selected_element = sdk.map. get_selected_element ()
selected_element.id # The element ID
selected_element.type # Type in "Pipe", "Junction", "Valve", "Pump", "SupplySource", "Tank", or "Zone"
Map Actions
setHighlights()
Highlights the network elements passed as parameters (assets or zones) in elementIds
(an array of element IDs). If the elementIds
array is empty, all highlights are cleared (equivalent to using clearHighlights()
).
Method signature
setHighlights (elementIds: string[]): void ;
def set_highlights ( element_ids : List[ str ] ) -> None :
Parameters
elementIds: string[]
: An array of asset / zone IDs to be highlighted
Example
Highlights two tanks in Magnetic Island:
sdk . map . setHighlights ([ ' Nellybay ' , ' Horseshoebay ' ]);
sdk.map. set_highlights ( [ ' Nellybay ' , ' Horseshoebay ' ] )
clearHighlights()
Clears all the highlights in the map.
Method signature
def clear_highlights () -> None :
fitTo()
Centers the map viewport, while fitting a set of destination network elements or bounds, using the animation options set in the optional options
parameter.
Method signature
fitTo (boundsOrIds: ElementId[] | Bounds, options ?: FlightOptions): Promise < void > ;
async def fit_to ( bounds_or_ids : Union[List[ElementId], Bounds], options : FlightOptions = None ) -> None :
Parameters
boundsOrIds: ElementId[] | Bounds
: Accepts an asset / zone ID or bounds as destination.
options: FlightOptions
(Optional) : Options object that accepts:
padding: Bounds
: (Optional) Dimensions in pixels applied on each side of the viewport for shifting the vanishing point
flightDuration: number
: (Optional) The animation’s duration, measured in milliseconds
maxZoom: number
: (Optional) The max level of zoom allowed to perform the action
Returns
A promise with no value, resolved when the camera movement has finished.
Example
Center the map to the Horseshoebay tank, using a slow animation (5 seconds), with a padding of 100 pixels on each side:
sdk . map . fitTo ([ ' Horseshoebay ' ], {
padding: { top: 100 , right: 100 , bottom: 100 , left: 100 }
await sdk.map. fit_to ( [ ' Horseshoebay ' ], {
' padding ' : { ' top ' : 100 , ' right ' : 100 , ' bottom ' : 100 , ' left ' : 100 }
Fit a collection of assets in the viewport:
sdk . map . fitTo ([ ' Horseshoebay ' , ' Nellybay ' , ' Cocklebay ' ], {
padding: { top: 300 , right: 300 , bottom: 300 , left: 300 }
await sdk.map. fit_to ( [ ' Horseshoebay ' , ' Nellybay ' , ' Cocklebay ' ], {
' padding ' : { ' top ' : 300 , ' right ' : 300 , ' bottom ' : 300 , ' left ' : 300 }
Fitting to bounds:
sdk . map . fitTo ({ top: 100 , right: 100 , bottom: 100 , left: 100 });
await sdk.map. fit_to ( { ' top ' : 100 , ' right ' : 100 , ' bottom ' : 100 , ' left ' : 100 } )
moveTo()
Method signature
Transitions the camera view, following a set of travel options.
moveTo (options: CameraOptions): Promise < void > ;
async def move_to ( options : CameraOptions ) -> None :
Parameters
options: CameraOptions
: Transition object that accepts:
zoom: number
: (Optional) Target zoom level
pitch: number
: (Optional) Angle towards the horizon measured in degrees with a range between 0 and 85
transitionDuration: number
: (Optional) The animation’s duration, measured in milliseconds
latitude: number
: (Optional) Geographic latitude in decimal degrees format, ranging from -90 to 90
longitude: number
: (Optional) Geographic longitude in decimal degrees format, ranging from -180 to 180
bearing: number
: (Optional) The direction the camera is facing, measured clockwise as an angle from true north on a compass. In Qatium, north is 0°, east is 90°, south is 180°, and west is 270°
padding: Padding
: (Optional) Dimensions in pixels applied on each side of the viewport for shifting the vanishing point
Returns
A promise with no value, resolved when the camera movement has finished.
Example
Move the camera to Mandalay in Magnetic Island, AU:
sdk . map . moveTo ({ latitude: - 19.157 , longitude: 146.849 });
await sdk.map. move_to ( { ' latitude ' : - 19.157 , ' longitude ' : 146.849 } )
Do a tilted camera travel to the same location:
transitionDuration: 2000 ,
' transitionDuration ' : 2000 ,
Animate the camera and rotate around the viewpoint:
transitionDuration: 2000 ,
await sdk . map . moveTo ({ transitionDuration: 3000 , bearing: 90 });
await sdk . map . moveTo ({ transitionDuration: 3000 , bearing: 180 });
await sdk . map . moveTo ({ transitionDuration: 3000 , bearing: 270 });
await sdk . map . moveTo ({ transitionDuration: 3000 , bearing: 0 });
' transitionDuration ' : 2000 ,
await sdk.map. move_to ( { ' transitionDuration ' : 3000 , ' bearing ' : 90 } )
await sdk.map. move_to ( { ' transitionDuration ' : 3000 , ' bearing ' : 180 } )
await sdk.map. move_to ( { ' transitionDuration ' : 3000 , ' bearing ' : 270 } )
await sdk.map. move_to ( { ' transitionDuration ' : 3000 , ' bearing ' : 0 } )
addOverlay()
Adds a custom visual overlay on top of the map.
Caution
At the moment our map overlays are using DeckGL and the content added might not be fully in sync with the map below.
Also be aware you’ll only be able to declare a single overlay. Any subsequent calls to this method will overwrite the previous overlay.
Method signature
addOverlay (layers: Layer[]): void ;
def add_overlay ( layers : List[Layer] ) -> None :
Parameters
layers: List[Layer]
: List of layer objects containing all data and styling, from any of the supported layer types.
Where Layer is:
type : ' ScatterplotLayer ' | ' PolygonLayer ' | ' IconLayer ' | ' HeatmapLayer ' , // ...
tooltip ?: GetTooltipData ,
// ... properties specific to the layer type
type : str # 'ScatterplotLayer' | 'PolygonLayer' | 'IconLayer' | 'HeatmapLayer'
tooltip: Optional[GetTooltipData] = None
popover: Optional[GetTooltipData] = None
You can associate a tooltip and/or a popover with your layer. To do that you need to provide the optional tooltip
and/or popover
properties. Ensure each data feature has an id
property for the tooltips and popovers to function correctly.
The main differences are that:
Popovers appear on click and are visible until they are closed or another popover is open.
Tooltips appear on hover and disappear on blur.
User can see 1 popover and 1 tooltip max at the same time.
Tooltips should be small and popovers may be a bit larger.
The property value must be a function that receives a MapItem
and returns TooltipData
.
export type GetTooltipData = ( mapItem : MapItem ) => TooltipData ;
coordinates ?: { lng : number ; lat : number };
export type TooltipData = {
icon : QatiumIcon | Base64Image ;
sections : TooltipSection [];
export type TooltipSection = TooltipProperty [];
coordinates: Optional[Dict[ str , float ]]
icon: Union[QatiumIcon, Base64Image]
sections: List[TooltipSection]
class TooltipSection (List[TooltipProperty]):
value: TooltipPropertyValue
unit: Optional[ str ] = None
reading: Optional[TooltipPropertyReading] = None
warning: Optional[TooltipPropertyWarning] = None
You can also return a Promise
for Section
, TooltipProperty
, TooltipProperty.value
, TooltipProperty.reading
, and TooltipProperty.warning
.
Examples
Highlight all hydrants in red:
const data = sdk . network . getJunctions ( ( j ) => j . group === JunctionGroups . Hydrant ) . map ( ( j ) => ( {
type: " ScatterplotLayer " ,
getPosition : ( d : Feature ) => d . geometry . coordinates ,
getFillColor: [ 255 , 0 , 0 ],
data = sdk.network. get_valves ( lambda *args : args [ 0 ] .family == ValveFamilies.TCV ). map ( lambda *args : {
' geometry ' : args [ 0 ] .geometry,
' status ' : args [ 0 ] .simulation.status
' type ' : " ScatterplotLayer " ,
' getPosition ' : lambda *args : args [ 0 ] [ " geometry " ] .coordinates,
' getFillColor ' : lambda *args : [ 0 , 255 , 0 ] if args [ 0 ] [ " properties " ][ " status " ] == AssetStatus.OPEN else [ 255 , 0 , 0 ] ,
' getLineColor ' : [ 0 , 0 , 0 ] ,
Hydrants mean pressure density with a heatmap:
const data = sdk . network . getJunctions ( ( j ) => j . group === JunctionGroups . Hydrant ) . map ( ( p ) => ( {
properties: { pressure: j . simulation . pressure }
getPosition : ( f ) => f . geometry . coordinates ,
getWeight : ( f ) => f . properties . pressure ,
data = sdk.network. get_junctions ( lambda *args : args [ 0 ] .group == JunctionGroups.Hydrant ). map ( lambda *args : {
' geometry ' : args [ 0 ] .geometry,
' properties ' : { ' pressure ' : args [ 0 ] .simulation.pressure }
' getPosition ' : lambda *args : args [ 0 ] [ " geometry " ] .coordinates,
' getWeight ' : lambda *args : args [ 0 ] [ " properties " ][ " pressure " ]
Arc layer showing source and target pressures at the connections of pipes:
const data = sdk . network . getPipes () . map ( ( p ) => ( {
sourcePressure: sdk . network . getNeighborAssets (p . id )[ 0 ] . simulation . pressure ,
targetPressure: sdk . network . getNeighborAssets (p . id )[ 1 ] . simulation . pressure
getSourcePosition : ( d ) => d . geometry . coordinates [ 0 ],
getTargetPosition : ( d ) => d . geometry . coordinates [d . geometry . coordinates . length - 1 ],
getSourceColor : ( f ) => [f . properties . sourcePressure * 2 , 0 , 255 , 255 ],
getTargetColor : ( f ) => [f . properties . targetPressure * 2 , 0 , 130 , 255 ],
data = sdk.network. get_pipes (). map ( lambda *args : {
' geometry ' : args [ 0 ] .geometry,
' sourcePressure ' : sdk.network. get_neighbor_assets ( args [ 0 ] .id ) [ 0 ] .simulation.pressure,
' targetPressure ' : sdk.network. get_neighbor_assets ( args [ 0 ] .id ) [ 1 ] .simulation.pressure
' getSourcePosition ' : lambda *args : args [ 0 ] [ " geometry " ] .coordinates [ 0 ] ,
' getTargetPosition ' : lambda *args : args [ 0 ] [ " geometry " ] .coordinates [ - 1 ] ,
' getSourceColor ' : lambda *args : [ args [ 0 ] [ " properties " ][ " sourcePressure " ] * 2 , 0 , 255 , 255 ] ,
' getTargetColor ' : lambda *args : [ args [ 0 ] [ " properties " ][ " targetPressure " ] * 2 , 0 , 130 , 255 ] ,
Show tank IDs on the map:
const data = sdk . network . getTanks () . map ( ( p ) => ( {
getPosition : ( f ) => f . geometry . coordinates ,
getText : ( f ) => f . properties . id ,
getColor : () => [ 255 , 255 , 255 , 255 ],
data = sdk.network. get_valves (). map ( lambda *args : {
' geometry ' : args [ 0 ] .geometry,
' properties ' : { ' id ' : args [ 0 ] .id }
' getPosition ' : lambda *args : args [ 0 ] [ " geometry " ] .coordinates,
' getText ' : lambda *args : args [ 0 ] [ " properties " ][ " id " ] ,
' getColor ' : [ 255 , 255 , 255 , 255 ] ,
Supported layers
You can refer to the DeckGL documentation to find a list of all available layers and how to declare them.
We support all available layer types except for BitmapLayer
and GeohashLayer
or custom layers.
For each layer, you’ll need to provide an object with a type
parameter with the name of the type of layer and all the relevant parameters for that specific type of layer.
showOverlay()
Forces all the layers in the overlay to be shown.
Method signature
def show_overlay () -> None :
hideOverlay()
Hides/removes all the layers of the overlay.
Method signature
def hide_overlay () -> None :
addStyles()
Allows you to change the styles of elements on the map.
Method signature
addStyles (styles: Styles): Success | Failure;
def add_styles ( styles : Styles ) -> Union[Success, Failure]:
Parameters
styles: Styles
: Styles object that needs:
assetId: string
: The asset ID.
Style properties:
isShadowVisible?: boolean
: Whether the feature halo is visible. Default: false
.
shadowColor?: string
: Color of the feature halo. Default: theme.colors.primary.light
. Accepted values are tied to Mapbox color specification .
outlineOpacity?: number
: Value used to show an outline around features. Default: 0
.
elementColor?: string
: Color of the line and fills of polygon features. Defaults to theme.colors.grey.250
for lines and rgba(0,0,0,0)
for fills. Accepted values are tied to <color> CSS data type .
iconId?: string
: Name of the icon to be used by the feature. Needs to be previously registered using registerIcon()
.
Example
Highlight all tanks in yellow:
removeStyles()
Allows you to delete the styles applied with the addStyles()
method.
Method signature
def remove_styles () -> None :
Example
registerIcon()
Registers an SVG icon to the map instance asynchronously. You must follow the icon guidelines to ensure consistency.
Method signature
registerIcon (id: string, svg: string): Promise < Success | Failure > ;
async def register_icon ( id : str , svg : str ) -> Union[Success, Failure]:
Example
Register a custom icon:
await sdk . map . registerIcon ( " open " , ` <svg width="44" height="44" viewBox="0 0 44 44" xmlns="http://www.w3.org/2000/svg">
t width="44" height="44" rx="10" fill="black" fill-opacity="0.3"/>
t x="2" y="2" width="40" height="40" rx="8" fill="#00C887"/>
h d="M15.6415 16.6349C15.6396 16.7361 15.6129 16.8339 15.5651 16.9144C15.5174 16.995 15.4511 17.0541 15.3757 17.0834C15.3003 17.1126 15.2196 17.1106 15.1451 17.0775C15.0707 17.0444 15.0063 16.9819 14.9611 16.899C14.6533 16.304 14.2555 15.7946 13.7913 15.4013C13.2079 14.9035 12.5232 14.638 11.8229 14.638C11.1226 14.638 10.4379 14.9035 9.85452 15.4013C9.38847 15.7956 8.98921 16.3069 8.68067 16.9043C8.63546 16.9872 8.57104 17.0497 8.49659 17.0828C8.42214 17.1159 8.34145 17.1179 8.26604 17.0886C8.19062 17.0594 8.12432 17.0003 8.07659 16.9197C8.02886 16.8392 8.00213 16.7413 8.00021 16.6401C7.99177 15.6618 8.24261 14.7088 8.7115 13.9379C9.08228 13.3338 9.5548 12.8457 10.0935 12.51C10.6322 12.1744 11.2232 12 11.8219 12C12.4206 12 13.0115 12.1744 13.5503 12.51C14.089 12.8457 14.5615 13.3338 14.9323 13.9379C15.3984 14.7085 15.6483 15.6589 15.6415 16.6349ZM35.9999 16.6349C35.9979 16.7361 35.9712 16.8339 35.9235 16.9144C35.8757 16.995 35.8094 17.0541 35.734 17.0834C35.6586 17.1126 35.5779 17.1106 35.5035 17.0775C35.429 17.0444 35.3646 16.9819 35.3194 16.899C35.0118 16.3047 34.6148 15.7955 34.1517 15.4013C33.568 14.9033 32.8829 14.6377 32.1823 14.6377C31.4816 14.6377 30.7966 14.9033 30.2129 15.4013C29.7468 15.7956 29.3476 16.3069 29.039 16.9043C28.9938 16.9872 28.9294 17.0497 28.8549 17.0828C28.7805 17.1159 28.6998 17.1179 28.6244 17.0886C28.549 17.0594 28.4827 17.0003 28.4349 16.9197C28.3872 16.8392 28.3605 16.7413 28.3585 16.6401C28.3501 15.6618 28.601 14.7088 29.0698 13.9379C29.4406 13.3338 29.9131 12.8457 30.4519 12.51C30.9906 12.1744 31.5815 12 32.1802 12C32.7789 12 33.3699 12.1744 33.9086 12.51C34.4473 12.8457 34.9198 13.3338 35.2906 13.9379C35.7567 14.7085 36.0066 15.6589 35.9999 16.6349Z" fill="#222230"/>
<svg width="44" height="44" viewBox="0 0 44 44" xmlns="http://www.w3.org/2000/svg">
<rect width="44" height="44" rx="10" fill="black" fill-opacity="0.3" />
<rect x="2" y="2" width="40" height="40" rx="8" fill="#00C887" />
d="M15.6415 16.6349C15.6396 16.7361 15.6129 16.8339 15.5651 16.9144C15.5174 16.995 15.4511 17.0541 15.3757 17.0834C15.3003 17.1126 15.2196 17.1106 15.1451 17.0775C15.0707 17.0444 15.0063 16.9819 14.9611 16.899C14.6533 16.304 14.2555 15.7946 13.7913 15.4013C13.2079 14.9035 12.5232 14.638 11.8229 14.638C11.1226 14.638 10.4379 14.9035 9.85452 15.4013C9.38847 15.7956 8.98921 16.3069 8.68067 16.9043C8.63546 16.9872 8.57104 17.0497 8.49659 17.0828C8.42214 17.1159 8.34145 17.1179 8.26604 17.0886C8.19062 17.0594 8.12432 17.0003 8.07659 16.9197C8.02886 16.8392 8.00213 16.7413 8.00021 16.6401C7.99177 15.6618 8.24261 14.7088 8.7115 13.9379C9.08228 13.3338 9.5548 12.8457 10.0935 12.51C10.6322 12.1744 11.2232 12 11.8219 12C12.4206 12 13.0115 12.1744 13.5503 12.51C14.089 12.8457 14.5615 13.3338 14.9323 13.9379C15.3984 14.7085 15.6483 15.6589 15.6415 16.6349ZM35.9999 16.6349C35.9979 16.7361 35.9712 16.8339 35.9235 16.9144C35.8757 16.995 35.8094 17.0541 35.734 17.0834C35.6586 17.1126 35.5779 17.1106 35.5035 17.0775C35.429 17.0444 35.3646 16.9819 35.3194 16.899C35.0118 16.3047 34.6148 15.7955 34.1517 15.4013C33.568 14.9033 32.8829 14.6377 32.1823 14.6377C31.4816 14.6377 30.7966 14.9033 30.2129 15.4013C29.7468 15.7956 29.3476 16.3069 29.039 16.9043C28.9938 16.9872 28.9294 17.0497 28.8549 17.0828C28.7805 17.1159 28.6998 17.1179 28.6244 17.0886C28.549 17.0594 28.4827 17.0003 28.4349 16.9197C28.3872 16.8392 28.3605 16.7413 28.3585 16.6401C28.3501 15.6618 28.601 14.7088 29.0698 13.9379C29.4406 13.3338 29.9131 12.8457 30.4519 12.51C30.9906 12.1744 31.5815 12 32.1802 12C32.7789 12 33.3699 12.1744 33.9086 12.51C34.4473 12.8457 34.9198 13.3338 35.2906 13.9379C35.7567 14.7085 36.0066 15.6589 35.9999 16.6349Z"
await sdk.map. register_icon ( " open " , svg )
updateIcon()
Allows you to change the icons of elements on the map. You need to first register the icon with registerIcon()
before assigning it to any element.
Method signature
updateIcon (elements: string[], iconId: string): Success | Failure;
def update_icon ( elements : List[ str ], icon_id : str ) -> Union[Success, Failure]:
Example
Change the icon of specific elements:
await sdk . map . updateIcon ([ ' Nellybay_PSV ' , ' Arcadia_DMA_PRV ' ], " open " );
await sdk.map. update_icon ( [ ' Nellybay_PSV ' , ' Arcadia_DMA_PRV ' ], " open " )