@@ -183,6 +183,17 @@ const map = new ol.Map({
183
183
]
184
184
} ) ;
185
185
186
+ // Load events data
187
+ let eventsData = [ ] ;
188
+ fetch ( 'data/revels_events.json' )
189
+ . then ( response => response . json ( ) )
190
+ . then ( data => {
191
+ if ( data . ok ) {
192
+ eventsData = data . data ;
193
+ }
194
+ } )
195
+ . catch ( error => console . error ( 'Error loading events:' , error ) ) ;
196
+
186
197
// Vector Sources Array and Layers Object
187
198
const vectorSources = [ ] ;
188
199
const layers = { } ;
@@ -241,6 +252,85 @@ Object.entries(layerConfigs).forEach(([id, config]) => {
241
252
addGeoJSONLayer ( config . url , config . style , id ) ;
242
253
} ) ;
243
254
255
+ // Add location pointer for "MIT Ground"
256
+ const sportsSource = layers . sports . getSource ( ) ;
257
+ sportsSource . once ( 'change' , function ( ) {
258
+ if ( sportsSource . getState ( ) === 'ready' ) {
259
+ const mitGround = sportsSource . getFeatures ( ) . find ( feature =>
260
+ feature . get ( 'Sports' ) === 'MIT Ground'
261
+ ) ;
262
+ if ( mitGround ) {
263
+ const geometry = mitGround . getGeometry ( ) ;
264
+ const centroid = ol . extent . getCenter ( geometry . getExtent ( ) ) ;
265
+
266
+ const pointer = new ol . Feature ( {
267
+ geometry : new ol . geom . Point ( centroid ) ,
268
+ } ) ;
269
+ pointer . setStyle ( new ol . style . Style ( {
270
+ image : new ol . style . Icon ( {
271
+ src : 'https://cdn-icons-png.flaticon.com/512/684/684908.png' , // Free pin icon
272
+ scale : 0.05 , // Adjust size as needed
273
+ anchor : [ 0.5 , 1 ] , // Bottom-center of the pin
274
+ } ) ,
275
+ } ) ) ;
276
+
277
+ pointerSource . addFeature ( pointer ) ;
278
+ }
279
+ }
280
+ } ) ;
281
+ // Add pointers for additional event locations
282
+ const additionalLocations = [
283
+ { layerId : 'shops' , property : 'Shops' , value : 'Student Plaza' } ,
284
+ { layerId : 'academic' , property : 'Name' , value : 'AB1' } ,
285
+ { layerId : 'academic' , property : 'Name' , value : 'AB2' } ,
286
+ { layerId : 'academic' , property : 'Name' , value : 'AB3' } ,
287
+ { layerId : 'academic' , property : 'Name' , value : 'AB5' } ,
288
+ { layerId : 'academic' , property : 'Name' , value : 'Library' } ,
289
+ { layerId : 'academic' , property : 'Name' , value : 'KEF R&D Centre' } ,
290
+ ] ;
291
+
292
+ additionalLocations . forEach ( location => {
293
+ const source = layers [ location . layerId ] . getSource ( ) ;
294
+ source . once ( 'change' , function ( ) {
295
+ if ( source . getState ( ) === 'ready' ) {
296
+ const feature = source . getFeatures ( ) . find ( f =>
297
+ f . get ( location . property ) === location . value
298
+ ) ;
299
+ if ( feature ) {
300
+ const geometry = feature . getGeometry ( ) ;
301
+ const centroid = ol . extent . getCenter ( geometry . getExtent ( ) ) ;
302
+ const pointer = new ol . Feature ( {
303
+ geometry : new ol . geom . Point ( centroid ) ,
304
+ name : location . value , // Store for reference
305
+ } ) ;
306
+ pointer . setStyle ( new ol . style . Style ( {
307
+ image : new ol . style . Icon ( {
308
+ src : 'https://cdn-icons-png.flaticon.com/512/684/684908.png' ,
309
+ scale : 0.05 ,
310
+ anchor : [ 0.5 , 1 ] ,
311
+ } ) ,
312
+ } ) ) ;
313
+ pointerSource . addFeature ( pointer ) ;
314
+ }
315
+ }
316
+ } ) ;
317
+ } ) ;
318
+
319
+ // Click handler for pointers
320
+ map . on ( 'click' , function ( event ) {
321
+ const feature = map . forEachFeatureAtPixel ( event . pixel , function ( feat , layer ) {
322
+ return layer === pointerLayer ? feat : null ; // Only detect pointerLayer features
323
+ } ) ;
324
+
325
+ if ( feature ) {
326
+ const locationName = feature . get ( 'name' ) ;
327
+ showEventsPopup ( locationName ) ;
328
+ } else {
329
+ const popup = document . getElementById ( 'eventsPopup' ) ;
330
+ popup . classList . remove ( 'active' ) ;
331
+ }
332
+ } ) ;
333
+
244
334
// User Position Tracking
245
335
let userPositionSource = new ol . source . Vector ( ) ;
246
336
let userPositionLayer = new ol . layer . Vector ( {
@@ -263,6 +353,14 @@ let userPositionLayer = new ol.layer.Vector({
263
353
// Add user position layer to map
264
354
map . addLayer ( userPositionLayer ) ;
265
355
356
+ // Pointer layer for event tracking
357
+ const pointerSource = new ol . source . Vector ( ) ;
358
+ const pointerLayer = new ol . layer . Vector ( {
359
+ source : pointerSource ,
360
+ zIndex : 1001 // Above other layers, including user position
361
+ } ) ;
362
+ map . addLayer ( pointerLayer ) ;
363
+
266
364
// User position tracking feature
267
365
let userPositionFeature = new ol . Feature ( ) ;
268
366
userPositionSource . addFeature ( userPositionFeature ) ;
@@ -667,3 +765,56 @@ setInterval(updateTime, 1000);
667
765
// Initialize Map
668
766
fitMapToFeatures ( ) ;
669
767
updateTime ( ) ;
768
+
769
+ // Show events popup
770
+ function showEventsPopup ( locationName ) {
771
+ const relevantEvents = eventsData . filter ( event =>
772
+ ( event . Name && event . Name === locationName ) ||
773
+ ( event . Shops && event . Shops === locationName ) ||
774
+ ( event . Sports && event . Sports === locationName )
775
+ ) ;
776
+
777
+ const popup = document . getElementById ( 'eventsPopup' ) ;
778
+ const content = document . getElementById ( 'eventsContent' ) ;
779
+
780
+ // Clear previous content
781
+ content . innerHTML = '' ;
782
+
783
+ // Build events list
784
+ content . innerHTML = `
785
+ <h2>Events at ${ locationName } </h2>
786
+ <ul class="events-list">
787
+ ${ relevantEvents . map ( event => `
788
+ <li class="event-item" onclick="showEventDetails('${ event . event_name . replace ( / ' / g, "\\'" ) } ', '${ locationName . replace ( / ' / g, "\\'" ) } ')">
789
+ <strong>${ event . event_name } </strong><br>
790
+ ${ new Date ( event . event_date ) . toLocaleDateString ( ) } ${ event . event_time }
791
+ </li>
792
+ ` ) . join ( '' ) }
793
+ </ul>
794
+ ` ;
795
+
796
+ popup . classList . add ( 'active' ) ;
797
+ }
798
+
799
+ // Show event details
800
+ function showEventDetails ( eventName , locationName ) {
801
+ const event = eventsData . find ( e =>
802
+ e . event_name === eventName && (
803
+ ( e . Name && e . Name === locationName ) ||
804
+ ( e . Shops && e . Shops === locationName ) ||
805
+ ( e . Sports && e . Sports === locationName )
806
+ )
807
+ ) ;
808
+
809
+ const content = document . getElementById ( 'eventsContent' ) ;
810
+ content . innerHTML = `
811
+ <h2>${ event . event_name } </h2>
812
+ <p><strong>Type:</strong> ${ event . event_type } </p>
813
+ <p><strong>Description:</strong> ${ event . event_desc . replace ( / \n / g, '<br>' ) } </p>
814
+ <p><strong>Date:</strong> ${ new Date ( event . event_date ) . toLocaleDateString ( ) } </p>
815
+ <p><strong>Time:</strong> ${ event . event_time } </p>
816
+ <p><strong>Venue:</strong> ${ event . venue_name } </p>
817
+ <p><strong>Team Type:</strong> ${ event . team_type } </p>
818
+ <button onclick="showEventsPopup('${ locationName . replace ( / ' / g, "\\'" ) } ')">Back to Events</button>
819
+ ` ;
820
+ }
0 commit comments