From 54092940434e27d26bf5d7dc03ee8450cc6fdb0e Mon Sep 17 00:00:00 2001 From: Sebastien Deleuze Date: Fri, 18 Mar 2016 01:06:36 +0100 Subject: [PATCH] Add messages layer + bring back SseBroadcaster --- .../spring/messenger/web/MessageController.kt | 13 ++++- .../io/spring/messenger/web/SseBroadcaster.kt | 25 +++++++++ src/main/resources/static/index.html | 2 + src/main/resources/static/map.js | 56 +++++++++++++++---- 4 files changed, 83 insertions(+), 13 deletions(-) create mode 100644 src/main/kotlin/io/spring/messenger/web/SseBroadcaster.kt diff --git a/src/main/kotlin/io/spring/messenger/web/MessageController.kt b/src/main/kotlin/io/spring/messenger/web/MessageController.kt index 1585a8d..90c7345 100644 --- a/src/main/kotlin/io/spring/messenger/web/MessageController.kt +++ b/src/main/kotlin/io/spring/messenger/web/MessageController.kt @@ -6,13 +6,19 @@ import org.postgis.PGbox2d import org.postgis.Point import org.springframework.beans.factory.annotation.Autowired import org.springframework.web.bind.annotation.* +import org.springframework.web.servlet.mvc.method.annotation.SseEmitter @RestController @RequestMapping("/message") class MessageController @Autowired constructor(val repository: MessageRepository) { + val broadcaster = SseBroadcaster() + @PostMapping - fun create(@RequestBody message: Message) = repository.create(message) + fun create(@RequestBody message: Message) { + repository.create(message) + broadcaster.send(message) + } @GetMapping fun findMessages() = repository.findAll() @@ -22,4 +28,7 @@ class MessageController @Autowired constructor(val repository: MessageRepository @PathVariable xMax:Double, @PathVariable yMax:Double) = repository.findByBoundingBox(PGbox2d(Point(xMin, yMin), Point(xMax, yMax))) - } \ No newline at end of file + @GetMapping("/subscribe") + fun subscribe(): SseEmitter = broadcaster.subscribe() + +} \ No newline at end of file diff --git a/src/main/kotlin/io/spring/messenger/web/SseBroadcaster.kt b/src/main/kotlin/io/spring/messenger/web/SseBroadcaster.kt new file mode 100644 index 0000000..67baf1b --- /dev/null +++ b/src/main/kotlin/io/spring/messenger/web/SseBroadcaster.kt @@ -0,0 +1,25 @@ +package io.spring.messenger.web + +import org.springframework.http.MediaType +import org.springframework.web.servlet.mvc.method.annotation.SseEmitter +import java.util.* +import java.util.Collections.synchronizedSet + +class SseBroadcaster { + + private var sseEmitters = synchronizedSet(HashSet()); + + fun subscribe(): SseEmitter { + val sseEmitter: SseEmitter = SseEmitter() + sseEmitter.onCompletion({ this.sseEmitters.remove(sseEmitter) }); + this.sseEmitters.add(sseEmitter); + return sseEmitter + } + + fun send(o:Any) { + synchronized (sseEmitters) { + sseEmitters.iterator().forEach { it.send(o, MediaType.APPLICATION_JSON) } + } + } +} + diff --git a/src/main/resources/static/index.html b/src/main/resources/static/index.html index ce225ba..5098dcf 100644 --- a/src/main/resources/static/index.html +++ b/src/main/resources/static/index.html @@ -10,6 +10,8 @@
+
Current user:
diff --git a/src/main/resources/static/map.js b/src/main/resources/static/map.js index eb5b510..3426eff 100644 --- a/src/main/resources/static/map.js +++ b/src/main/resources/static/map.js @@ -28,7 +28,7 @@ var geolocation = new ol.Geolocation({ projection: view.getProjection() }); geolocation.on("error", function (error) { - alert(error.message); + alert("Geolocation error: " + error.message); }); var positionFeature = new ol.Feature(); positionFeature.setStyle(new ol.style.Style({ @@ -55,18 +55,19 @@ geolocation.setTracking(true); // ################################# Popup ################################# +var container = document.getElementById('popup'); + +var popup = new ol.Overlay(({ + element: container, + autoPan: true, + autoPanAnimation: { + duration: 250 + } +})); +map.addOverlay(popup) + map.on('singleclick', function (evt) { var coordinate = evt.coordinate; - var container = document.createElement("div"); - container.className = "ol-popup"; - var popup = new ol.Overlay(({ - element: container, - autoPan: true, - autoPanAnimation: { - duration: 250 - } - })); - map.addOverlay(popup) popup.setPosition(coordinate); $(container).editable(function(value, settings) { $.ajax({ @@ -75,6 +76,7 @@ map.on('singleclick', function (evt) { data: JSON.stringify({content: value, author: $('#select-user').val(), location: {type: "Point", coordinates:[coordinate[0],coordinate[1]]}}), contentType: "application/json; charset=utf-8", dataType: "json"}); + popup.setPosition(undefined); return value; }, { type : "textarea", @@ -82,3 +84,35 @@ map.on('singleclick', function (evt) { }); }); + +// ################################# Messages layer ################################# + +var vectorSource = new ol.source.Vector({ + loader: function(extent, resolution, projection) { + var url = '/message/bbox/' + extent[0] + "," + extent[1] + "," + extent[2] + "," + extent[3]; + $.ajax({url: url, dataType: 'json', success: function(response) { + if (response.error) { + alert(response.error.message + '\n' + + response.error.details.join('\n')); + } else { + $.each(response, function( index, value ) { + var feature = new ol.Feature({ + geometry: new ol.geom.Point(value.location.coordinates), + data: value + }); + vectorSource.addFeature(feature); + }); + } + }}); + }, + strategy: ol.loadingstrategy.tile(ol.tilegrid.createXYZ({ + tileSize: 512 + })) + }); + +var vector = new ol.layer.Vector({ + source: vectorSource, + style: new ol.style.Style({image: new ol.style.Icon({src: "pig.png", scale: 0.15})}), +}); + +map.addLayer(vector);