diff --git a/package-lock.json b/package-lock.json
index b24cf074..db52e017 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -10,7 +10,7 @@
"dependencies": {
"@heroicons/vue": "^2.0.11",
"@pinia/testing": "^0.0.14",
- "@vcmap/core": "^5.0.0-rc.23",
+ "@vcmap/core": "git://git@github.com/virtualcitySYSTEMS/map-core.git",
"ol": "^7.1.0",
"pinia": "^2.0.21",
"rollup-plugin-strip-pragma": "^1.0.0",
@@ -899,10 +899,10 @@
}
},
"node_modules/@vcmap/core": {
- "version": "5.0.0-rc.23",
- "resolved": "https://registry.npmjs.org/@vcmap/core/-/core-5.0.0-rc.23.tgz",
- "integrity": "sha512-2tGAZ8xfvm+kqxdWdkTdOcref4k+zewSW6SsTGbf5uPhhKkGPMwqq2zpbumK/HnXLirQVPC+tkdWjPbRvOwL1w==",
+ "version": "5.0.0-rc.24",
+ "resolved": "git+https://git@github.com/virtualcitySYSTEMS/map-core.git#8a2499c53785f0c89fc283a38a2651dcea3e5c4f",
"hasInstallScript": true,
+ "license": "MIT",
"dependencies": {
"@types/rbush": "^3.0.0",
"@vcsuite/check": "^1.1.2",
@@ -9249,9 +9249,8 @@
}
},
"@vcmap/core": {
- "version": "5.0.0-rc.23",
- "resolved": "https://registry.npmjs.org/@vcmap/core/-/core-5.0.0-rc.23.tgz",
- "integrity": "sha512-2tGAZ8xfvm+kqxdWdkTdOcref4k+zewSW6SsTGbf5uPhhKkGPMwqq2zpbumK/HnXLirQVPC+tkdWjPbRvOwL1w==",
+ "version": "git+https://git@github.com/virtualcitySYSTEMS/map-core.git#8a2499c53785f0c89fc283a38a2651dcea3e5c4f",
+ "from": "@vcmap/core@git://git@github.com/virtualcitySYSTEMS/map-core.git",
"requires": {
"@types/rbush": "^3.0.0",
"@vcsuite/check": "^1.1.2",
diff --git a/package.json b/package.json
index 09d3638e..161789e3 100644
--- a/package.json
+++ b/package.json
@@ -29,7 +29,7 @@
"dependencies": {
"@heroicons/vue": "^2.0.11",
"@pinia/testing": "^0.0.14",
- "@vcmap/core": "^5.0.0-rc.23",
+ "@vcmap/core": "git://git@github.com/virtualcitySYSTEMS/map-core.git",
"ol": "^7.1.0",
"pinia": "^2.0.21",
"rollup-plugin-strip-pragma": "^1.0.0",
diff --git a/src/components/map/MapComponent.vue b/src/components/map/MapComponent.vue
index bef50e6c..daf6ccef 100644
--- a/src/components/map/MapComponent.vue
+++ b/src/components/map/MapComponent.vue
@@ -1,17 +1,22 @@
diff --git a/src/interactions/selectStation.ts b/src/interactions/selectStation.ts
new file mode 100644
index 00000000..a0677893
--- /dev/null
+++ b/src/interactions/selectStation.ts
@@ -0,0 +1,155 @@
+import {
+ AbstractInteraction,
+ vcsLayerName,
+ EventType,
+ ModificationKeyType,
+ VectorLayer,
+ type InteractionEvent,
+ type VcsApp,
+ ArcStyle,
+ GeoJSONLayer,
+ markVolatile,
+ mercatorProjection,
+} from '@vcmap/core'
+import { useStationsStore } from '@/stores/stations'
+import { Feature } from 'ol'
+import { type Point, LineString } from 'ol/geom'
+import type { StationsModel } from '@/model/stations.model'
+import { DeclarativeStyleItem } from '@vcmap/core'
+
+class SelectStationInteraction extends AbstractInteraction {
+ private readonly _stationsLayerName: string
+
+ constructor(stationsLayerName: string) {
+ super(EventType.CLICKMOVE, ModificationKeyType.NONE)
+
+ this._stationsLayerName = stationsLayerName
+ }
+
+ async pipe(event: InteractionEvent): Promise {
+ const isLayerFeature =
+ event.feature?.[vcsLayerName] === this._stationsLayerName
+
+ if (event.type & EventType.CLICK) {
+ const store = useStationsStore()
+ if (event.feature && isLayerFeature) {
+ store.selectStation(event.feature as Feature)
+ } else if (store.selectedStation) {
+ store.selectStation()
+ }
+ } else if (isLayerFeature) {
+ document.body.style.cursor = 'pointer'
+ } else {
+ document.body.style.cursor = 'auto'
+ }
+
+ return event
+ }
+}
+
+export default SelectStationInteraction
+
+const scratchPoiLayerName = '_poiScracthLayer'
+
+const scratchArcLayerName = '_poiArcLayer'
+
+const stationToPoi: Map]> = new Map()
+
+function getPoisForStation(
+ stationId: number,
+ vcsApp: VcsApp
+): [Feature] | [] {
+ if (stationToPoi.size === 0) {
+ const stationsLayer = vcsApp.layers.getByKey('trambusStops') as GeoJSONLayer
+ const poiLayer = vcsApp.layers.getByKey('poi') as GeoJSONLayer
+ const source = stationsLayer.getSource()
+ const features = poiLayer.getFeatures() as [Feature]
+ features.map((poiFeature) => {
+ const geom = poiFeature.getGeometry() as Point
+ const station = source.getClosestFeatureToCoordinate(
+ geom.getCoordinates()
+ )
+
+ const stationId = station.get('id') as number
+ if (!stationToPoi.has(stationId)) {
+ stationToPoi.set(stationId, [poiFeature])
+ } else {
+ const featuresArray = stationToPoi.get(stationId) as [Feature]
+ featuresArray.push(poiFeature)
+ }
+ })
+ }
+ return stationToPoi.get(stationId) ?? []
+}
+
+function getScratchLayer(
+ app: VcsApp,
+ layerName: string,
+ arc?: boolean
+): VectorLayer {
+ if (app.layers.hasKey(layerName)) {
+ return app.layers.getByKey(layerName) as VectorLayer
+ }
+
+ const layer = new VectorLayer({
+ name: layerName,
+ projection: mercatorProjection.toJSON(),
+ })
+ if (arc) {
+ layer.setStyle(new ArcStyle())
+ } else {
+ layer.setStyle(
+ new DeclarativeStyleItem({
+ declarativeStyle: {
+ pointOutlineColor: "color('#6B23C9')",
+ pointOutlineWidth: '2',
+ labelText: {
+ conditions: [
+ ['${ordre}===1', "'${nom_site}'"],
+ ['true', "''"],
+ ],
+ },
+ labelOutlineColor: "color('#ffffff')",
+ labelColor: "color('#6B23C9')",
+ labelOutlineWidth: '2',
+ font: "'13px sans-serif'",
+ },
+ })
+ )
+ }
+ markVolatile(layer)
+ app.layers.add(layer)
+ layer.activate()
+ return layer
+}
+
+export async function explodeStationPOIs(
+ app: VcsApp,
+ poiLayerName: string,
+ station?: StationsModel | null
+): Promise {
+ const poiScratchLayer = getScratchLayer(app, scratchPoiLayerName)
+ const arcLayer = getScratchLayer(app, scratchArcLayerName, true)
+ poiScratchLayer.removeAllFeatures()
+ arcLayer.removeAllFeatures()
+ if (station) {
+ const poiLayer = app.layers.getByKey(poiLayerName) as GeoJSONLayer
+ if (poiLayer) {
+ await poiLayer.fetchData()
+ const features = getPoisForStation(station.id, app)
+ // TODO drape onto terrain
+ poiScratchLayer.addFeatures(features)
+ const arcFeatures = features.map((f) => {
+ const geometry = f.getGeometry() as Point
+ const lineString = new LineString([
+ station.position,
+ geometry.getCoordinates(),
+ ])
+ return new Feature(lineString)
+ })
+ arcLayer.addFeatures(arcFeatures)
+ } else {
+ console.warn(`Could not find POI layer with name: ${poiLayerName}`)
+ }
+ }
+}
diff --git a/src/map.config.json b/src/map.config.json
index d0a66d3d..79a53657 100644
--- a/src/map.config.json
+++ b/src/map.config.json
@@ -164,7 +164,20 @@
}
}
},
- "activeOnStartup": false
+ "vectorProperties": {
+ "primitiveOptions": {
+ "type": "ellipsoid",
+ "geometryOptions": {
+ "radii": [5, 5, 5],
+ "innerRadii": [0.000001, 0.000001, 0.000001],
+ "minimumCone": 1.54,
+ "maximumCone": 1.58
+ },
+ "offset": [0, 0, 0.1]
+ },
+ "modelAutoScale": true
+ },
+ "activeOnStartup": true
},
{
"name": "parking",
@@ -184,7 +197,7 @@
"name": "poi",
"url": "https://gist.githubusercontent.com/ismailsunni/561f39f97f8e1a36491207a61224270c/raw/bb7ddd1c233760fb3cf8ce562f8a3302846ade57/POI.geojson",
"type": "GeoJSONLayer",
- "activeOnStartup": true,
+ "activeOnStartup": false,
"style": {
"name": "poiStyle",
"type": "DeclarativeStyleItem",
diff --git a/src/model/stations.model.ts b/src/model/stations.model.ts
new file mode 100644
index 00000000..be59e93c
--- /dev/null
+++ b/src/model/stations.model.ts
@@ -0,0 +1,48 @@
+import type { LineNumber } from '@/model/lines.model'
+import type { Feature } from 'ol'
+import type { Point } from 'ol/geom'
+import type { Coordinate } from 'ol/coordinate'
+
+export interface StationsModel {
+ id: number
+ version: string
+ trace_type: string // FIXME this is probably an enum
+ li_code: LineNumber
+ nom: string
+ position: Coordinate
+}
+
+function lineCodeFromString(stringLineCode: string): LineNumber {
+ if (stringLineCode === 'T1') {
+ return 1
+ }
+
+ if (stringLineCode === 'T2') {
+ return 2
+ }
+
+ if (stringLineCode === 'T3') {
+ return 3
+ }
+
+ return 4
+}
+
+export function getStationModelFromFeature(
+ feature: Feature
+): StationsModel {
+ const properties = feature.getProperties()
+ const geometry = feature.getGeometry()
+ if (!geometry) {
+ throw new Error('Cannot set station from a Feature without a geometry')
+ }
+
+ return {
+ id: properties.id,
+ version: properties.version,
+ trace_type: properties.trace_type,
+ li_code: lineCodeFromString(properties.li_code),
+ nom: properties.nom,
+ position: geometry.getCoordinates(),
+ }
+}
diff --git a/src/stores/stations.ts b/src/stores/stations.ts
new file mode 100644
index 00000000..ec9e3a28
--- /dev/null
+++ b/src/stores/stations.ts
@@ -0,0 +1,21 @@
+import { ref } from 'vue'
+import type { Ref } from 'vue'
+import { defineStore } from 'pinia'
+import type { Feature } from 'ol'
+import type { Point } from 'ol/geom'
+import {
+ type StationsModel,
+ getStationModelFromFeature,
+} from '@/model/stations.model'
+
+export const useStationsStore = defineStore('stores', () => {
+ const selectedStation: Ref = ref(null)
+
+ function selectStation(stationFeature?: Feature) {
+ selectedStation.value = stationFeature
+ ? getStationModelFromFeature(stationFeature)
+ : null
+ }
+
+ return { selectStation, selectedStation }
+})