L.Control.AutoUpdate = L.Control.extend({ options: { position: 'topleft', label: 'Automatic update', layer: undefined }, pressed: true, onAdd: function() { var container = L.DomUtil.create('div', 'leaflet-bar leaflet-control'); this.link = L.DomUtil.create('a', 'leaflet-bar-part', container); this.iconStart = L.DomUtil.create('i', 'fa fa-play', this.link); this.link.href = '#'; L.DomEvent.on(this.link, 'click', this.cbClick, this); return container; }, cbClick: function (e) { L.DomEvent.stopPropagation(e); this.intendedFunction(this.pressed); if (this.pressed) { this.pressed = false; this.iconStart.setAttribute('class', 'fa fa-pause'); this.autoUpdate(); } else { this.pressed = true; this.iconStart.setAttribute('class', 'fa fa-play'); this.stopUpdate(); } }, intendedFunction: function() { alert('no function selected'); }, stopUpdate: function() { this.socket.close(); }, autoUpdate: function() { var me = this; this.socket = new WebSocket('ws://' + window.location.host + '/ws'); this.socket.onmessage = function(evt) { var updatePlayers = function(json) { if (!(typeof json === "string")) { return; } var players; try { players = JSON.parse(json); } catch (err) { return; } if (players.players) { me.options.layer.clearLayers(); me.options.layer.addData(players.players); } }(evt.data); var invalidate = function(json) { var invalidateAll = function(x, y, z) { return true; }; if (!(typeof json === "string")) { return invalidateAll; } var tiles; var tileData; try { var tileData = JSON.parse(json); } catch (err) { return invalidateAll; } if (!tileData.tiles) { return invalidateAll; } tiles = tileData.tiles; var pyramid = new Array(9); var last = new Object(); pyramid[8] = last; for (var i = 0; i < tiles.length; i++) { var xz = tiles[i]; last[xz.X + "#" + xz.Z] = xz; } for (var p = 7; p >= 0; p--) { var prev = pyramid[p+1]; var curr = new Object(); pyramid[p] = curr; for (var k in prev) { if (prev.hasOwnProperty(k)) { var oxz = prev[k]; var nxz = { X: oxz.X >> 1, Z: oxz.Z >> 1 }; curr[nxz.X + "#" + nxz.Z] = nxz; } } } return function(x, y, z) { if (y > 8) { x >>= y - 8; z >>= y - 8; y = 8; } var level = pyramid[y]; var k = x + "#" + z; return level.hasOwnProperty(k); }; } (evt.data); var tiles = document.getElementsByTagName('img'); var re = /\/map\/([0-9]+)\/([0-9]+)\/([0-9]+).*/; for (var i = 0; i < tiles.length; i++) { var img = tiles[i]; var cl = img.getAttribute('class'); if (!cl.contains('leaflet-tile-loaded')) { continue; } var src = img.src; var coord = src.match(re); if (coord == null) { continue; } var y = parseInt(coord[1]); var x = parseInt(coord[2]); var z = parseInt(coord[3]); if (invalidate(x, y, z)) { var idx = src.lastIndexOf('#'); if (idx >= 0) { src = src.substring(0, idx); } img.src = src + '#' + Math.random(); } } }; } }); L.autoUpdate = function(cbLabel, cbFunc, layer, cbMap) { var control = new L.Control.AutoUpdate(); if (cbLabel) { control.options.label = cbLabel; } if (cbFunc) { control.intendedFunction = cbFunc; } if (layer) { control.options.layer = layer; } if (cbMap === '') { return control; } else if (cbMap) { cbMap.addControl(control); } else { map.addControl(control); } return control; };