node-red-contrib-web-worldmap 2.29.0 → 2.30.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (188) hide show
  1. package/.github/FUNDING.yml +13 -0
  2. package/CHANGELOG.md +5 -2
  3. package/README.md +3 -0
  4. package/node_modules/array-flatten/package.json +6 -9
  5. package/node_modules/body-parser/HISTORY.md +18 -0
  6. package/node_modules/body-parser/README.md +9 -1
  7. package/node_modules/body-parser/SECURITY.md +25 -0
  8. package/node_modules/body-parser/lib/read.js +26 -2
  9. package/node_modules/body-parser/lib/types/json.js +10 -4
  10. package/node_modules/body-parser/package.json +24 -20
  11. package/node_modules/call-bind/.eslintignore +1 -0
  12. package/node_modules/call-bind/.eslintrc +17 -0
  13. package/node_modules/call-bind/.github/FUNDING.yml +12 -0
  14. package/node_modules/call-bind/.nycrc +13 -0
  15. package/node_modules/call-bind/CHANGELOG.md +42 -0
  16. package/node_modules/call-bind/LICENSE +21 -0
  17. package/node_modules/call-bind/README.md +2 -0
  18. package/node_modules/call-bind/callBound.js +15 -0
  19. package/node_modules/call-bind/index.js +47 -0
  20. package/node_modules/call-bind/package.json +108 -0
  21. package/node_modules/call-bind/test/callBound.js +55 -0
  22. package/node_modules/call-bind/test/index.js +66 -0
  23. package/node_modules/cookie/HISTORY.md +8 -0
  24. package/node_modules/cookie/README.md +50 -34
  25. package/node_modules/cookie/SECURITY.md +25 -0
  26. package/node_modules/cookie/index.js +83 -15
  27. package/node_modules/cookie/package.json +17 -15
  28. package/node_modules/cookie-signature/package.json +6 -9
  29. package/node_modules/depd/History.md +7 -0
  30. package/node_modules/depd/LICENSE +1 -1
  31. package/node_modules/depd/Readme.md +8 -8
  32. package/node_modules/depd/index.js +29 -13
  33. package/node_modules/depd/package.json +25 -24
  34. package/node_modules/destroy/LICENSE +1 -0
  35. package/node_modules/destroy/README.md +15 -12
  36. package/node_modules/destroy/index.js +147 -13
  37. package/node_modules/destroy/package.json +29 -20
  38. package/node_modules/ee-first/package.json +6 -9
  39. package/node_modules/encodeurl/package.json +11 -14
  40. package/node_modules/escape-html/package.json +11 -14
  41. package/node_modules/etag/package.json +11 -14
  42. package/node_modules/express/History.md +54 -0
  43. package/node_modules/express/Readme.md +39 -31
  44. package/node_modules/express/lib/application.js +18 -1
  45. package/node_modules/express/lib/response.js +40 -18
  46. package/node_modules/express/lib/router/index.js +20 -15
  47. package/node_modules/express/lib/router/route.js +9 -0
  48. package/node_modules/express/lib/utils.js +1 -0
  49. package/node_modules/express/lib/view.js +1 -1
  50. package/node_modules/express/package.json +25 -26
  51. package/node_modules/finalhandler/HISTORY.md +8 -0
  52. package/node_modules/finalhandler/LICENSE +1 -1
  53. package/node_modules/finalhandler/README.md +5 -6
  54. package/node_modules/finalhandler/SECURITY.md +25 -0
  55. package/node_modules/finalhandler/index.js +8 -3
  56. package/node_modules/finalhandler/package.json +30 -32
  57. package/node_modules/fresh/package.json +6 -9
  58. package/node_modules/function-bind/.editorconfig +20 -0
  59. package/node_modules/function-bind/.eslintrc +15 -0
  60. package/node_modules/function-bind/.jscs.json +176 -0
  61. package/node_modules/function-bind/.npmignore +22 -0
  62. package/node_modules/function-bind/.travis.yml +168 -0
  63. package/node_modules/function-bind/LICENSE +20 -0
  64. package/node_modules/function-bind/README.md +48 -0
  65. package/node_modules/function-bind/implementation.js +52 -0
  66. package/node_modules/function-bind/index.js +5 -0
  67. package/node_modules/function-bind/package.json +96 -0
  68. package/node_modules/function-bind/test/.eslintrc +9 -0
  69. package/node_modules/function-bind/test/index.js +252 -0
  70. package/node_modules/get-intrinsic/.eslintrc +37 -0
  71. package/node_modules/get-intrinsic/.github/FUNDING.yml +12 -0
  72. package/node_modules/get-intrinsic/.nycrc +9 -0
  73. package/node_modules/get-intrinsic/CHANGELOG.md +98 -0
  74. package/node_modules/get-intrinsic/LICENSE +21 -0
  75. package/node_modules/get-intrinsic/README.md +71 -0
  76. package/node_modules/get-intrinsic/index.js +334 -0
  77. package/node_modules/get-intrinsic/package.json +120 -0
  78. package/node_modules/get-intrinsic/test/GetIntrinsic.js +274 -0
  79. package/node_modules/has/LICENSE-MIT +22 -0
  80. package/node_modules/has/README.md +18 -0
  81. package/node_modules/has/package.json +73 -0
  82. package/node_modules/has/src/index.js +5 -0
  83. package/node_modules/has/test/index.js +10 -0
  84. package/node_modules/has-symbols/.eslintrc +11 -0
  85. package/node_modules/has-symbols/.github/FUNDING.yml +12 -0
  86. package/node_modules/has-symbols/.nycrc +9 -0
  87. package/node_modules/has-symbols/CHANGELOG.md +75 -0
  88. package/node_modules/has-symbols/LICENSE +21 -0
  89. package/node_modules/has-symbols/README.md +46 -0
  90. package/node_modules/has-symbols/index.js +13 -0
  91. package/node_modules/has-symbols/package.json +126 -0
  92. package/node_modules/has-symbols/shams.js +42 -0
  93. package/node_modules/has-symbols/test/index.js +22 -0
  94. package/node_modules/has-symbols/test/shams/core-js.js +28 -0
  95. package/node_modules/has-symbols/test/shams/get-own-property-symbols.js +28 -0
  96. package/node_modules/has-symbols/test/tests.js +56 -0
  97. package/node_modules/http-errors/HISTORY.md +15 -0
  98. package/node_modules/http-errors/README.md +2 -2
  99. package/node_modules/http-errors/index.js +15 -25
  100. package/node_modules/http-errors/package.json +22 -20
  101. package/node_modules/media-typer/package.json +6 -9
  102. package/node_modules/merge-descriptors/package.json +6 -9
  103. package/node_modules/methods/package.json +11 -14
  104. package/node_modules/object-inspect/.eslintrc +53 -0
  105. package/node_modules/object-inspect/.github/FUNDING.yml +12 -0
  106. package/node_modules/object-inspect/.nycrc +13 -0
  107. package/node_modules/object-inspect/CHANGELOG.md +360 -0
  108. package/node_modules/object-inspect/LICENSE +21 -0
  109. package/node_modules/object-inspect/example/all.js +23 -0
  110. package/node_modules/object-inspect/example/circular.js +6 -0
  111. package/node_modules/object-inspect/example/fn.js +5 -0
  112. package/node_modules/object-inspect/example/inspect.js +10 -0
  113. package/node_modules/object-inspect/index.js +512 -0
  114. package/node_modules/object-inspect/package-support.json +20 -0
  115. package/node_modules/object-inspect/package.json +122 -0
  116. package/node_modules/object-inspect/readme.markdown +86 -0
  117. package/node_modules/object-inspect/test/bigint.js +58 -0
  118. package/node_modules/object-inspect/test/browser/dom.js +15 -0
  119. package/node_modules/object-inspect/test/circular.js +16 -0
  120. package/node_modules/object-inspect/test/deep.js +12 -0
  121. package/node_modules/object-inspect/test/element.js +53 -0
  122. package/node_modules/object-inspect/test/err.js +48 -0
  123. package/node_modules/object-inspect/test/fakes.js +29 -0
  124. package/node_modules/object-inspect/test/fn.js +76 -0
  125. package/node_modules/object-inspect/test/has.js +15 -0
  126. package/node_modules/object-inspect/test/holes.js +15 -0
  127. package/node_modules/object-inspect/test/indent-option.js +271 -0
  128. package/node_modules/object-inspect/test/inspect.js +139 -0
  129. package/node_modules/object-inspect/test/lowbyte.js +12 -0
  130. package/node_modules/object-inspect/test/number.js +58 -0
  131. package/node_modules/object-inspect/test/quoteStyle.js +17 -0
  132. package/node_modules/object-inspect/test/toStringTag.js +40 -0
  133. package/node_modules/object-inspect/test/undef.js +12 -0
  134. package/node_modules/object-inspect/test/values.js +211 -0
  135. package/node_modules/object-inspect/test-core-js.js +26 -0
  136. package/node_modules/object-inspect/util.inspect.js +1 -0
  137. package/node_modules/on-finished/HISTORY.md +10 -0
  138. package/node_modules/on-finished/README.md +28 -20
  139. package/node_modules/on-finished/index.js +51 -13
  140. package/node_modules/on-finished/package.json +25 -20
  141. package/node_modules/path-to-regexp/package.json +6 -9
  142. package/node_modules/qs/CHANGELOG.md +22 -5
  143. package/node_modules/qs/README.md +7 -0
  144. package/node_modules/qs/dist/qs.js +1207 -5
  145. package/node_modules/qs/lib/parse.js +6 -0
  146. package/node_modules/qs/lib/stringify.js +33 -3
  147. package/node_modules/qs/package.json +16 -13
  148. package/node_modules/qs/test/parse.js +9 -0
  149. package/node_modules/qs/test/stringify.js +62 -1
  150. package/node_modules/raw-body/HISTORY.md +14 -0
  151. package/node_modules/raw-body/LICENSE +1 -1
  152. package/node_modules/raw-body/README.md +4 -0
  153. package/node_modules/raw-body/SECURITY.md +24 -0
  154. package/node_modules/raw-body/index.js +45 -2
  155. package/node_modules/raw-body/package.json +16 -15
  156. package/node_modules/send/HISTORY.md +15 -0
  157. package/node_modules/send/LICENSE +1 -1
  158. package/node_modules/send/README.md +2 -2
  159. package/node_modules/send/SECURITY.md +24 -0
  160. package/node_modules/send/index.js +37 -27
  161. package/node_modules/send/package.json +22 -21
  162. package/node_modules/serve-static/HISTORY.md +12 -0
  163. package/node_modules/serve-static/README.md +1 -1
  164. package/node_modules/serve-static/package.json +16 -16
  165. package/node_modules/side-channel/.eslintignore +1 -0
  166. package/node_modules/side-channel/.eslintrc +11 -0
  167. package/node_modules/side-channel/.github/FUNDING.yml +12 -0
  168. package/node_modules/side-channel/.nycrc +13 -0
  169. package/node_modules/side-channel/CHANGELOG.md +65 -0
  170. package/node_modules/side-channel/LICENSE +21 -0
  171. package/node_modules/side-channel/README.md +2 -0
  172. package/node_modules/side-channel/index.js +124 -0
  173. package/node_modules/side-channel/package.json +95 -0
  174. package/node_modules/side-channel/test/index.js +78 -0
  175. package/node_modules/statuses/HISTORY.md +17 -0
  176. package/node_modules/statuses/README.md +51 -42
  177. package/node_modules/statuses/codes.json +2 -3
  178. package/node_modules/statuses/index.js +52 -19
  179. package/node_modules/statuses/package.json +29 -31
  180. package/node_modules/unpipe/package.json +7 -9
  181. package/node_modules/utils-merge/package.json +6 -9
  182. package/package.json +2 -2
  183. package/worldmap/worldmap.js +22 -7
  184. package/worldmap.html +16 -0
  185. package/worldmap.js +553 -551
  186. package/node_modules/depd/lib/compat/callsite-tostring.js +0 -103
  187. package/node_modules/depd/lib/compat/event-listener-count.js +0 -22
  188. package/node_modules/depd/lib/compat/index.js +0 -79
package/worldmap.js CHANGED
@@ -1,551 +1,553 @@
1
- /* eslint-disable no-inner-declarations */
2
-
3
- module.exports = function(RED) {
4
- "use strict";
5
- var fs = require('fs');
6
- var path = require("path");
7
- var express = require("express");
8
- var compression = require("compression");
9
- var sockjs = require('sockjs');
10
- var sockets = {};
11
- RED.log.info("Worldmap version " + require('./package.json').version );
12
- // add the cgi module for serving local maps.... only if mapserv exists
13
- if (fs.existsSync((__dirname + '/mapserv'))) {
14
- RED.httpNode.use("/cgi-bin/mapserv", require('cgi')(__dirname + '/mapserv'));
15
- }
16
-
17
- function worldMap(node, n) {
18
- var allPoints = {};
19
- RED.nodes.createNode(node,n);
20
- node.lat = n.lat || "";
21
- node.lon = n.lon || "";
22
- node.zoom = n.zoom || "";
23
- node.layer = n.layer || "";
24
- node.cluster = n.cluster || "";
25
- node.maxage = n.maxage || "";
26
- node.showmenu = n.usermenu || "show";
27
- node.layers = n.layers || "show";
28
- node.panlock = n.panlock || "false";
29
- node.zoomlock = n.zoomlock || "false";
30
- node.panit = n.panit || "false";
31
- node.hiderightclick = n.hiderightclick || "false";
32
- node.coords = n.coords || "none";
33
- node.showgrid = n.showgrid || "false";
34
- node.allowFileDrop = n.allowFileDrop || "false";
35
- node.path = n.path || "/worldmap";
36
- node.maplist = n.maplist;
37
- node.overlist = n.overlist;
38
- node.mapname = n.mapname || "";
39
- node.mapurl = n.mapurl || "";
40
- node.mapopt = n.mapopt || "";
41
- node.mapwms = n.mapwms || false;
42
- if (n.maplist === undefined) { node.maplist = "OSMG,OSMC,EsriC,EsriS,EsriT,EsriDG,UKOS,SW"; }
43
- if (n.overlist === undefined) { node.overlist = "DR,CO,RA,DN,HM"; }
44
- try { node.mapopt2 = JSON.parse(node.mapopt); }
45
- catch(e) { node.mapopt2 = null; }
46
-
47
- if (node.path.charAt(0) != "/") { node.path = "/" + node.path; }
48
- if (!sockets[node.path]) {
49
- var libPath = path.posix.join(RED.settings.httpNodeRoot, node.path, 'leaflet', 'sockjs.min.js');
50
- var sockPath = path.posix.join(RED.settings.httpNodeRoot,node.path,'socket');
51
- sockets[node.path] = sockjs.createServer({prefix:sockPath, sockjs_url:libPath, log:function(s,e) { return; }});
52
- sockets[node.path].installHandlers(RED.server);
53
- sockets[node.path].on('error', function(e) { node.error("Socket Connection Error: "+e.stack); });
54
- }
55
- //node.log("Serving "+__dirname+" as "+node.path);
56
- node.log("started at "+node.path);
57
- var clients = {};
58
- RED.httpNode.get("/-worldmap3d-key", RED.auth.needsPermission('worldmap3d.read'), function(req, res) {
59
- if (process.env.MAPBOXGL_TOKEN) {
60
- res.send({key:process.env.MAPBOXGL_TOKEN});
61
- }
62
- else {
63
- node.error("No API key set");
64
- res.send({key:''})
65
- }
66
- });
67
- RED.httpNode.use(compression());
68
- RED.httpNode.use(node.path, express.static(__dirname + '/worldmap'));
69
- // RED.httpNode.use(node.path, express.static(__dirname + '/worldmap', {maxage:3600000}));
70
-
71
- var callback = function(client) {
72
- if (!client.headers.hasOwnProperty("user-agent")) { client.close(); }
73
- //client.setMaxListeners(0);
74
- clients[client.id] = client;
75
- client.on('data', function(message) {
76
- message = JSON.parse(message);
77
- if (message.action === "connected") {
78
- var m = {};
79
- var c = {init:true};
80
- c.maplist = node.maplist;
81
- c.overlist = node.overlist;
82
- if (node.layer && node.layer == "Custom") {
83
- m.name = node.mapname;
84
- m.url = node.mapurl;
85
- m.opt = node.mapopt2;
86
- if (node.mapwms === true) { m.wms = true; }
87
- client.write(JSON.stringify({command:{map:m}}));
88
- c.layer = m.name;
89
- }
90
- else {
91
- if (node.layer && node.layer.length > 0) { c.layer = node.layer; }
92
- }
93
- if (node.lat && node.lat.length > 0) { c.lat = node.lat; }
94
- if (node.lon && node.lon.length > 0) { c.lon = node.lon; }
95
- if (node.zoom && node.zoom.length > 0) { c.zoom = node.zoom; }
96
- if (node.cluster && node.cluster.length > 0) { c.cluster = node.cluster; }
97
- if (node.maxage && node.maxage.length > 0) { c.maxage = node.maxage; }
98
- c.showmenu = node.showmenu;
99
- c.panit = node.panit;
100
- c.panlock = node.panlock;
101
- c.zoomlock = node.zoomlock;
102
- c.showlayers = node.layers;
103
- c.grid = {showgrid:node.showgrid};
104
- c.hiderightclick = node.hiderightclick;
105
- c.allowFileDrop = node.allowFileDrop;
106
- c.coords = node.coords;
107
- if (node.name) { c.toptitle = node.name; }
108
- //console.log("INIT",c)
109
- client.write(JSON.stringify({command:c}));
110
- var o = Object.values(allPoints);
111
- o.map(v => delete v.tout);
112
- setTimeout(function() { client.write(JSON.stringify(o)) }, 250);
113
- }
114
- });
115
- client.on('close', function() {
116
- delete clients[client.id];
117
- node.status({fill:"green",shape:"ring",text:"connected "+Object.keys(clients).length,_sessionid:client.id});
118
- });
119
- node.status({fill:"green",shape:"dot",text:"connected "+Object.keys(clients).length,_sessionid:client.id});
120
- }
121
- node.on('input', function(msg) {
122
- if (msg.hasOwnProperty("_sessionid")) {
123
- if (clients.hasOwnProperty(msg._sessionid)) {
124
- clients[msg._sessionid].write(JSON.stringify(msg.payload));
125
- }
126
- }
127
- else {
128
- for (var c in clients) {
129
- if (clients.hasOwnProperty(c)) {
130
- clients[c].write(JSON.stringify(msg.payload));
131
- }
132
- }
133
- }
134
- if (msg.payload.hasOwnProperty("name")) {
135
- allPoints[msg.payload.name] = RED.util.cloneMessage(msg.payload);
136
- var t = node.maxage || 3600;
137
- if (msg.payload.ttl && msg.payload.ttl < t) { t = msg.payload.ttl; }
138
- allPoints[msg.payload.name].tout = setTimeout( function() { delete allPoints[msg.payload.name] }, t * 1000 );
139
- }
140
- });
141
- node.on("close", function() {
142
- for (var c in clients) {
143
- if (clients.hasOwnProperty(c)) {
144
- clients[c].end();
145
- }
146
- }
147
- clients = {};
148
- sockets[node.path].removeListener('connection', callback);
149
- for (var i=0; i < RED.httpNode._router.stack.length; i++) {
150
- var r = RED.httpNode._router.stack[i];
151
- if ((r.name === "serveStatic") && (r.regexp.test(node.path))) {
152
- RED.httpNode._router.stack.splice(i, 1)
153
- }
154
- }
155
- node.status({});
156
- });
157
- sockets[node.path].on('connection', callback);
158
- }
159
- var WorldMap = function(n) {
160
- worldMap(this, n);
161
- }
162
- RED.nodes.registerType("worldmap",WorldMap);
163
-
164
- function HTML(ui, config) {
165
- var width = config.width;
166
- if (width == 0) {
167
- var group = RED.nodes.getNode(config.group);
168
- if (group) { width = group.config.width; }
169
- }
170
- var height = config.height;
171
- if (height == 0) { height = 10; }
172
- var size = ui.getSizes();
173
- var frameWidth = (size.sx + size.cx) * width - size.cx;
174
- var frameHeight = (size.sy + size.cy) * height - size.cy;
175
- var url = encodeURI(path.posix.join(RED.settings.httpNodeRoot||RED.settings.httpRoot,config.path));
176
- if (config.layer === "MB3d") { url += "/index3d.html"; }
177
- var html = `<style>.nr-dashboard-ui_worldmap{padding:0;}</style><div style="overflow:hidden;">
178
- <iframe src="${url}" width="${frameWidth}px" height="${frameHeight}px" style="border:none;"></iframe></div>`;
179
- return html;
180
- }
181
-
182
- function checkConfig(node, conf) {
183
- if (!conf || !conf.hasOwnProperty("group")) {
184
- node.error("no group");
185
- return false;
186
- }
187
- return true;
188
- }
189
-
190
- var ui = undefined;
191
- try {
192
- ui = RED.require("node-red-dashboard")(RED);
193
- }
194
- catch(e) {
195
- RED.log.info("Node-RED Dashboard not found - ui_worldmap not installed.");
196
- }
197
- setTimeout( function() {
198
- if (ui) {
199
- function UIWorldMap(config) {
200
- try {
201
- var node = this;
202
- worldMap(node, config);
203
- var done = null;
204
- if (checkConfig(node, config)) {
205
- var html = HTML(ui, config);
206
- done = ui.addWidget({
207
- node: node,
208
- order: config.order,
209
- group: config.group,
210
- width: config.width,
211
- height: config.height,
212
- format: html,
213
- templateScope: "local",
214
- emitOnlyNewValues: false,
215
- forwardInputMessages: false,
216
- storeFrontEndInputAsState: false,
217
- convertBack: function (value) {
218
- return value;
219
- },
220
- beforeEmit: function(msg, value) {
221
- return { msg: { items: value } };
222
- },
223
- beforeSend: function (msg, orig) {
224
- if (orig) { return orig.msg; }
225
- },
226
- initController: function($scope, events) {
227
- }
228
- });
229
- }
230
- }
231
- catch (e) {
232
- console.log(e);
233
- }
234
- node.on("close", function() {
235
- if (done) { done(); }
236
- });
237
- }
238
- setImmediate(function() { RED.nodes.registerType("ui_worldmap", UIWorldMap) });
239
- }
240
- }, 100);
241
-
242
-
243
- var WorldMapIn = function(n) {
244
- RED.nodes.createNode(this,n);
245
- this.path = n.path || "/worldmap";
246
- this.events = n.events || "connect,disconnect,point,bounds,files,draw,other";
247
- if (this.path.charAt(0) != "/") { this.path = "/" + this.path; }
248
- if (!sockets[this.path]) {
249
- var libPath = path.posix.join(RED.settings.httpNodeRoot, this.path, 'leaflet', 'sockjs.min.js');
250
- var sockPath = path.posix.join(RED.settings.httpNodeRoot,this.path,'socket');
251
- sockets[this.path] = sockjs.createServer({prefix:sockPath, sockjs_url:libPath, log:function() { return; }});
252
- sockets[this.path].installHandlers(RED.server);
253
- }
254
- var node = this;
255
- var clients = {};
256
-
257
- var callback = function(client) {
258
- //client.setMaxListeners(0);
259
- clients[client.id] = client;
260
- //get ip of user connected to the _sessionid, check to see if its proxied first
261
- var sessionip = client.headers['x-real-ip'] || client.headers['x-forwarded-for'] || client.remoteAddress;
262
- node.status({fill:"green",shape:"dot",text:"connected "+Object.keys(clients).length,_sessionid:client.id});
263
- client.on('data', function(message) {
264
- message = JSON.parse(message);
265
- if (message.hasOwnProperty("action")) {
266
- if ((node.events.indexOf("connect")!==-1) && (message.action === "connected")) {
267
- setImmediate(function() {node.send({payload:message, topic:node.path.substr(1), _sessionid:client.id, _sessionip:sessionip})});
268
- }
269
- if ((node.events.indexOf("bounds")!==-1) && (message.action === "bounds")) {
270
- setImmediate(function() {node.send({payload:message, topic:node.path.substr(1), _sessionid:client.id, _sessionip:sessionip})});
271
- }
272
- if ((node.events.indexOf("point")!==-1) && ((message.action === "point")||(message.action === "move")||(message.action === "delete") )) {
273
- setImmediate(function() {node.send({payload:message, topic:node.path.substr(1), _sessionid:client.id, _sessionip:sessionip})});
274
- }
275
- if ((node.events.indexOf("layer")!==-1) && (message.action.indexOf("layer") !== -1) ) {
276
- setImmediate(function() {node.send({payload:message, topic:node.path.substr(1), _sessionid:client.id, _sessionip:sessionip})});
277
- }
278
- if ((node.events.indexOf("files")!==-1) && (message.action === "file")) {
279
- message.content = Buffer.from(message.content.split('base64,')[1], 'base64');
280
- setImmediate(function() {node.send({payload:message, topic:node.path.substr(1), _sessionid:client.id, _sessionip:sessionip})});
281
- }
282
- if ((node.events.indexOf("draw")!==-1) && (message.action === "draw")) {
283
- setImmediate(function() {node.send({payload:message, topic:node.path.substr(1), _sessionid:client.id, _sessionip:sessionip})});
284
- }
285
- if (node.events.indexOf("other")!==-1 && "connected,point,delete,move,draw,files,bounds".indexOf(message.action) === -1) {
286
- setImmediate(function() {node.send({payload:message, topic:node.path.substr(1), _sessionid:client.id, _sessionip:sessionip})});
287
- }
288
- }
289
- });
290
- client.on('close', function() {
291
- delete clients[client.id];
292
- node.status({fill:"green",shape:"ring",text:"connected "+Object.keys(clients).length,_sessionid:client.id});
293
- if (node.events.indexOf("disconnect")!==-1) {
294
- node.send({payload:{action:"disconnect", clients:Object.keys(clients).length}, topic:node.path.substr(1), _sessionid:client.id, _sessionip:sessionip});
295
- }
296
- });
297
- }
298
-
299
- node.on("close", function() {
300
- for (var c in clients) {
301
- if (clients.hasOwnProperty(c)) {
302
- clients[c].end();
303
- }
304
- }
305
- clients = {};
306
- sockets[this.path].removeListener('connection', callback);
307
- node.status({});
308
- });
309
- sockets[this.path].on('connection', callback);
310
- }
311
- RED.nodes.registerType("worldmap in",WorldMapIn);
312
-
313
-
314
- var WorldMapTracks = function(n) {
315
- RED.nodes.createNode(this,n);
316
- this.depth = parseInt(Number(n.depth) || 20);
317
- this.pointsarray = {};
318
- this.layer = n.layer || "combined"; // separate, single
319
- this.smooth = n.smooth || false;
320
- var node = this;
321
- var bezierSpline = require("@turf/bezier-spline").default;
322
-
323
- var doTrack = function(msg) {
324
- if (msg.hasOwnProperty("payload") && msg.payload.hasOwnProperty("name")) {
325
- var newmsg = RED.util.cloneMessage(msg);
326
- if (msg.payload.deleted) {
327
- if (msg.payload.name.substr(-1) === '_') {
328
- var a = node.pointsarray[msg.payload.name.substr(0,msg.payload.name.length-1)].pop();
329
- node.pointsarray[msg.payload.name.substr(0,msg.payload.name.length-1)] = [ a ];
330
- node.send(newmsg);
331
- }
332
- else {
333
- delete node.pointsarray[msg.payload.name];
334
- }
335
- //newmsg.payload.name = msg.payload.name + "_";
336
- node.send(newmsg);
337
- return;
338
- }
339
- if (!msg.payload.hasOwnProperty("lat") || !msg.payload.hasOwnProperty("lon")) { return; }
340
- if (!node.pointsarray.hasOwnProperty(msg.payload.name)) {
341
- node.pointsarray[msg.payload.name] = [];
342
- }
343
- if (msg.payload.hasOwnProperty("trackpoints") && !isNaN(parseInt(msg.payload.trackpoints)) ) {
344
- var tl = parseInt(msg.payload.trackpoints);
345
- if (tl < 0) { tl = 0; }
346
- if (node.pointsarray[msg.payload.name].length > tl) {
347
- node.pointsarray[msg.payload.name] = node.pointsarray[msg.payload.name].slice(-tl);
348
- }
349
- node.depth = tl;
350
- }
351
- if (node.depth < 2) { return; } // if set less than 2 then don't bother.
352
-
353
- var still = false;
354
- if (node.pointsarray[msg.payload.name].length > 0) {
355
- var oldlat = node.pointsarray[msg.payload.name][node.pointsarray[msg.payload.name].length-1].lat;
356
- var oldlon = node.pointsarray[msg.payload.name][node.pointsarray[msg.payload.name].length-1].lon;
357
- if (msg.payload.lat === oldlat && msg.payload.lon === oldlon) { still = true; }
358
- }
359
- if (!still) { node.pointsarray[msg.payload.name].push(msg.payload);
360
- if (node.pointsarray[msg.payload.name].length > node.depth) {
361
- node.pointsarray[msg.payload.name].shift();
362
- }
363
- }
364
- var line = [];
365
- for (var i=0; i<node.pointsarray[msg.payload.name].length; i++) {
366
- var m = node.pointsarray[msg.payload.name][i];
367
- if (m.hasOwnProperty("lat") && m.hasOwnProperty("lon")) {
368
- line.push( [m.lat*1, m.lon*1] );
369
- delete newmsg.payload.lat;
370
- delete newmsg.payload.lon;
371
- }
372
- if (m.hasOwnProperty("latitude") && m.hasOwnProperty("longitude")) {
373
- line.push( [m.latitude*1, m.longitude*1] );
374
- delete newmsg.payload.latitude;
375
- delete newmsg.payload.longitude;
376
- }
377
- if (m.hasOwnProperty("position") && m.position.hasOwnProperty("lat") && m.position.hasOwnProperty("lon")) {
378
- line.push( [m.position.lat*1, m.position.lon*1] );
379
- delete newmsg.payload.position;
380
- }
381
- }
382
- if (line.length > 1) { // only send track if two points or more
383
- if (node.smooth) {
384
- var curved = bezierSpline({"type":"Feature", "properties":{}, "geometry":{"type":"LineString", "coordinates":line }});
385
- newmsg.payload.line = curved.geometry.coordinates;
386
- }
387
- else {
388
- newmsg.payload.line = line;
389
- }
390
- newmsg.payload.name = msg.payload.name + "_";
391
- if (node.layer === "separate") {
392
- newmsg.payload.layer = msg.payload.layer + " tracks";
393
- if (newmsg.payload.layer.indexOf('_') === 0) {
394
- newmsg.payload.layer = newmsg.payload.layer.substr(1);
395
- }
396
- }
397
- if (node.layer === "single") {
398
- newmsg.payload.layer = "Tracks";
399
- }
400
- node.send(newmsg); // send the track
401
- }
402
- }
403
- if (msg.hasOwnProperty("payload") && msg.payload.hasOwnProperty("command") && msg.payload.command.hasOwnProperty("clear")) {
404
- for (var p in node.pointsarray) {
405
- if (node.pointsarray.hasOwnProperty(p)) {
406
- if (node.pointsarray[p][0].layer === msg.payload.command.clear) {
407
- delete node.pointsarray[p];
408
- }
409
- }
410
- }
411
- }
412
- }
413
-
414
- node.on("input", function(m) {
415
- if (Array.isArray(m.payload)) {
416
- m.payload.forEach(function (pay) {
417
- var n = RED.util.cloneMessage(m)
418
- n.payload = pay;
419
- doTrack(n);
420
- });
421
- }
422
- else {
423
- doTrack(m);
424
- }
425
- });
426
-
427
- node.on("close", function() {
428
- node.pointsarray = {};
429
- });
430
- }
431
- RED.nodes.registerType("worldmap-tracks",WorldMapTracks);
432
-
433
-
434
- var WorldMapHull = function(n) {
435
- RED.nodes.createNode(this,n);
436
- this.prop = n.prop || "layer";
437
- var node = this;
438
- node.oldlayercount = {};
439
- node.hulls = {};
440
-
441
- var convexHull = function(points) {
442
- var arr = [];
443
- for (const val of Object.values(points)) {
444
- arr.push(val);
445
- }
446
-
447
- arr.sort(function (a, b) {
448
- return a.lat != b.lat ? a.lat - b.lat : a.lon - b.lon;
449
- });
450
-
451
- var n = arr.length;
452
- var hull = [];
453
-
454
- for (var i = 0; i < 2 * n; i++) {
455
- var j = i < n ? i : 2 * n - 1 - i;
456
- while (hull.length >= 2 && removeMiddle(hull[hull.length - 2], hull[hull.length - 1], arr[j]))
457
- hull.pop();
458
- hull.push(arr[j]);
459
- }
460
-
461
- hull.pop();
462
- return hull;
463
- }
464
-
465
- var removeMiddle = function(a, b, c) {
466
- var cross = (a.lat- b.lat) * (c.lon - b.lon) - (a.lon - b.lon) * (c.lat- b.lat);
467
- var dot = (a.lat- b.lat) * (c.lat- b.lat) + (a.lon - b.lon) * (c.lon - b.lon);
468
- return cross < 0 || cross == 0 && dot <= 0;
469
- }
470
-
471
- var doHull = function(msg) {
472
- if (msg.hasOwnProperty("payload") && msg.payload.hasOwnProperty("name")) {
473
- var newmsg = RED.util.cloneMessage(msg);
474
- newmsg.payload = {};
475
- newmsg.payload[node.prop] = msg.payload[node.prop] || "unknown";
476
- if (msg.payload.deleted === true) {
477
- if (node.hulls.hasOwnProperty(newmsg.payload[node.prop])) {
478
- delete node.hulls[newmsg.payload[node.prop]][msg.payload.name];
479
- }
480
- }
481
- else {
482
- if (!msg.payload.hasOwnProperty("lat") || !msg.payload.hasOwnProperty("lon")) { return; }
483
- if (!node.hulls.hasOwnProperty(newmsg.payload[node.prop])) {
484
- node.hulls[newmsg.payload[node.prop]] = {};
485
- }
486
- node.hulls[newmsg.payload[node.prop]][msg.payload.name] = {lat:msg.payload.lat,lon:msg.payload.lon};
487
- }
488
- var convexHullPoints = convexHull(node.hulls[newmsg.payload[node.prop]]);
489
- var leafletHull = convexHullPoints.map(function (element) {return ([element.lat,element.lon])})
490
-
491
- newmsg.payload.name = newmsg.payload[node.prop];
492
- newmsg.payload.clickable = true;
493
-
494
- if (msg.payload.fillColor) {
495
- newmsg.payload.color = msg.payload.fillColor;
496
- newmsg.payload.fillColor = msg.payload.fillColor;
497
- }
498
-
499
- if (node.oldlayercount[newmsg.payload[node.prop]] === undefined) {
500
- node.oldlayercount[newmsg.payload[node.prop]] = 0;
501
- }
502
- var oldl = node.oldlayercount[newmsg.payload[node.prop]];
503
-
504
- if (leafletHull.length === 1 && oldl === 2) {
505
- newmsg.payload.deleted = true;
506
- node.send(newmsg);
507
- }
508
- if (leafletHull.length === 2 && (oldl === 1 || oldl === 3)) {
509
- var newmsg2 = RED.util.cloneMessage(newmsg);
510
- newmsg2.payload.deleted = true;
511
- node.send(newmsg2);
512
- newmsg.payload.line = leafletHull;
513
- node.send(newmsg);
514
- }
515
- if (leafletHull.length === 3 && oldl === 2) {
516
- var newmsg3 = RED.util.cloneMessage(newmsg);
517
- newmsg3.payload.deleted = true;
518
- node.send(newmsg3);
519
- }
520
- if (leafletHull.length >= 3) {
521
- newmsg.payload.area = leafletHull;
522
- node.send(newmsg);
523
- }
524
-
525
- node.oldlayercount[newmsg.payload[node.prop]] = leafletHull.length;
526
- }
527
- }
528
-
529
- node.on("input", function(m) {
530
- if (Array.isArray(m.payload)) {
531
- m.payload.forEach(function (pay) {
532
- var n = RED.util.cloneMessage(m)
533
- n.payload = pay;
534
- doHull(n);
535
- });
536
- }
537
- else {
538
- doHull(m);
539
- }
540
- });
541
-
542
- node.on("close", function() {
543
- node.hulls = {};
544
- });
545
- }
546
- RED.nodes.registerType("worldmap-hull",WorldMapHull);
547
-
548
- RED.httpAdmin.get("/-ui-worldmap", RED.auth.needsPermission('rpi-ui-worldmap.read'), function(req, res) {
549
- res.send(ui ? "true": "false");
550
- });
551
- }
1
+ /* eslint-disable no-inner-declarations */
2
+
3
+ module.exports = function(RED) {
4
+ "use strict";
5
+ var fs = require('fs');
6
+ var path = require("path");
7
+ var express = require("express");
8
+ var compression = require("compression");
9
+ var sockjs = require('sockjs');
10
+ var sockets = {};
11
+ RED.log.info("Worldmap version " + require('./package.json').version );
12
+ // add the cgi module for serving local maps.... only if mapserv exists
13
+ if (fs.existsSync((__dirname + '/mapserv'))) {
14
+ RED.httpNode.use("/cgi-bin/mapserv", require('cgi')(__dirname + '/mapserv'));
15
+ }
16
+
17
+ function worldMap(node, n) {
18
+ var allPoints = {};
19
+ RED.nodes.createNode(node,n);
20
+ node.lat = n.lat || "";
21
+ node.lon = n.lon || "";
22
+ node.zoom = n.zoom || "";
23
+ node.layer = n.layer || "";
24
+ node.cluster = n.cluster || "";
25
+ node.maxage = n.maxage || "";
26
+ node.showmenu = n.usermenu || "show";
27
+ node.layers = n.layers || "show";
28
+ node.panlock = n.panlock || "false";
29
+ node.zoomlock = n.zoomlock || "false";
30
+ node.panit = n.panit || "false";
31
+ node.hiderightclick = n.hiderightclick || "false";
32
+ node.coords = n.coords || "none";
33
+ node.showgrid = n.showgrid || "false";
34
+ node.showruler = n.showruler || "false";
35
+ node.allowFileDrop = n.allowFileDrop || "false";
36
+ node.path = n.path || "/worldmap";
37
+ node.maplist = n.maplist;
38
+ node.overlist = n.overlist;
39
+ node.mapname = n.mapname || "";
40
+ node.mapurl = n.mapurl || "";
41
+ node.mapopt = n.mapopt || "";
42
+ node.mapwms = n.mapwms || false;
43
+ if (n.maplist === undefined) { node.maplist = "OSMG,OSMC,EsriC,EsriS,EsriT,EsriDG,UKOS,SW"; }
44
+ if (n.overlist === undefined) { node.overlist = "DR,CO,RA,DN,HM"; }
45
+ try { node.mapopt2 = JSON.parse(node.mapopt); }
46
+ catch(e) { node.mapopt2 = null; }
47
+
48
+ if (node.path.charAt(0) != "/") { node.path = "/" + node.path; }
49
+ if (!sockets[node.path]) {
50
+ var libPath = path.posix.join(RED.settings.httpNodeRoot, node.path, 'leaflet', 'sockjs.min.js');
51
+ var sockPath = path.posix.join(RED.settings.httpNodeRoot,node.path,'socket');
52
+ sockets[node.path] = sockjs.createServer({prefix:sockPath, sockjs_url:libPath, log:function(s,e) { return; }});
53
+ sockets[node.path].installHandlers(RED.server);
54
+ sockets[node.path].on('error', function(e) { node.error("Socket Connection Error: "+e.stack); });
55
+ }
56
+ //node.log("Serving "+__dirname+" as "+node.path);
57
+ node.log("started at "+node.path);
58
+ var clients = {};
59
+ RED.httpNode.get("/-worldmap3d-key", RED.auth.needsPermission('worldmap3d.read'), function(req, res) {
60
+ if (process.env.MAPBOXGL_TOKEN) {
61
+ res.send({key:process.env.MAPBOXGL_TOKEN});
62
+ }
63
+ else {
64
+ node.error("No API key set");
65
+ res.send({key:''})
66
+ }
67
+ });
68
+ RED.httpNode.use(compression());
69
+ RED.httpNode.use(node.path, express.static(__dirname + '/worldmap'));
70
+ // RED.httpNode.use(node.path, express.static(__dirname + '/worldmap', {maxage:3600000}));
71
+
72
+ var callback = function(client) {
73
+ if (!client.headers.hasOwnProperty("user-agent")) { client.close(); }
74
+ //client.setMaxListeners(0);
75
+ clients[client.id] = client;
76
+ client.on('data', function(message) {
77
+ message = JSON.parse(message);
78
+ if (message.action === "connected") {
79
+ var m = {};
80
+ var c = {init:true};
81
+ c.maplist = node.maplist;
82
+ c.overlist = node.overlist;
83
+ if (node.layer && node.layer == "Custom") {
84
+ m.name = node.mapname;
85
+ m.url = node.mapurl;
86
+ m.opt = node.mapopt2;
87
+ if (node.mapwms === true) { m.wms = true; }
88
+ client.write(JSON.stringify({command:{map:m}}));
89
+ c.layer = m.name;
90
+ }
91
+ else {
92
+ if (node.layer && node.layer.length > 0) { c.layer = node.layer; }
93
+ }
94
+ if (node.lat && node.lat.length > 0) { c.lat = node.lat; }
95
+ if (node.lon && node.lon.length > 0) { c.lon = node.lon; }
96
+ if (node.zoom && node.zoom.length > 0) { c.zoom = node.zoom; }
97
+ if (node.cluster && node.cluster.length > 0) { c.cluster = node.cluster; }
98
+ if (node.maxage && node.maxage.length > 0) { c.maxage = node.maxage; }
99
+ c.showmenu = node.showmenu;
100
+ c.panit = node.panit;
101
+ c.panlock = node.panlock;
102
+ c.zoomlock = node.zoomlock;
103
+ c.showlayers = node.layers;
104
+ c.grid = {showgrid:node.showgrid};
105
+ c.ruler = {showruler:node.showruler};
106
+ c.hiderightclick = node.hiderightclick;
107
+ c.allowFileDrop = node.allowFileDrop;
108
+ c.coords = node.coords;
109
+ if (node.name) { c.toptitle = node.name; }
110
+ //console.log("INIT",c)
111
+ client.write(JSON.stringify({command:c}));
112
+ var o = Object.values(allPoints);
113
+ o.map(v => delete v.tout);
114
+ setTimeout(function() { client.write(JSON.stringify(o)) }, 250);
115
+ }
116
+ });
117
+ client.on('close', function() {
118
+ delete clients[client.id];
119
+ node.status({fill:"green",shape:"ring",text:"connected "+Object.keys(clients).length,_sessionid:client.id});
120
+ });
121
+ node.status({fill:"green",shape:"dot",text:"connected "+Object.keys(clients).length,_sessionid:client.id});
122
+ }
123
+ node.on('input', function(msg) {
124
+ if (msg.hasOwnProperty("_sessionid")) {
125
+ if (clients.hasOwnProperty(msg._sessionid)) {
126
+ clients[msg._sessionid].write(JSON.stringify(msg.payload));
127
+ }
128
+ }
129
+ else {
130
+ for (var c in clients) {
131
+ if (clients.hasOwnProperty(c)) {
132
+ clients[c].write(JSON.stringify(msg.payload));
133
+ }
134
+ }
135
+ }
136
+ if (msg.payload.hasOwnProperty("name")) {
137
+ allPoints[msg.payload.name] = RED.util.cloneMessage(msg.payload);
138
+ var t = node.maxage || 3600;
139
+ if (msg.payload.ttl && msg.payload.ttl < t) { t = msg.payload.ttl; }
140
+ allPoints[msg.payload.name].tout = setTimeout( function() { delete allPoints[msg.payload.name] }, t * 1000 );
141
+ }
142
+ });
143
+ node.on("close", function() {
144
+ for (var c in clients) {
145
+ if (clients.hasOwnProperty(c)) {
146
+ clients[c].end();
147
+ }
148
+ }
149
+ clients = {};
150
+ sockets[node.path].removeListener('connection', callback);
151
+ for (var i=0; i < RED.httpNode._router.stack.length; i++) {
152
+ var r = RED.httpNode._router.stack[i];
153
+ if ((r.name === "serveStatic") && (r.regexp.test(node.path))) {
154
+ RED.httpNode._router.stack.splice(i, 1)
155
+ }
156
+ }
157
+ node.status({});
158
+ });
159
+ sockets[node.path].on('connection', callback);
160
+ }
161
+ var WorldMap = function(n) {
162
+ worldMap(this, n);
163
+ }
164
+ RED.nodes.registerType("worldmap",WorldMap);
165
+
166
+ function HTML(ui, config) {
167
+ var width = config.width;
168
+ if (width == 0) {
169
+ var group = RED.nodes.getNode(config.group);
170
+ if (group) { width = group.config.width; }
171
+ }
172
+ var height = config.height;
173
+ if (height == 0) { height = 10; }
174
+ var size = ui.getSizes();
175
+ var frameWidth = (size.sx + size.cx) * width - size.cx;
176
+ var frameHeight = (size.sy + size.cy) * height - size.cy;
177
+ var url = encodeURI(path.posix.join(RED.settings.httpNodeRoot||RED.settings.httpRoot,config.path));
178
+ if (config.layer === "MB3d") { url += "/index3d.html"; }
179
+ var html = `<style>.nr-dashboard-ui_worldmap{padding:0;}</style><div style="overflow:hidden;">
180
+ <iframe src="${url}" width="${frameWidth}px" height="${frameHeight}px" style="border:none;"></iframe></div>`;
181
+ return html;
182
+ }
183
+
184
+ function checkConfig(node, conf) {
185
+ if (!conf || !conf.hasOwnProperty("group")) {
186
+ node.error("no group");
187
+ return false;
188
+ }
189
+ return true;
190
+ }
191
+
192
+ var ui = undefined;
193
+ try {
194
+ ui = RED.require("node-red-dashboard")(RED);
195
+ }
196
+ catch(e) {
197
+ RED.log.info("Node-RED Dashboard not found - ui_worldmap not installed.");
198
+ }
199
+ setTimeout( function() {
200
+ if (ui) {
201
+ function UIWorldMap(config) {
202
+ try {
203
+ var node = this;
204
+ worldMap(node, config);
205
+ var done = null;
206
+ if (checkConfig(node, config)) {
207
+ var html = HTML(ui, config);
208
+ done = ui.addWidget({
209
+ node: node,
210
+ order: config.order,
211
+ group: config.group,
212
+ width: config.width,
213
+ height: config.height,
214
+ format: html,
215
+ templateScope: "local",
216
+ emitOnlyNewValues: false,
217
+ forwardInputMessages: false,
218
+ storeFrontEndInputAsState: false,
219
+ convertBack: function (value) {
220
+ return value;
221
+ },
222
+ beforeEmit: function(msg, value) {
223
+ return { msg: { items: value } };
224
+ },
225
+ beforeSend: function (msg, orig) {
226
+ if (orig) { return orig.msg; }
227
+ },
228
+ initController: function($scope, events) {
229
+ }
230
+ });
231
+ }
232
+ }
233
+ catch (e) {
234
+ console.log(e);
235
+ }
236
+ node.on("close", function() {
237
+ if (done) { done(); }
238
+ });
239
+ }
240
+ setImmediate(function() { RED.nodes.registerType("ui_worldmap", UIWorldMap) });
241
+ }
242
+ }, 100);
243
+
244
+
245
+ var WorldMapIn = function(n) {
246
+ RED.nodes.createNode(this,n);
247
+ this.path = n.path || "/worldmap";
248
+ this.events = n.events || "connect,disconnect,point,bounds,files,draw,other";
249
+ if (this.path.charAt(0) != "/") { this.path = "/" + this.path; }
250
+ if (!sockets[this.path]) {
251
+ var libPath = path.posix.join(RED.settings.httpNodeRoot, this.path, 'leaflet', 'sockjs.min.js');
252
+ var sockPath = path.posix.join(RED.settings.httpNodeRoot,this.path,'socket');
253
+ sockets[this.path] = sockjs.createServer({prefix:sockPath, sockjs_url:libPath, log:function() { return; }});
254
+ sockets[this.path].installHandlers(RED.server);
255
+ }
256
+ var node = this;
257
+ var clients = {};
258
+
259
+ var callback = function(client) {
260
+ //client.setMaxListeners(0);
261
+ clients[client.id] = client;
262
+ //get ip of user connected to the _sessionid, check to see if its proxied first
263
+ var sessionip = client.headers['x-real-ip'] || client.headers['x-forwarded-for'] || client.remoteAddress;
264
+ node.status({fill:"green",shape:"dot",text:"connected "+Object.keys(clients).length,_sessionid:client.id});
265
+ client.on('data', function(message) {
266
+ message = JSON.parse(message);
267
+ if (message.hasOwnProperty("action")) {
268
+ if ((node.events.indexOf("connect")!==-1) && (message.action === "connected")) {
269
+ setImmediate(function() {node.send({payload:message, topic:node.path.substr(1), _sessionid:client.id, _sessionip:sessionip})});
270
+ }
271
+ if ((node.events.indexOf("bounds")!==-1) && (message.action === "bounds")) {
272
+ setImmediate(function() {node.send({payload:message, topic:node.path.substr(1), _sessionid:client.id, _sessionip:sessionip})});
273
+ }
274
+ if ((node.events.indexOf("point")!==-1) && ((message.action === "point")||(message.action === "move")||(message.action === "delete") )) {
275
+ setImmediate(function() {node.send({payload:message, topic:node.path.substr(1), _sessionid:client.id, _sessionip:sessionip})});
276
+ }
277
+ if ((node.events.indexOf("layer")!==-1) && (message.action.indexOf("layer") !== -1) ) {
278
+ setImmediate(function() {node.send({payload:message, topic:node.path.substr(1), _sessionid:client.id, _sessionip:sessionip})});
279
+ }
280
+ if ((node.events.indexOf("files")!==-1) && (message.action === "file")) {
281
+ message.content = Buffer.from(message.content.split('base64,')[1], 'base64');
282
+ setImmediate(function() {node.send({payload:message, topic:node.path.substr(1), _sessionid:client.id, _sessionip:sessionip})});
283
+ }
284
+ if ((node.events.indexOf("draw")!==-1) && (message.action === "draw")) {
285
+ setImmediate(function() {node.send({payload:message, topic:node.path.substr(1), _sessionid:client.id, _sessionip:sessionip})});
286
+ }
287
+ if (node.events.indexOf("other")!==-1 && "connected,point,delete,move,draw,files,bounds".indexOf(message.action) === -1) {
288
+ setImmediate(function() {node.send({payload:message, topic:node.path.substr(1), _sessionid:client.id, _sessionip:sessionip})});
289
+ }
290
+ }
291
+ });
292
+ client.on('close', function() {
293
+ delete clients[client.id];
294
+ node.status({fill:"green",shape:"ring",text:"connected "+Object.keys(clients).length,_sessionid:client.id});
295
+ if (node.events.indexOf("disconnect")!==-1) {
296
+ node.send({payload:{action:"disconnect", clients:Object.keys(clients).length}, topic:node.path.substr(1), _sessionid:client.id, _sessionip:sessionip});
297
+ }
298
+ });
299
+ }
300
+
301
+ node.on("close", function() {
302
+ for (var c in clients) {
303
+ if (clients.hasOwnProperty(c)) {
304
+ clients[c].end();
305
+ }
306
+ }
307
+ clients = {};
308
+ sockets[this.path].removeListener('connection', callback);
309
+ node.status({});
310
+ });
311
+ sockets[this.path].on('connection', callback);
312
+ }
313
+ RED.nodes.registerType("worldmap in",WorldMapIn);
314
+
315
+
316
+ var WorldMapTracks = function(n) {
317
+ RED.nodes.createNode(this,n);
318
+ this.depth = parseInt(Number(n.depth) || 20);
319
+ this.pointsarray = {};
320
+ this.layer = n.layer || "combined"; // separate, single
321
+ this.smooth = n.smooth || false;
322
+ var node = this;
323
+ var bezierSpline = require("@turf/bezier-spline").default;
324
+
325
+ var doTrack = function(msg) {
326
+ if (msg.hasOwnProperty("payload") && msg.payload.hasOwnProperty("name")) {
327
+ var newmsg = RED.util.cloneMessage(msg);
328
+ if (msg.payload.deleted) {
329
+ if (msg.payload.name.substr(-1) === '_') {
330
+ var a = node.pointsarray[msg.payload.name.substr(0,msg.payload.name.length-1)].pop();
331
+ node.pointsarray[msg.payload.name.substr(0,msg.payload.name.length-1)] = [ a ];
332
+ node.send(newmsg);
333
+ }
334
+ else {
335
+ delete node.pointsarray[msg.payload.name];
336
+ }
337
+ //newmsg.payload.name = msg.payload.name + "_";
338
+ node.send(newmsg);
339
+ return;
340
+ }
341
+ if (!msg.payload.hasOwnProperty("lat") || !msg.payload.hasOwnProperty("lon")) { return; }
342
+ if (!node.pointsarray.hasOwnProperty(msg.payload.name)) {
343
+ node.pointsarray[msg.payload.name] = [];
344
+ }
345
+ if (msg.payload.hasOwnProperty("trackpoints") && !isNaN(parseInt(msg.payload.trackpoints)) ) {
346
+ var tl = parseInt(msg.payload.trackpoints);
347
+ if (tl < 0) { tl = 0; }
348
+ if (node.pointsarray[msg.payload.name].length > tl) {
349
+ node.pointsarray[msg.payload.name] = node.pointsarray[msg.payload.name].slice(-tl);
350
+ }
351
+ node.depth = tl;
352
+ }
353
+ if (node.depth < 2) { return; } // if set less than 2 then don't bother.
354
+
355
+ var still = false;
356
+ if (node.pointsarray[msg.payload.name].length > 0) {
357
+ var oldlat = node.pointsarray[msg.payload.name][node.pointsarray[msg.payload.name].length-1].lat;
358
+ var oldlon = node.pointsarray[msg.payload.name][node.pointsarray[msg.payload.name].length-1].lon;
359
+ if (msg.payload.lat === oldlat && msg.payload.lon === oldlon) { still = true; }
360
+ }
361
+ if (!still) { node.pointsarray[msg.payload.name].push(msg.payload);
362
+ if (node.pointsarray[msg.payload.name].length > node.depth) {
363
+ node.pointsarray[msg.payload.name].shift();
364
+ }
365
+ }
366
+ var line = [];
367
+ for (var i=0; i<node.pointsarray[msg.payload.name].length; i++) {
368
+ var m = node.pointsarray[msg.payload.name][i];
369
+ if (m.hasOwnProperty("lat") && m.hasOwnProperty("lon")) {
370
+ line.push( [m.lat*1, m.lon*1] );
371
+ delete newmsg.payload.lat;
372
+ delete newmsg.payload.lon;
373
+ }
374
+ if (m.hasOwnProperty("latitude") && m.hasOwnProperty("longitude")) {
375
+ line.push( [m.latitude*1, m.longitude*1] );
376
+ delete newmsg.payload.latitude;
377
+ delete newmsg.payload.longitude;
378
+ }
379
+ if (m.hasOwnProperty("position") && m.position.hasOwnProperty("lat") && m.position.hasOwnProperty("lon")) {
380
+ line.push( [m.position.lat*1, m.position.lon*1] );
381
+ delete newmsg.payload.position;
382
+ }
383
+ }
384
+ if (line.length > 1) { // only send track if two points or more
385
+ if (node.smooth) {
386
+ var curved = bezierSpline({"type":"Feature", "properties":{}, "geometry":{"type":"LineString", "coordinates":line }});
387
+ newmsg.payload.line = curved.geometry.coordinates;
388
+ }
389
+ else {
390
+ newmsg.payload.line = line;
391
+ }
392
+ newmsg.payload.name = msg.payload.name + "_";
393
+ if (node.layer === "separate") {
394
+ newmsg.payload.layer = msg.payload.layer + " tracks";
395
+ if (newmsg.payload.layer.indexOf('_') === 0) {
396
+ newmsg.payload.layer = newmsg.payload.layer.substr(1);
397
+ }
398
+ }
399
+ if (node.layer === "single") {
400
+ newmsg.payload.layer = "Tracks";
401
+ }
402
+ node.send(newmsg); // send the track
403
+ }
404
+ }
405
+ if (msg.hasOwnProperty("payload") && msg.payload.hasOwnProperty("command") && msg.payload.command.hasOwnProperty("clear")) {
406
+ for (var p in node.pointsarray) {
407
+ if (node.pointsarray.hasOwnProperty(p)) {
408
+ if (node.pointsarray[p][0].layer === msg.payload.command.clear) {
409
+ delete node.pointsarray[p];
410
+ }
411
+ }
412
+ }
413
+ }
414
+ }
415
+
416
+ node.on("input", function(m) {
417
+ if (Array.isArray(m.payload)) {
418
+ m.payload.forEach(function (pay) {
419
+ var n = RED.util.cloneMessage(m)
420
+ n.payload = pay;
421
+ doTrack(n);
422
+ });
423
+ }
424
+ else {
425
+ doTrack(m);
426
+ }
427
+ });
428
+
429
+ node.on("close", function() {
430
+ node.pointsarray = {};
431
+ });
432
+ }
433
+ RED.nodes.registerType("worldmap-tracks",WorldMapTracks);
434
+
435
+
436
+ var WorldMapHull = function(n) {
437
+ RED.nodes.createNode(this,n);
438
+ this.prop = n.prop || "layer";
439
+ var node = this;
440
+ node.oldlayercount = {};
441
+ node.hulls = {};
442
+
443
+ var convexHull = function(points) {
444
+ var arr = [];
445
+ for (const val of Object.values(points)) {
446
+ arr.push(val);
447
+ }
448
+
449
+ arr.sort(function (a, b) {
450
+ return a.lat != b.lat ? a.lat - b.lat : a.lon - b.lon;
451
+ });
452
+
453
+ var n = arr.length;
454
+ var hull = [];
455
+
456
+ for (var i = 0; i < 2 * n; i++) {
457
+ var j = i < n ? i : 2 * n - 1 - i;
458
+ while (hull.length >= 2 && removeMiddle(hull[hull.length - 2], hull[hull.length - 1], arr[j]))
459
+ hull.pop();
460
+ hull.push(arr[j]);
461
+ }
462
+
463
+ hull.pop();
464
+ return hull;
465
+ }
466
+
467
+ var removeMiddle = function(a, b, c) {
468
+ var cross = (a.lat- b.lat) * (c.lon - b.lon) - (a.lon - b.lon) * (c.lat- b.lat);
469
+ var dot = (a.lat- b.lat) * (c.lat- b.lat) + (a.lon - b.lon) * (c.lon - b.lon);
470
+ return cross < 0 || cross == 0 && dot <= 0;
471
+ }
472
+
473
+ var doHull = function(msg) {
474
+ if (msg.hasOwnProperty("payload") && msg.payload.hasOwnProperty("name")) {
475
+ var newmsg = RED.util.cloneMessage(msg);
476
+ newmsg.payload = {};
477
+ newmsg.payload[node.prop] = msg.payload[node.prop] || "unknown";
478
+ if (msg.payload.deleted === true) {
479
+ if (node.hulls.hasOwnProperty(newmsg.payload[node.prop])) {
480
+ delete node.hulls[newmsg.payload[node.prop]][msg.payload.name];
481
+ }
482
+ }
483
+ else {
484
+ if (!msg.payload.hasOwnProperty("lat") || !msg.payload.hasOwnProperty("lon")) { return; }
485
+ if (!node.hulls.hasOwnProperty(newmsg.payload[node.prop])) {
486
+ node.hulls[newmsg.payload[node.prop]] = {};
487
+ }
488
+ node.hulls[newmsg.payload[node.prop]][msg.payload.name] = {lat:msg.payload.lat,lon:msg.payload.lon};
489
+ }
490
+ var convexHullPoints = convexHull(node.hulls[newmsg.payload[node.prop]]);
491
+ var leafletHull = convexHullPoints.map(function (element) {return ([element.lat,element.lon])})
492
+
493
+ newmsg.payload.name = newmsg.payload[node.prop];
494
+ newmsg.payload.clickable = true;
495
+
496
+ if (msg.payload.fillColor) {
497
+ newmsg.payload.color = msg.payload.fillColor;
498
+ newmsg.payload.fillColor = msg.payload.fillColor;
499
+ }
500
+
501
+ if (node.oldlayercount[newmsg.payload[node.prop]] === undefined) {
502
+ node.oldlayercount[newmsg.payload[node.prop]] = 0;
503
+ }
504
+ var oldl = node.oldlayercount[newmsg.payload[node.prop]];
505
+
506
+ if (leafletHull.length === 1 && oldl === 2) {
507
+ newmsg.payload.deleted = true;
508
+ node.send(newmsg);
509
+ }
510
+ if (leafletHull.length === 2 && (oldl === 1 || oldl === 3)) {
511
+ var newmsg2 = RED.util.cloneMessage(newmsg);
512
+ newmsg2.payload.deleted = true;
513
+ node.send(newmsg2);
514
+ newmsg.payload.line = leafletHull;
515
+ node.send(newmsg);
516
+ }
517
+ if (leafletHull.length === 3 && oldl === 2) {
518
+ var newmsg3 = RED.util.cloneMessage(newmsg);
519
+ newmsg3.payload.deleted = true;
520
+ node.send(newmsg3);
521
+ }
522
+ if (leafletHull.length >= 3) {
523
+ newmsg.payload.area = leafletHull;
524
+ node.send(newmsg);
525
+ }
526
+
527
+ node.oldlayercount[newmsg.payload[node.prop]] = leafletHull.length;
528
+ }
529
+ }
530
+
531
+ node.on("input", function(m) {
532
+ if (Array.isArray(m.payload)) {
533
+ m.payload.forEach(function (pay) {
534
+ var n = RED.util.cloneMessage(m)
535
+ n.payload = pay;
536
+ doHull(n);
537
+ });
538
+ }
539
+ else {
540
+ doHull(m);
541
+ }
542
+ });
543
+
544
+ node.on("close", function() {
545
+ node.hulls = {};
546
+ });
547
+ }
548
+ RED.nodes.registerType("worldmap-hull",WorldMapHull);
549
+
550
+ RED.httpAdmin.get("/-ui-worldmap", RED.auth.needsPermission('rpi-ui-worldmap.read'), function(req, res) {
551
+ res.send(ui ? "true": "false");
552
+ });
553
+ }