Fix web socket connect/disconnect

This commit is contained in:
Dave Conway-Jones 2016-06-27 11:55:30 +01:00
parent 7e6aec6558
commit 80fbd59002
5 changed files with 320 additions and 36 deletions

View File

@ -1,6 +1,6 @@
{ {
"name" : "node-red-contrib-web-worldmap", "name" : "node-red-contrib-web-worldmap",
"version" : "1.0.13", "version" : "1.0.15",
"description" : "A Node-RED node to provide a web page of a world map for plotting things on.", "description" : "A Node-RED node to provide a web page of a world map for plotting things on.",
"dependencies" : { "dependencies" : {
"express": "4.*", "express": "4.*",

View File

@ -17,10 +17,12 @@
module.exports = function(RED) { module.exports = function(RED) {
"use strict"; "use strict";
var express = require("express"); var express = require("express");
var io = require('socket.io')(RED.server); var io = require('socket.io');
var socket;
var WorldMap = function(n) { var WorldMap = function(n) {
RED.nodes.createNode(this,n); RED.nodes.createNode(this,n);
if (!socket) { socket = io.listen(RED.server); }
this.lat = n.lat || ""; this.lat = n.lat || "";
this.lon = n.lon || ""; this.lon = n.lon || "";
this.zoom = n.zoom || ""; this.zoom = n.zoom || "";
@ -30,12 +32,14 @@ module.exports = function(RED) {
var node = this; var node = this;
//node.log("Serving map from "+__dirname+" as "+RED.settings.httpNodeRoot.slice(0,-1)+"/worldmap"); //node.log("Serving map from "+__dirname+" as "+RED.settings.httpNodeRoot.slice(0,-1)+"/worldmap");
RED.httpNode.use("/worldmap", express.static(__dirname + '/worldmap')); RED.httpNode.use("/worldmap", express.static(__dirname + '/worldmap'));
var callback = function(socket) {
node.status({fill:"green",shape:"dot",text:"connected "+Object.keys(io.sockets.connected).length}); var callback = function(client) {
node.on('input', function(msg) { node.status({fill:"green",shape:"dot",text:"connected "+socket.engine.clientsCount});
socket.emit("worldmapdata",msg.payload); function handler(msg) {
}); client.emit("worldmapdata",msg.payload);
socket.on('worldmap', function(data) { }
node.on('input', handler);
client.on('worldmap', function(data) {
if (data.action === "connected") { if (data.action === "connected") {
var c = {init:true}; var c = {init:true};
if (node.lat && node.lat.length > 0) { c.lat = node.lat; } if (node.lat && node.lat.length > 0) { c.lat = node.lat; }
@ -44,45 +48,50 @@ module.exports = function(RED) {
if (node.layer && node.layer.length > 0) { c.layer = node.layer; } if (node.layer && node.layer.length > 0) { c.layer = node.layer; }
if (node.cluster && node.cluster.length > 0) { c.cluster = node.cluster; } if (node.cluster && node.cluster.length > 0) { c.cluster = node.cluster; }
if (node.maxage && node.maxage.length > 0) { c.maxage = node.maxage; } if (node.maxage && node.maxage.length > 0) { c.maxage = node.maxage; }
socket.emit("worldmapdata",{command:c}); client.emit("worldmapdata",{command:c});
} }
}); });
socket.on('disconnect', function() { client.on('disconnect', function() {
node.status({fill:"green",shape:"ring",text:"connected "+Object.keys(io.sockets.connected).length}); node.removeListener("input", handler);
node.status({fill:"green",shape:"ring",text:"connected "+socket.engine.clientsCount});
}); });
node.on("close", function() { node.on("close", function() {
socket.disconnect(); client.disconnect(true);
}); });
} }
node.on("close", function() { node.on("close", function() {
node.status({}); node.status({});
io.sockets.removeListener('connection', callback); //socket.close();
}); });
io.on('connection', callback ); socket.on('connection', callback);
} }
RED.nodes.registerType("worldmap",WorldMap); RED.nodes.registerType("worldmap",WorldMap);
var WorldMapIn = function(n) { var WorldMapIn = function(n) {
RED.nodes.createNode(this,n); RED.nodes.createNode(this,n);
if (!socket) { socket = io.listen(RED.server); }
var node = this; var node = this;
var callback = function(socket) {
node.status({fill:"green",shape:"dot",text:"connected "+Object.keys(io.sockets.connected).length}); var callback = function(client) {
socket.on('worldmap', function(data) { node.status({fill:"green",shape:"dot",text:"connected "+socket.engine.clientsCount});
client.on('worldmap', function(data) {
node.send({payload:data, topic:"worldmap"}); node.send({payload:data, topic:"worldmap"});
}); });
socket.on('disconnect', function() { client.on('disconnect', function() {
node.status({fill:"green",shape:"ring",text:"connected "+Object.keys(io.sockets.connected).length}); node.status({fill:"green",shape:"ring",text:"connected "+socket.engine.clientsCount});
node.send({payload:{action:"disconnect", clients:Object.keys(io.sockets.connected).length}, topic:"worldmap"}); node.send({payload:{action:"disconnect", clients:socket.engine.clientsCount}, topic:"worldmap"});
}); });
node.on("close", function() { node.on("close", function() {
socket.disconnect(); client.disconnect(true);
}); });
} }
node.on("close", function() { node.on("close", function() {
node.status({}); node.status({});
io.sockets.removeListener('connection', callback); //socket.close();
}); });
io.on('connection', callback); socket.on('connection', callback);
} }
RED.nodes.registerType("worldmap in",WorldMapIn); RED.nodes.registerType("worldmap in",WorldMapIn);
} }

View File

@ -38,6 +38,7 @@
<script type="text/javascript" src="leaflet/Leaflet.vector-markers.min.js"></script> <script type="text/javascript" src="leaflet/Leaflet.vector-markers.min.js"></script>
<script type="text/javascript" src="leaflet/leaflet.boatmarker.js"></script> <script type="text/javascript" src="leaflet/leaflet.boatmarker.js"></script>
<script type="text/javascript" src="leaflet/leaflet.markercluster.js"></script> <script type="text/javascript" src="leaflet/leaflet.markercluster.js"></script>
<script type="text/javascript" src="leaflet/leaflet.markercluster.freezable-src.js"></script>
<script type="text/javascript" src="leaflet/leaflet.active-layers.min.js"></script> <script type="text/javascript" src="leaflet/leaflet.active-layers.min.js"></script>
<script type="text/javascript" src="leaflet/leaflet.select-layers.min.js"></script> <script type="text/javascript" src="leaflet/leaflet.select-layers.min.js"></script>
<script type="text/javascript" src="leaflet/leaflet.draw.js"></script> <script type="text/javascript" src="leaflet/leaflet.draw.js"></script>
@ -113,7 +114,7 @@ var marks = [];
var marksIndex = 0; var marksIndex = 0;
var popid = ""; var popid = "";
var menuOpen = false; var menuOpen = false;
var clusterAt = 1; var clusterAt = 12;
var maxage = 600; // default max age of icons on map in seconds - cleared after 10 mins var maxage = 600; // default max age of icons on map in seconds - cleared after 10 mins
var baselayername = "OSM grey"; // Default base layer OSM but uniform grey var baselayername = "OSM grey"; // Default base layer OSM but uniform grey
var ibmfoot = "&nbsp;&copy; IBM 2015,2016" var ibmfoot = "&nbsp;&copy; IBM 2015,2016"
@ -154,10 +155,10 @@ if ( window.localStorage.hasOwnProperty("lastpos") ) {
if ( window.localStorage.hasOwnProperty("lastzoom") ) { if ( window.localStorage.hasOwnProperty("lastzoom") ) {
startzoom = window.localStorage.getItem("lastzoom"); startzoom = window.localStorage.getItem("lastzoom");
} }
if ( window.localStorage.hasOwnProperty("clusterat") ) { // if ( window.localStorage.hasOwnProperty("clusterat") ) {
clusterAt = window.localStorage.getItem("clusterat"); // clusterAt = window.localStorage.getItem("clusterat");
document.getElementById("setclus").value = clusterAt; // document.getElementById("setclus").value = clusterAt;
} // }
if ( window.localStorage.hasOwnProperty("maxage") ) { if ( window.localStorage.hasOwnProperty("maxage") ) {
maxage = window.localStorage.getItem("maxage"); maxage = window.localStorage.getItem("maxage");
document.getElementById("maxage").value = maxage; document.getElementById("maxage").value = maxage;
@ -293,8 +294,9 @@ function setMaxAge() {
setMaxAge(); setMaxAge();
function setCluster() { function setCluster() {
clusterAt = parseInt(document.getElementById('setclus').value); clusterAt = parseInt(document.getElementById('setclus').value) || 0;
console.log("clusterAt set :",clusterAt); console.log("clusterAt set:",clusterAt);
showMapCurrentZoom();
} }
setCluster(); setCluster();
@ -401,9 +403,19 @@ map.on('baselayerchange', function(e) {
ws.emit("worldmap",{action:"layer", name:e.name}); ws.emit("worldmap",{action:"layer", name:e.name});
}); });
map.on('zoomend', function() { function showMapCurrentZoom() {
console.log("ZOOM:",map.getZoom(),". CLUSTER:",clusterAt);
for (var l in layers) {
if (layers[l].hasOwnProperty("_zoom")) {
if (map.getZoom() >= clusterAt) {
layers[l].disableClustering();
}
else {
layers[l].enableClustering();
}
}
}
setTimeout( function() { setTimeout( function() {
console.log("ZOOM :",map.getZoom());
for (var key in markers) { for (var key in markers) {
if (polygons[key]) { if (polygons[key]) {
var vis = layers[markers[key].lay].getVisibleParent(markers[key]); var vis = layers[markers[key].lay].getVisibleParent(markers[key]);
@ -417,6 +429,10 @@ map.on('zoomend', function() {
} }
} }
},750); },750);
}
map.on('zoomend', function() {
showMapCurrentZoom();
}); });
//map.on('contextmenu', function(e) { //map.on('contextmenu', function(e) {
@ -680,7 +696,12 @@ function setMarker(data) {
var lay = data.layer || "not known"; var lay = data.layer || "not known";
if (typeof layers[lay] == "undefined") { // add layer if if doesn't exist if (typeof layers[lay] == "undefined") { // add layer if if doesn't exist
//layers[lay] = new L.LayerGroup().addTo(map); //layers[lay] = new L.LayerGroup().addTo(map);
layers[lay] = new L.MarkerClusterGroup({maxClusterRadius:50, spiderfyDistanceMultiplier:1.8, disableClusteringAtZoom:clusterAt}).addTo(map); layers[lay] = new L.MarkerClusterGroup({
maxClusterRadius:50,
spiderfyDistanceMultiplier:1.8,
disableClusteringAtZoom:clusterAt,
//zoomToBoundsOnClick:false
}).addTo(map);
overlays[lay] = layers[lay]; overlays[lay] = layers[lay];
layercontrol.addOverlay(layers[lay],lay); layercontrol.addOverlay(layers[lay],lay);
} }
@ -926,8 +947,9 @@ function doCommand(cmd) {
if (cmd.hasOwnProperty("lon")) { clon = cmd.lon; } if (cmd.hasOwnProperty("lon")) { clon = cmd.lon; }
if (cmd.hasOwnProperty("zoom")) { czoom = cmd.zoom; } if (cmd.hasOwnProperty("zoom")) { czoom = cmd.zoom; }
if (cmd.hasOwnProperty("cluster")) { if (cmd.hasOwnProperty("cluster")) {
document.getElementById("setclus").value = cmd.cluster; clusterAt = cmd.cluster;
setCluster(); // document.getElementById("setclus").value = cmd.cluster;
// setCluster();
} }
if (cmd.hasOwnProperty("maxage")) { if (cmd.hasOwnProperty("maxage")) {
document.getElementById("maxage").value = cmd.maxage; document.getElementById("maxage").value = cmd.maxage;

View File

@ -0,0 +1,252 @@
/**
* Leaflet.MarkerCluster.Freezable sub-plugin for Leaflet.markercluster plugin.
* Adds the ability to freeze clusters at a specified zoom.
* Copyright (c) 2015 Boris Seang
* Distributed under the MIT License (Expat type)
*/
// UMD
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define(['leaflet'], function (L) {
return (root.L.MarkerClusterGroup = factory(L));
});
} else if (typeof module === 'object' && module.exports) {
// Node. Does not work with strict CommonJS, but
// only CommonJS-like environments that support module.exports,
// like Node.
module.exports = factory(require('leaflet'));
} else {
// Browser globals
root.L.MarkerClusterGroup = factory(root.L);
}
}(this, function (L, undefined) { // Does not actually expect the 'undefined' argument, it is just a trick to have an undefined variable.
var LMCG = L.MarkerClusterGroup,
LMCGproto = LMCG.prototype;
LMCG.freezableVersion = '0.1.0';
LMCG.include({
_originalOnAdd: LMCGproto.onAdd,
onAdd: function (map) {
var frozenZoom = this._zoom;
this._originalOnAdd(map);
if (this._frozen) {
// Restore the specified frozenZoom if necessary.
if (frozenZoom >= 0 && frozenZoom !== this._zoom) {
// Undo clusters and markers addition to this._featureGroup.
this._featureGroup.clearLayers();
this._zoom = frozenZoom;
this.addLayers([]);
}
// Replace the callbacks on zoomend and moveend events.
map.off('zoomend', this._zoomEnd, this);
map.off('moveend', this._moveEnd, this);
map.on('zoomend moveend', this._viewChangeEndNotClustering, this);
}
},
_originalOnRemove: LMCGproto.onRemove,
onRemove: function (map) {
map.off('zoomend moveend', this._viewChangeEndNotClustering, this);
this._originalOnRemove(map);
},
disableClustering: function () {
return this.freezeAtZoom(this._maxZoom + 1);
},
disableClusteringKeepSpiderfy: function () {
return this.freezeAtZoom(this._maxZoom);
},
enableClustering: function () {
return this.unfreeze();
},
unfreeze: function () {
return this.freezeAtZoom(false);
},
freezeAtZoom: function (frozenZoom) {
this._processQueue();
var map = this._map;
// If frozenZoom is not specified, true or NaN, freeze at current zoom.
// Note: NaN is the only value which is not eaqual to itself.
if (frozenZoom === undefined || frozenZoom === true || (frozenZoom !== frozenZoom)) {
// Set to -1 if not on map, as the sign to freeze as soon as it gets added to a map.
frozenZoom = map ? Math.round(map.getZoom()) : -1;
} else if (frozenZoom === 'max') {
// If frozenZoom is "max", freeze at MCG maxZoom + 1 (eliminates all clusters).
frozenZoom = this._maxZoom + 1;
} else if (frozenZoom === 'maxKeepSpiderfy') {
// If "maxKeepSpiderfy", freeze at MCG maxZoom (eliminates all clusters but bottom-most ones).
frozenZoom = this._maxZoom;
}
var requestFreezing = typeof frozenZoom === 'number';
if (this._frozen) { // Already frozen.
if (!requestFreezing) { // Unfreeze.
this._unfreeze();
return this;
}
// Just change the frozen zoom: go straight to artificial zoom.
} else if (requestFreezing) {
// Start freezing
this._initiateFreeze();
} else { // Not frozen and not requesting freezing => nothing to do.
return this;
}
this._artificialZoomSafe(this._zoom, frozenZoom);
return this;
},
_initiateFreeze: function () {
var map = this._map;
// Start freezing
this._frozen = true;
if (map) {
// Change behaviour on zoomEnd and moveEnd.
map.off('zoomend', this._zoomEnd, this);
map.off('moveend', this._moveEnd, this);
map.on('zoomend moveend', this._viewChangeEndNotClustering, this);
}
},
_unfreeze: function () {
var map = this._map;
this._frozen = false;
if (map) {
// Restore original behaviour on zoomEnd.
map.off('zoomend moveend', this._viewChangeEndNotClustering, this);
map.on('zoomend', this._zoomEnd, this);
map.on('moveend', this._moveEnd, this);
// Animate.
this._executeAfterUnspiderfy(function () {
this._zoomEnd(); // Will set this._zoom at the end.
}, this);
}
},
_executeAfterUnspiderfy: function (callback, context) {
// Take care of spiderfied markers!
// The cluster might be removed, whereas markers are on fake positions.
if (this._unspiderfy && this._spiderfied) {
this.once('animationend', function () {
callback.call(context);
});
this._unspiderfy();
return;
}
callback.call(context);
},
_artificialZoomSafe: function (previousZoom, targetZoom) {
this._zoom = targetZoom;
if (!this._map || previousZoom === targetZoom) {
return;
}
this._executeAfterUnspiderfy(function () {
this._artificialZoom(previousZoom, targetZoom);
}, this);
},
_artificialZoom: function (previousZoom, targetZoom) {
if (previousZoom < targetZoom) {
// Make as if we had instantly zoomed in from previousZoom to targetZoom.
this._animationStart();
this._topClusterLevel._recursivelyRemoveChildrenFromMap(
this._currentShownBounds, previousZoom, this._getExpandedVisibleBounds()
);
this._animationZoomIn(previousZoom, targetZoom);
} else if (previousZoom > targetZoom) {
// Make as if we had instantly zoomed out from previousZoom to targetZoom.
this._animationStart();
this._animationZoomOut(previousZoom, targetZoom);
}
},
_viewChangeEndNotClustering: function () {
var fg = this._featureGroup,
newBounds = this._getExpandedVisibleBounds(),
targetZoom = this._zoom;
// Remove markers and bottom clusters outside newBounds, unless they come
// from a spiderfied cluster.
fg.eachLayer(function (layer) {
if (!newBounds.contains(layer._latlng) && layer.__parent && layer.__parent._zoom < targetZoom) {
fg.removeLayer(layer);
}
});
// Add markers and bottom clusters in newBounds.
this._topClusterLevel._recursively(newBounds, -1, targetZoom,
function (c) { // Add markers from each cluster of lower zoom than targetZoom
if (c._zoom === targetZoom) { // except targetZoom
return;
}
var markers = c._markers,
i = 0,
marker;
for (; i < markers.length; i++) {
marker = c._markers[i];
if (!newBounds.contains(marker._latlng)) {
continue;
}
fg.addLayer(marker);
}
},
function (c) { // Add clusters from targetZoom.
c._addToMap();
}
);
},
_originalZoomOrSpiderfy: LMCGproto._zoomOrSpiderfy,
_zoomOrSpiderfy: function (e) {
if (this._frozen && this.options.spiderfyOnMaxZoom) {
e.layer.spiderfy();
if (e.originalEvent && e.originalEvent.keyCode === 13) {
map._container.focus();
}
} else {
this._originalZoomOrSpiderfy(e);
}
}
});
// Just return a value to define the module export.
return LMCG;
}));

View File

@ -1,5 +1,5 @@
CACHE MANIFEST CACHE MANIFEST
# date: Jun 14th v1.0.13 # date: Jun 14th v1.0.15
CACHE: CACHE:
index.html index.html
@ -35,6 +35,7 @@ leaflet/leaflet.draw.js
leaflet/leaflet.fullscreen.css leaflet/leaflet.fullscreen.css
leaflet/leaflet.js leaflet/leaflet.js
leaflet/leaflet.markercluster.js leaflet/leaflet.markercluster.js
leaflet/leaflet.markercluster.freezable-src.js
leaflet/leaflet.measurecontrol.css leaflet/leaflet.measurecontrol.css
leaflet/leaflet.measurecontrol.js leaflet/leaflet.measurecontrol.js
leaflet/leaflet.select-layers.min.js leaflet/leaflet.select-layers.min.js