Difference between revisions of "Widget:SpaceAPI"
m (step 2 of the line coordinates) |
m (Try and fix SpaceAPI popup alignment) |
||
(42 intermediate revisions by the same user not shown) | |||
Line 10: | Line 10: | ||
|url=/spaceAPI/ | |url=/spaceAPI/ | ||
|width=260px | |width=260px | ||
− | |height= | + | |height=300px |
|padding=8px | |padding=8px | ||
|interval=20 | |interval=20 | ||
|float=right | |float=right | ||
− | |features=beacon | + | |features=beacon,annex |
}}</nowiki> | }}</nowiki> | ||
This will give the following result:<br/> | This will give the following result:<br/> | ||
{{#widget:{{PAGENAME}} | {{#widget:{{PAGENAME}} | ||
− | |url=/spaceAPI/ | + | |url=/spaceAPI/?beacon_log=HoT |
|width=260px | |width=260px | ||
− | |height= | + | |height=300px |
|padding=8px | |padding=8px | ||
|interval=20 | |interval=20 | ||
|float=right | |float=right | ||
− | |features=beacon | + | |features=beacon,annex |
}}<br/> | }}<br/> | ||
'''Notes''' | '''Notes''' | ||
Line 82: | Line 82: | ||
SpaceAPI.prototype._colorUnknown = "#f70"; | SpaceAPI.prototype._colorUnknown = "#f70"; | ||
SpaceAPI.prototype._debug = null; | SpaceAPI.prototype._debug = null; | ||
+ | |||
+ | SpaceAPI.prototype._drawBeaconPolyLine = function( ) | ||
+ | { | ||
+ | if ( !this.data.sensors || !this.data.sensors.beacon || this.data.sensors.beacon.length < 50 ) | ||
+ | return; | ||
+ | |||
+ | var points = []; | ||
+ | var bounds = this._leaflet.map.getBounds(); | ||
+ | |||
+ | // Only add points within the bounds | ||
+ | if ( this._leaflet.beaconCount !== this.data.sensors.beacon.length ) | ||
+ | { | ||
+ | this._leaflet.beaconCount = this.data.sensors.beacon.length; | ||
+ | for ( var n = 0, len = this.data.sensors.beacon.length; n < len; ++n ) | ||
+ | { | ||
+ | var point = L.latLng( this.data.sensors.beacon[n].location.lat, this.data.sensors.beacon[n].location.lon ); | ||
+ | points.push( point ); | ||
+ | } | ||
+ | |||
+ | if ( !this._leaflet.beaconline ) | ||
+ | this._leaflet.beaconline = L.polyline(points, {color: 'green'}).addTo( this._leaflet.map ); | ||
+ | else | ||
+ | this._leaflet.beaconline.setLatLngs( points ); | ||
+ | } | ||
+ | }; | ||
SpaceAPI.prototype.start = function( ) | SpaceAPI.prototype.start = function( ) | ||
Line 101: | Line 126: | ||
} | } | ||
node.style.width = this._width; | node.style.width = this._width; | ||
+ | node.style.height = this._height; | ||
+ | |||
node.style.textAlign = "center"; | node.style.textAlign = "center"; | ||
node.style.BoxShadow = "3px 3px 4px rgba(0,0,0,0.2)"; | node.style.BoxShadow = "3px 3px 4px rgba(0,0,0,0.2)"; | ||
Line 111: | Line 138: | ||
this._node.style.display = "block"; | this._node.style.display = "block"; | ||
this._node.style.color = "inherit"; | this._node.style.color = "inherit"; | ||
− | |||
this._node.style.padding = this._padding; | this._node.style.padding = this._padding; | ||
this._node.textContent = this._msgLoading; | this._node.textContent = this._msgLoading; | ||
Line 121: | Line 147: | ||
var mapNode = node.appendChild( document.createElement( "div" ) ); | var mapNode = node.appendChild( document.createElement( "div" ) ); | ||
mapNode.style.width = "100%"; | mapNode.style.width = "100%"; | ||
− | mapNode.style.height = " | + | mapNode.style.height = "calc(" + this._height + " + " + this._padding + " - 2em)"; |
srcNode = document.createElement( "link" ); | srcNode = document.createElement( "link" ); | ||
Line 138: | Line 164: | ||
this._leaflet = {}; | this._leaflet = {}; | ||
this._leaflet.point = L.latLng( 50.8925,5.9713 ); | this._leaflet.point = L.latLng( 50.8925,5.9713 ); | ||
− | this._leaflet.map = L.map( mapNode ).setView( this._leaflet.point, 16); | + | this._leaflet.map = L.map( mapNode ).panTo( this._leaflet.point ); |
+ | //this._leaflet.map = L.map( mapNode ).setView( this._leaflet.point, 16); | ||
L.CRS.CustomZoom = L.extend({}, L.CRS.EPSG3857, | L.CRS.CustomZoom = L.extend({}, L.CRS.EPSG3857, | ||
Line 276: | Line 303: | ||
maxZoom: 28 | maxZoom: 28 | ||
} ).addTo( this._leaflet.map ); | } ).addTo( this._leaflet.map ); | ||
+ | |||
+ | this._leaflet.map.on('moveend', function( _event ) | ||
+ | { | ||
+ | //this._drawBeaconPolyLine( _event ); | ||
+ | |||
+ | }, this ); | ||
this._leaflet.map.on('zoomend', function( _event ) | this._leaflet.map.on('zoomend', function( _event ) | ||
Line 293: | Line 326: | ||
*/ | */ | ||
− | if ( !this._leaflet.temperatures[" | + | |
+ | //this._drawBeaconPolyLine( _event ); | ||
+ | |||
+ | |||
+ | if ( !this._leaflet.temperatures["000005667ABD"] ) | ||
return; | return; | ||
Line 299: | Line 336: | ||
if ( z > 17 ) | if ( z > 17 ) | ||
o = Math.max( (23-z) / 5, 0 ); | o = Math.max( (23-z) / 5, 0 ); | ||
− | this._leaflet.temperatures[" | + | this._leaflet.temperatures["000005667ABD"].setStyle( { fillOpacity: o } ); |
}, this ); | }, this ); | ||
Line 359: | Line 396: | ||
bounds.extend( this._leaflet.point ); | bounds.extend( this._leaflet.point ); | ||
− | this._leaflet.map.fitBounds( bounds ); | + | // Depending on polyline: don't zoom |
− | if ( this._leaflet.map.getZoom() > 18 ) | + | //this._leaflet.map.fitBounds( bounds ); |
− | this._leaflet.map.setZoom( 18 ); | + | //if ( this._leaflet.map.getZoom() > 18 ) |
+ | //this._leaflet.map.setZoom( 18 ); | ||
} | } | ||
}.bind( this ) ); | }.bind( this ) ); | ||
Line 379: | Line 417: | ||
popupAnchor: [0, -26], | popupAnchor: [0, -26], | ||
shadowUrl: '//maps.google.com/intl/en_us/mapfiles/ms/micons/cycling.shadow.png', | shadowUrl: '//maps.google.com/intl/en_us/mapfiles/ms/micons/cycling.shadow.png', | ||
+ | shadowSize: [59, 32], | ||
+ | shadowAnchor: [16, 26] | ||
+ | } ), | ||
+ | "HoT" : L.icon( { | ||
+ | iconUrl: '//maps.google.com/intl/en_us/mapfiles/ms/micons/bus.png', | ||
+ | iconSize: [32, 32], | ||
+ | iconAnchor: [16, 26], | ||
+ | popupAnchor: [0, -26], | ||
+ | shadowUrl: '//maps.google.com/intl/en_us/mapfiles/ms/micons/bus.shadow.png', | ||
shadowSize: [59, 32], | shadowSize: [59, 32], | ||
shadowAnchor: [16, 26] | shadowAnchor: [16, 26] | ||
Line 384: | Line 431: | ||
}; | }; | ||
this._leaflet.descriptions = { | this._leaflet.descriptions = { | ||
− | "HoaB" : "Hackers on a Bike" | + | "HoaB" : "Hackers on a Bike", |
+ | "HoT" : "Hackers on Tour" | ||
}; | }; | ||
Line 394: | Line 442: | ||
this._leaflet.temperatures = { | this._leaflet.temperatures = { | ||
// outside | // outside | ||
− | " | + | "000005671715" : L.polygon([[50.892537811238,5.9711101056338], [50.892517508729,5.9710966945888], [50.892534427487,5.9710564614536], [50.892715457818,5.9712093473674], [50.892696847256,5.9712790848018], [50.892808510518,5.9713836909534], [50.892788208127,5.9714373351337], [50.892774673195,5.9714319707157], [50.892681620427,5.971697509408], [50.892641015525,5.9716653228998], [50.892559805614,5.971893310666], [50.892569956861,5.9719120861291], [50.892559805614,5.9719496370554], [50.892377082796,5.9717940689325], [50.892399077248,5.9717189670801], [50.89233140198,5.9716545940637], [50.892350012689,5.9716009498835], [50.892326326331,5.9715794922114], [50.892414304169,5.9713032246828], [50.892458293026,5.971340775609]], {stroke:0,fillOpacity:0.8} ).addTo( this._leaflet.map ), |
// cold zone | // cold zone | ||
− | " | + | "000005667ABD" : L.polygon( [[50.892458293019,5.971340775608], [50.892410920402,5.9713032246818], [50.8924743319376, 5.9711186739150435], [50.89251872057557, 5.97115655487869]], {stroke:0,fillOpacity:0.8} ).addTo( this._leaflet.map ), |
// barbecue | // barbecue | ||
− | "DEADBEEF0" : L.circle( [ 50.89277, 5.97134 ], 1, {stroke:0,fillOpacity:0.8} ).addTo( this._leaflet.map ) | + | "DEADBEEF0" : L.circle( [ 50.89277, 5.97134 ], 1, {stroke:0,fillOpacity:0.8} ).addTo( this._leaflet.map ), |
// hot zone | // hot zone | ||
− | + | "00000567138A" : L.circle( [ 50.89250, 5.9711867 ], 2, {stroke:0,fillOpacity:0.8} ).addTo( this._leaflet.map ) | |
}; | }; | ||
Line 434: | Line 482: | ||
// Load the script | // Load the script | ||
( document.head || document.documentElement ).appendChild( srcNode ); | ( document.head || document.documentElement ).appendChild( srcNode ); | ||
− | } | + | } // beacon |
// Update the space state immediately | // Update the space state immediately | ||
Line 614: | Line 662: | ||
}, this ); | }, this ); | ||
} | } | ||
+ | |||
+ | var bounds = null; | ||
+ | var maxZoom = 18; | ||
// Handle beacons | // Handle beacons | ||
− | if ( this.data.sensors && this.data.sensors.beacon && this.data.sensors.beacon.length ) | + | if ( this.data.sensors && this.data.sensors.beacon && this.data.sensors.beacon.length < 25 ) |
{ | { | ||
var bHoaB = false; | var bHoaB = false; | ||
Line 630: | Line 681: | ||
// Closure variable | // Closure variable | ||
− | if ( ( delta < 3600 ) && ( _apiBeacon.name === "HoaB" ) ) | + | if ( ( delta < 3600 ) && ( _apiBeacon.name === "HoaB" || _apiBeacon.name === "HoT" ) ) |
bHoaB = true; | bHoaB = true; | ||
Line 671: | Line 722: | ||
} | } | ||
} | } | ||
+ | else if (this.data.sensors && this.data.sensors.beacon && this.data.sensors.beacon.length) | ||
+ | { | ||
+ | var apiBeacon = this.data.sensors.beacon[ 0 ]; | ||
+ | var beacon = {}; | ||
+ | var bHoaB = false; | ||
+ | |||
+ | beacon.point = L.latLng( apiBeacon.location.lat,apiBeacon.location.lon ); | ||
+ | beacon.marker = L.marker( beacon.point, { icon: this._leaflet.icons[ apiBeacon.name ] || new L.Icon.Default() } ).addTo( this._leaflet.map ); | ||
+ | beacon.circle = L.circle( beacon.point, apiBeacon.location.accuracy, {stroke:0} ).addTo( this._leaflet.map ); | ||
+ | |||
+ | var delta = (Date.now() - new Date( apiBeacon.ext_lastchange * 1000 )) / 1000; | ||
+ | |||
+ | // Closure variable | ||
+ | if ( ( delta < 3600 ) && ( apiBeacon.name === "HoaB" || apiBeacon.name === "HoT" ) ) | ||
+ | bHoaB = true; | ||
+ | |||
+ | if ( this._leaflet.icons[ apiBeacon.name ] ) | ||
+ | this._leaflet.icons[ apiBeacon.name ].options.className = delta > 60 ? "disconnected" : ""; | ||
+ | |||
+ | var popup = beacon.marker.getPopup(); | ||
+ | if ( !popup ) | ||
+ | popup = beacon.marker.bindPopup().getPopup(); | ||
+ | |||
+ | popup.setContent( ( this._leaflet.descriptions[ apiBeacon.name ] || apiBeacon.name ) + "<br/>Last update: " + this._nlsTime( delta ) + " ago" ); | ||
+ | |||
+ | // TODO: clean up old beacons!! | ||
+ | this._leaflet.beacons.forEach( function( _beacon ) | ||
+ | { | ||
+ | // Destroy popup | ||
+ | _beacon.marker.unbindPopup( ); | ||
+ | |||
+ | // Remove marker and circle | ||
+ | this._leaflet.map.removeLayer( _beacon.marker ); | ||
+ | this._leaflet.map.removeLayer( _beacon.circle ); | ||
+ | }, this ); | ||
+ | this._leaflet.beacons = [ beacon ]; | ||
+ | if ( bHoaB && this._leaflet.follow === null ) | ||
+ | { | ||
+ | this._leaflet.follow = true; | ||
+ | document.querySelector( "div.leaflet-bar > a.leaflet-clickable" ).className = "leaflet-clickable toggle"; | ||
+ | } | ||
+ | |||
+ | this._drawBeaconPolyLine( ); | ||
+ | |||
+ | maxZoom = 10; | ||
+ | } | ||
// TODO: Update if coordinate is incorrect | // TODO: Update if coordinate is incorrect | ||
Line 681: | Line 778: | ||
this._leaflet.point = L.latLng( this.data.location.lat, this.data.location.lon ); | this._leaflet.point = L.latLng( this.data.location.lat, this.data.location.lon ); | ||
this._leaflet.marker.setLatLng( this._leaflet.point ); | this._leaflet.marker.setLatLng( this._leaflet.point ); | ||
+ | this._leaflet.map.setZoom( 18 ); | ||
+ | |||
// Set popup data and open it | // Set popup data and open it | ||
Line 687: | Line 786: | ||
popup = this._leaflet.marker.bindPopup().getPopup(); | popup = this._leaflet.marker.bindPopup().getPopup(); | ||
− | var info = | + | var info = '<img src="' + this.data.logo + '" style="max-width:'+this._width+'px;width:100%"><br/>'; |
var l = this.data.location, s = this.data.spacefed; | var l = this.data.location, s = this.data.spacefed; | ||
info += l.address+"<br/>"; | info += l.address+"<br/>"; | ||
Line 695: | Line 794: | ||
if ( l.ext_room ) | if ( l.ext_room ) | ||
info += ", room " + l.ext_room; | info += ", room " + l.ext_room; | ||
− | info += "<br/>" + | + | info += "<br/>☎ " + '<a target="blank" href="tel:+'+this.data.contact.phone+'">+'+this.data.contact.phone+'</a>'; |
− | info += "<br/>" + (s.ext_spacenet5g | + | info += "<br/>" + this._tristate( s.spacenet ) + ' <a target="blank" href="Spacenet">spacenet</a>'; |
− | info += "<br/>" + (s.spacesaml | + | info += "<br/>" + this._tristate( s.ext_spacenet5g ) + " spacenet (5GHz)"; |
− | info += "<br/>" + (s.ext_spaceconnect | + | info += "<br/>" + this._tristate( s.spacesaml ) + " spacesaml"; |
− | info += "<br/>" + (s.spacephone | + | info += "<br/>" + this._tristate( s.ext_spaceconnect ) + " spaceconnect"; |
+ | info += "<br/>" + this._tristate( s.spacephone ) + ' <a target="blank" href="Spacephone">spacephone</a>'; | ||
if ( s.ext_spacephone_extension ) | if ( s.ext_spacephone_extension ) | ||
− | info += ": | + | info += ": E" + s.ext_spacephone_extension; |
popup.setContent( info ); | popup.setContent( info ); | ||
Line 712: | Line 812: | ||
{ | { | ||
// Determine the bounding box to 'follow | // Determine the bounding box to 'follow | ||
− | + | bounds = L.latLngBounds( this._leaflet.beacons.map( function( _beacon ) | |
{ | { | ||
return _beacon.point; | return _beacon.point; | ||
Line 721: | Line 821: | ||
bounds.extend( this._leaflet.point ); | bounds.extend( this._leaflet.point ); | ||
− | this._leaflet.map.fitBounds( bounds ); | + | // Disable zoom (in) if already zoomed beyond set max |
− | + | if ( this._leaflet.map.getZoom() > maxZoom ) | |
− | + | { | |
+ | this._leaflet.map.panTo( bounds.getCenter() ); | ||
+ | } | ||
+ | else | ||
+ | { | ||
+ | this._leaflet.map.fitBounds( bounds ); | ||
+ | if ( this._leaflet.map.getZoom() > maxZoom ) | ||
+ | this._leaflet.map.setZoom( maxZoom ); | ||
+ | } | ||
} | } | ||
+ | } // leaflet | ||
+ | |||
+ | if ( this._features.split(",").indexOf( "annex" ) >= 0 ) | ||
+ | { | ||
+ | var node = this._node; | ||
+ | [].forEach.call(document.querySelectorAll(".state.annex"),function(_n) | ||
+ | { | ||
+ | node.removeChild( _n ); | ||
+ | }); | ||
+ | |||
+ | (this.data.sensors&&this.data.sensors.service||[]).filter(function(_s) | ||
+ | { | ||
+ | return (_s.source==="annex" && _s.name!=="annex"); | ||
+ | }).forEach(function(_d,_i) | ||
+ | { | ||
+ | var anode = node.appendChild( document.createElement( "div" ) ); | ||
+ | anode.style.position = "absolute"; | ||
+ | anode.style.width = "0.4em"; | ||
+ | anode.style.height = "0.4em"; | ||
+ | anode.style.top = "calc(2em + 10px)"; | ||
+ | anode.style.right = (0.5 * _i) + "em"; | ||
+ | anode.style.backgroundColor = (_d.status|0)?"green":"red"; | ||
+ | anode.style.zIndex = 500; | ||
+ | anode.className = "state annex"; | ||
+ | var t = new Date( 0 ); | ||
+ | t.setUTCSeconds( _d.ext_lastchange ); | ||
+ | anode.title = _d.name + " (updated " + t.toLocaleString( )+")"; | ||
+ | }); | ||
} | } | ||
}; | }; | ||
+ | |||
+ | SpaceAPI.prototype._tristate = function( _state ) | ||
+ | { | ||
+ | if ( _state ) | ||
+ | return "✅"; | ||
+ | else if ( _state === null ) | ||
+ | return "❓"; | ||
+ | else | ||
+ | return "❌"; | ||
+ | } | ||
SpaceAPI.prototype._xhr_onerror = function( ) | SpaceAPI.prototype._xhr_onerror = function( ) | ||
Line 736: | Line 882: | ||
var state; | var state; | ||
//state = new SpaceAPI( "auto", "auto", "none", "8px-->", "//ackspace.nl/spaceAPI/", 15, "beacon" ); | //state = new SpaceAPI( "auto", "auto", "none", "8px-->", "//ackspace.nl/spaceAPI/", 15, "beacon" ); | ||
− | state = new SpaceAPI( "<!--{$width|escape:html|default:auto}-->", "<!--{$height|escape:html|default:auto}-->", "<!--{$float|escape:html|default:none}-->", "<!--{$padding|escape:html|default:8px}-->", "<!--{$url | + | state = new SpaceAPI( "<!--{$width|escape:html|default:auto}-->", "<!--{$height|escape:html|default:auto}-->", "<!--{$float|escape:html|default:none}-->", "<!--{$padding|escape:html|default:8px}-->", "<!--{$url}-->", <!--{$interval|validate:int|default:0}-->, "<!--{$features|escape:'quotes'}-->" ); |
state.start(); | state.start(); | ||
Latest revision as of 16:51, 24 April 2023
This widget allows you to display the Space API data (provided as JSON)
Created by Xopr
Using this widget
To insert this widget, use the following code:
{{#widget:SpaceAPI |url=/spaceAPI/ |width=260px |height=300px |padding=8px |interval=20 |float=right |features=beacon,annex }}
This will give the following result:
Notes
- url is mandatory, the rest is optional (leave out interval to make the data static).
- it also must be written without protocol since colon (:) is not allowed, and may be relative, for example: //ackspace.nl/spaceAPI/ or /spaceAPI/
- You must provide a unit for the sizes (i.e. px, %, etc.)
Copy to your site
To use this widget on your site, just install MediaWiki Widgets extension and copy full source code of this page to your wiki as Widget:SpaceAPI article.