@delta10/atlas-sdk
v0.2.2
Published
A Vue 3 component library for interactive map visualization using OpenLayers, featuring support for multiple layer types (WMTS, WMS, Vector) and various map interactions.
Readme
Zaanstad Atlas SDK
A Vue 3 component library for interactive map visualization using OpenLayers, featuring support for multiple layer types (WMTS, WMS, Vector) and various map interactions.
Installation
npm install @delta10/atlas-sdkQuick Start
Basic Usage
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { Map } from '@delta10/atlas-sdk'
import '@delta10/atlas-sdk/style.css'
import type { LayerConfig, InteractionsConfig } from '@delta10/atlas-sdk'
const layers: LayerConfig[] = [
{
type: 'vector',
options: {
identifier: 'meetbouten',
title: 'Meetbouten',
features: [
{
type: 'Point',
coordinates: [120000, 487000],
properties: {
id: '123482',
geplaatst: false
}
}
],
style: {
'circle-radius': 8,
'circle-fill-color': 'rgba(173, 216, 230, 0.6)',
'circle-stroke-color': 'blue',
'circle-stroke-width': 3,
}
}
}
]
const baseLayers: LayerConfig[] = [
{
type: 'wmts',
options: {
identifier: 'referentiekaart',
title: 'Referentiekaart',
url: 'https://tiles.zaanstad.nl/mapproxy/service?REQUEST=GetCapabilities&service=wmts'
}
}
]
const toggleableLayers: LayerConfig[] = [
{
type: 'wms',
options: {
identifier: 'bag-pand-bouwjaar',
title: 'BAG Pand Bouwjaar',
url: 'https://maps.zaanstad.nl/geoserver/wms',
layer: 'geo:bag_pand_bouwjaar'
}
}
]
const interactions: InteractionsConfig = {
selectable: {
enabled: true,
layers: ['meetbouten'],
hitTolerance: 20,
style: {
'circle-radius': 8,
'circle-fill-color': 'red',
'circle-stroke-color': 'darkred',
'circle-stroke-width': 2,
}
}
}
const mapRef = ref()
const onFeatureSelected = (event: any) => {
console.log('Features selected:', event.selected)
}
const onFeatureModified = (event: any) => {
console.log('Features modified:', event.features)
}
const onModifyCancelled = (event: any) => {
console.log('Modification cancelled:', event.features)
}
const onMapClicked = (event: any) => {
console.log('Map clicked:', event.coordinate, event.pixel)
}
</script>
<template>
<div style="width: 100%; height: 500px;">
<Map
ref="mapRef"
:layers="layers"
:toggleableLayers="toggleableLayers"
:baseLayers="baseLayers"
:interactions="interactions"
@featureSelected="onFeatureSelected"
@featureModified="onFeatureModified"
@modifyCancelled="onModifyCancelled"
@mapClicked="onMapClicked"
/>
</div>
</template>Map Component
The Map component is the main component of the SDK, providing an interactive map with support for multiple layer types and interactions.
Props
layersLayerConfig[]- Array of regular layers to displaybaseLayersLayerConfig[]- Array of base layers (only one can be active)toggleableLayersLayerConfig[]- Array of toggleable layers (users can show/hide)interactionsInteractionsConfig- Configuration for map interactions (select, modify, snap)zoomnumber(default:10) - Initial zoom levelcenter[number, number](default:[120000, 487000]) - Initial center coordinates
Events
@featureSelected- Emitted when features are selected. Payload:{ selected: Feature[] }@featureModified- Emitted when features are modified. Payload:{ features: Feature[] }@modifyCancelled- Emitted when a pending modification is cancelled. Payload:{ features: Feature[] }@mapClicked- Emitted when the map is clicked. Payload:{ coordinate: [number, number]; pixel: [number, number] }
Methods
fitToFeatures(features)- Fit the map view to include all specified features with appropriate padding
Basic usage:
mapRef.value.fitToFeatures([
{
type: 'Polygon',
coordinates: [[[x1, y1], [x2, y2], ...]]
},
{
type: 'Point',
coordinates: [x, y]
}
])Complete example in a Vue component:
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { Map } from '@delta10/atlas-sdk'
import type { LayerConfig } from '@delta10/atlas-sdk'
const mapRef = ref()
const features = [/* your features */]
const layers: LayerConfig[] = [
{
type: 'vector',
options: {
identifier: 'panden',
title: 'Panden',
features: features,
style: {
'fill-color': 'rgba(173, 216, 230, 0.6)',
'stroke-color': 'blue',
'stroke-width': 2
}
}
}
]
// Fit map to features on component mount
onMounted(() => {
if (mapRef.value) {
mapRef.value.fitToFeatures(features)
}
})
</script>
<template>
<Map ref="mapRef" :layers="layers" />
</template>Layer Configuration
Vector Layer with Polygon
{
type: 'vector',
options: {
identifier: 'panden',
title: 'Panden',
features: [
{
type: 'Polygon',
coordinates: [[
[116044.07, 495387.61],
[116036.43, 495385.83],
[116041.45, 495365.34],
[116048.78, 495366.99],
[116044.07, 495387.61]
]]
}
],
style: {
'fill-color': 'rgba(173, 216, 230, 0.6)',
'stroke-color': 'blue',
'stroke-width': 2
}
}
}Vector Layer with Points
{
type: 'vector',
options: {
identifier: 'meetbouten',
title: 'Meetbouten',
features: [
{
type: 'Point',
coordinates: [120000, 487000],
properties: {
id: '123482',
geplaatst: false
}
}
],
style: {
'circle-radius': 8,
'circle-fill-color': 'rgba(173, 216, 230, 0.6)',
'circle-stroke-color': 'blue',
'circle-stroke-width': 3
}
}
}WMTS Layer
{
type: 'wmts',
options: {
identifier: 'referentiekaart',
title: 'Referentiekaart',
url: 'https://tiles.zaanstad.nl/mapproxy/service?REQUEST=GetCapabilities&service=wmts',
format: 'image/png' // optional, defaults to image/png
}
}WMS Layer
{
type: 'wms',
options: {
identifier: 'bag-pand-bouwjaar',
title: 'BAG Pand Bouwjaar',
url: 'https://maps.zaanstad.nl/geoserver/wms',
layer: 'geo:bag_pand_bouwjaar'
}
}Styling
Static Styles
Vector layers support flat style properties:
fill-color- Fill color (e.g., 'rgba(255, 0, 0, 0.5)')stroke-color- Stroke color (e.g., 'blue')stroke-width- Stroke width in pixelscircle-radius- Circle radius in pixelscircle-fill-color- Circle fill colorcircle-stroke-color- Circle stroke colorcircle-stroke-width- Circle stroke width
Conditional Styles
You can create dynamic styles based on feature properties using flat style expressions with rules. Use OpenLayers expressions to conditionally set colors and other properties.
Using Flat Style Expressions (Recommended)
{
type: 'vector',
options: {
identifier: 'meetbouten',
title: 'Meetbouten',
features: meetboutenFeatures,
style: {
'circle-radius': 8,
'circle-fill-color': ['case', ['==', ['get', 'geplaatst'], true], 'blue', 'lightblue'],
'circle-stroke-color': 'blue',
'circle-stroke-width': 3,
}
}
}This example checks if the geplaatst property equals true:
- If true: circle fill color is
blue - If false: circle fill color is
lightblue
Supported expression operators:
'get'- Read a feature property'case'- Choose a value based on conditions'=='- Equal to'coalesce'- Use the first non-null value
OpenLayers Style Functions
For more control, vector layers can also use an OpenLayers style function. This is useful for resolution-dependent styling, feature labels, or logic that is easier to express in TypeScript:
import { Style, Stroke, Fill, Circle as CircleStyle, Text } from 'ol/style'
{
type: 'vector',
options: {
identifier: 'meetbouten',
title: 'Meetbouten',
features: meetboutenFeatures,
styleFunction: (feature, _currentStyle, resolution) => {
if (resolution > 0.2) {
return []
}
const properties = feature.getProperties()
const isGeplaatst = properties.geplaatst === true
const featureId = properties.id || ''
return [new Style({
image: new CircleStyle({
radius: 20,
fill: new Fill({ color: 'white' }),
stroke: new Stroke({
color: isGeplaatst ? 'green' : 'red',
width: 2
})
}),
text: featureId ? new Text({
text: String(featureId),
fill: new Fill({ color: '#000' }),
stroke: new Stroke({ color: '#fff', width: 2 })
}) : undefined
})]
}
}
}Returning an empty array hides the feature for that render pass.
Interactions Configuration
Select Interaction
Allow users to select features from specific layers:
{
selectable: {
enabled: true,
layers: ['meetbouten'],
hitTolerance: 20,
style: {
'circle-radius': 8,
'circle-fill-color': 'red',
'circle-stroke-color': 'darkred',
'circle-stroke-width': 2
}
}
}Modify Interaction
Allow users to edit existing geometries directly on the configured layer:
{
modify: {
enabled: true,
layer: 'meetbouten',
labelProperty: 'meetboutnummer', // Optional: feature property shown in the confirm/cancel overlay
pixelTolerance: 20, // Optional: edit tolerance in pixels for point symbols
filter: (feature) => feature.get('editable') === true // Optional: return false to prevent editing
}
}The labelProperty value is read from the modified feature's properties. For example, if a feature has properties: { id: '123482' }, use labelProperty: 'id' to show that value in the confirmation overlay.
The optional filter callback receives the OpenLayers feature and layer. Return false to skip that feature for editing.
Snap Interaction
Snap modified features to existing features:
{
snap: {
enabled: true,
targetLayer: 'panden',
pixelTolerance: 10 // Optional: distance in pixels where snap activates (default: 8)
}
}The pixelTolerance controls how close (in pixels) the cursor needs to be to snap to a feature. Adjust for your needs:
- Lower values (e.g., 5-8 pixels) - More precise snapping, requires cursor to be very close
- Higher values (e.g., 15-20 pixels) - Easier snapping, works from further away
Combined Interactions Example
const interactions: InteractionsConfig = {
selectable: {
enabled: true,
layers: ['meetbouten'],
style: {
'circle-radius': 8,
'circle-fill-color': 'red',
'circle-stroke-color': 'darkred',
'circle-stroke-width': 2
}
},
modify: {
enabled: true,
layer: 'meetbouten',
labelProperty: 'meetboutnummer'
},
snap: {
enabled: true,
targetLayer: 'panden'
}
}Reactive Data
Layer configuration can be reactive. Use computed when feature arrays are loaded or replaced after mount:
const pandenFeatures = ref<any[]>([])
const meetboutenFeatures = ref<any[]>([])
const layers = computed<LayerConfig[]>(() => [
{
type: 'vector',
options: {
identifier: 'panden',
title: 'Panden',
features: pandenFeatures.value
}
},
{
type: 'vector',
options: {
identifier: 'meetbouten',
title: 'Meetbouten',
features: meetboutenFeatures.value
}
}
])
onMounted(() => {
pandenFeatures.value = loadedPandenFeatures
meetboutenFeatures.value = loadedMeetboutenFeatures
mapRef.value?.fitToFeatures(loadedPandenFeatures)
})Development
Install dependencies
npm installRun development server
npm run devBuild library
npm run build:libPreview production build
npm run previewProject Structure
src/components/Map.vue- Main Map componentsrc/components/panels/- UI panels for layer and base layer controlssrc/utils/projections.ts- Projection definitions (EPSG:28992)src/index.ts- Library entry pointdist/- Built library files (generated)
License
EUPL-1.2
