Difference between revisions of "Widget:SpaceAPI"
m (added (hidden) features parameter) |
(Added multiple beacon support, added popup (temperature, address, spacefed) + colored temperature polygons) |
||
Line 62: | Line 62: | ||
SpaceAPI.prototype._intervalId = null; | SpaceAPI.prototype._intervalId = null; | ||
SpaceAPI.prototype._node = null; | SpaceAPI.prototype._node = null; | ||
− | SpaceAPI.prototype. | + | SpaceAPI.prototype._leaflet = null; |
SpaceAPI.prototype._msgLoading = "Loading.."; | SpaceAPI.prototype._msgLoading = "Loading.."; | ||
SpaceAPI.prototype._msgError = "Error"; | SpaceAPI.prototype._msgError = "Error"; | ||
Line 122: | Line 122: | ||
srcNode.addEventListener( "load", function( _evt ) | srcNode.addEventListener( "load", function( _evt ) | ||
{ | { | ||
− | this. | + | this._leaflet = {}; |
− | this. | + | this._leaflet.point = L.latLng( 50.8925,5.9713 ); |
− | this. | + | this._leaflet.map = L.map( mapNode ).setView( this._leaflet.point, 16); |
L.tileLayer('//{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { | L.tileLayer('//{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { | ||
attribution: '© <a href="//openstreetmap.org/copyright">OpenStreetMap</a> contributors' | attribution: '© <a href="//openstreetmap.org/copyright">OpenStreetMap</a> contributors' | ||
− | }).addTo( this. | + | }).addTo( this._leaflet.map ); |
// "Follow" control | // "Follow" control | ||
− | this. | + | this._leaflet.follow = null; |
L.Control.Command = L.Control.extend( | L.Control.Command = L.Control.extend( | ||
{ | { | ||
Line 142: | Line 142: | ||
{ | { | ||
var controlDiv = L.DomUtil.create( "div", "leaflet-bar" ); | var controlDiv = L.DomUtil.create( "div", "leaflet-bar" ); | ||
− | var controlUI = L.DomUtil.create( "a", "leaflet-clickable" + (this. | + | var controlUI = L.DomUtil.create( "a", "leaflet-clickable" + (this._leaflet.follow ? " toggle" : ""), controlDiv ); |
controlUI.innerHTML = "⌖"; | controlUI.innerHTML = "⌖"; | ||
controlUI.style.fontSize = "35px"; | controlUI.style.fontSize = "35px"; | ||
Line 149: | Line 149: | ||
L.DomEvent.addListener( controlUI, 'click', function( _evt ) | L.DomEvent.addListener( controlUI, 'click', function( _evt ) | ||
{ | { | ||
− | this. | + | this._leaflet.follow = !this._leaflet.follow; |
− | _evt.currentTarget.className = "leaflet-clickable" + (this. | + | _evt.currentTarget.className = "leaflet-clickable" + (this._leaflet.follow ? " toggle" : ""); |
// Update the map immediately | // Update the map immediately | ||
− | if ( this. | + | if ( this._leaflet.follow ) |
− | this. | + | { |
+ | // Determine the bounding box to 'follow | ||
+ | var bounds = L.latLngBounds( this._leaflet.beacons.map( function( _beacon ) | ||
+ | { | ||
+ | return _beacon.point; | ||
+ | } ) ); | ||
+ | if ( !this._leaflet.beacons.length ) | ||
+ | bounds.extend( this._leaflet.point ); | ||
+ | |||
+ | this._leaflet.map.fitBounds( bounds ); | ||
+ | } | ||
}.bind( this ) ); | }.bind( this ) ); | ||
Line 162: | Line 172: | ||
} ); | } ); | ||
− | this. | + | this._leaflet.map.addControl( new L.Control.Command() ); |
// Icons | // Icons | ||
− | this. | + | this._leaflet.icons = { |
"HoaB" : L.icon( { | "HoaB" : L.icon( { | ||
iconUrl: '//maps.google.com/intl/en_us/mapfiles/ms/micons/cycling.png', | iconUrl: '//maps.google.com/intl/en_us/mapfiles/ms/micons/cycling.png', | ||
Line 175: | Line 185: | ||
shadowAnchor: [16, 26] | shadowAnchor: [16, 26] | ||
} ) | } ) | ||
+ | }; | ||
+ | this._leaflet.descriptions = { | ||
+ | "HoaB" : "Hackers on a Bike" | ||
+ | }; | ||
+ | |||
+ | this._leaflet.marker = L.marker( this._leaflet.point ).addTo( this._leaflet.map ); | ||
+ | this._leaflet.beacons = []; | ||
+ | this._leaflet.temperatures = { | ||
+ | // outside | ||
+ | "28bd7a660500002f" : 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 | ||
+ | "28151767050000a0" : L.polygon( [[50.892458293019,5.971340775608], [50.892410920402,5.9713032246818], [50.892461676775,5.9711557031861], [50.892507357464,5.9711959363214]], {stroke:0,fillOpacity:0.8} ).addTo( this._leaflet.map ) | ||
+ | // hot zone | ||
+ | /*"288a13670500002a" : null*/ | ||
}; | }; | ||
− | |||
− | |||
}.bind( this ) ); | }.bind( this ) ); | ||
Line 187: | Line 209: | ||
// Update the space state immediately | // Update the space state immediately | ||
setTimeout( this._fetchState.bind( this ), 1 ); | setTimeout( this._fetchState.bind( this ), 1 ); | ||
+ | }; | ||
+ | SpaceAPI.prototype._determineColor = function( _temperature ) | ||
+ | { | ||
+ | var tempteratureColors = [ | ||
+ | [ -10, 0, 0, 0], // black | ||
+ | [ 0, 0, 0,255], // blue | ||
+ | [ 15, 255,255, 0], // yellow | ||
+ | [ 35, 255, 0, 0], // red | ||
+ | [ 45, 255,255,255], // white | ||
+ | [5000, 255,255,255] // white, blink | ||
+ | ]; | ||
+ | var index; | ||
+ | var ratio; | ||
+ | |||
+ | for ( var nTemp = tempteratureColors.length - 1; nTemp; nTemp-- ) | ||
+ | { | ||
+ | if ( _temperature >= tempteratureColors[ nTemp ][0] ) | ||
+ | break; | ||
+ | |||
+ | ratio = 0; | ||
+ | if ( index = nTemp ) | ||
+ | ratio = (_temperature - tempteratureColors[ nTemp - 1 ][0]) / ( tempteratureColors[ nTemp ][0] - tempteratureColors[ nTemp - 1 ][0] ); | ||
+ | } | ||
+ | |||
+ | var lo = tempteratureColors[ index ? index - 1 : 0 ]; | ||
+ | var hi = tempteratureColors[ index ]; | ||
+ | |||
+ | return "rgb("+Math.round( (lo[1] * (1 - ratio) + hi[1] * ratio) ) +","+Math.round( (lo[2] * (1 - ratio) + hi[2] * ratio))+","+Math.round( (lo[3] * (1 - ratio) + hi[3] * ratio))+")"; | ||
+ | }; | ||
+ | |||
+ | SpaceAPI.prototype._nlsTime = function( _time ) | ||
+ | { | ||
+ | var postfix; | ||
+ | |||
+ | if ( _time > 31556952 ) | ||
+ | { | ||
+ | _time /= 31556952; | ||
+ | postfix = "Year"; | ||
+ | } | ||
+ | else if ( _time > 2629746 ) | ||
+ | { | ||
+ | _time /= 2629746; | ||
+ | postfix = "Month"; | ||
+ | } | ||
+ | else if ( _time > 604800 ) | ||
+ | { | ||
+ | _time /= 604800; | ||
+ | postfix = "Week"; | ||
+ | } | ||
+ | else if ( _time > 86400 ) | ||
+ | { | ||
+ | _time /= 86400; | ||
+ | postfix = "day"; | ||
+ | } | ||
+ | else if ( _time > 3600 ) | ||
+ | { | ||
+ | _time /= 3600; | ||
+ | postfix = "hour"; | ||
+ | } | ||
+ | else if ( _time > 60 ) | ||
+ | { | ||
+ | _time /= 60; | ||
+ | postfix = "minute"; | ||
+ | } | ||
+ | else | ||
+ | { | ||
+ | postfix = "second"; | ||
+ | } | ||
+ | |||
+ | _time = Math.round( _time ); | ||
+ | return _time + " " + postfix + (_time !== 1 ? "s" : ""); | ||
}; | }; | ||
Line 262: | Line 355: | ||
this._updateState( message || this._msgUnknown, this._colorUnknown, title ); | this._updateState( message || this._msgUnknown, this._colorUnknown, title ); | ||
− | if ( this. | + | if ( this._leaflet ) |
{ | { | ||
+ | // Handle temperatures | ||
+ | if ( this.data.sensors && this.data.sensors.temperature && this.data.sensors.temperature.length ) | ||
+ | { | ||
+ | // Iterate the sensors and match a local sensor name | ||
+ | this.data.sensors.temperature.forEach( function( _apiTemp ) | ||
+ | { | ||
+ | var temp = this._leaflet.temperatures[ _apiTemp.name ]; | ||
+ | if ( temp ) | ||
+ | { | ||
+ | temp.setStyle({color: this._determineColor( _apiTemp.value )}); | ||
+ | |||
+ | var delta = (Date.now() - new Date( _apiTemp.ext_lastchange * 1000 )) / 1000; | ||
+ | temp.bindPopup( "Description: " + _apiTemp.description + "<br/>Location: " + _apiTemp.location + "Value: " + _apiTemp.value + _apiTemp.unit + "<br/>Last update: " + this._nlsTime( delta ) + " ago" ); | ||
+ | } | ||
+ | }, this ); | ||
+ | } | ||
+ | |||
+ | // 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 ) | ||
{ | { | ||
− | + | var bHoaB = false; | |
− | + | var beacons = this.data.sensors.beacon.map( function( _apiBeacon ) | |
− | + | { | |
+ | var beacon = {}; | ||
+ | |||
+ | 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" ) ) | ||
+ | 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" ); | ||
+ | |||
+ | return beacon; | ||
+ | }, this ); | ||
− | + | // 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 ); | ||
+ | /* | ||
+ | for ( var b = 0; b < Math.min( this._leaflet.beacons.length, beacons, length ); b++ ) | ||
{ | { | ||
− | + | // Update position, icon, radius, tooltip | |
− | + | this._leaflet.beacons[ b ] | |
} | } | ||
− | + | */ | |
+ | this._leaflet.beacons = beacons; | ||
+ | |||
+ | // Only follow beacons automatically initially if there is a HoaB among it | ||
+ | if ( bHoaB && this._leaflet.follow === null ) | ||
{ | { | ||
− | + | this._leaflet.follow = true; | |
− | + | document.querySelector( "div.leaflet-bar > a.leaflet-clickable" ).className = "leaflet-clickable toggle"; | |
} | } | ||
− | + | } | |
− | + | ||
− | + | ||
− | + | // TODO: Update if coordinate is incorrect | |
− | + | if ( this._leaflet.follow === null ) | |
− | + | { | |
− | + | this._leaflet.follow = false; | |
− | + | ||
− | + | // Update location | |
− | + | this._leaflet.point = L.latLng( this.data.location.lat, this.data.location.lon ); | |
− | + | this._leaflet.marker.setLatLng( this._leaflet.point ); | |
− | + | ||
− | + | // Set popup data and open it | |
− | + | var popup = this._leaflet.marker.getPopup(); | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | var popup = this. | ||
if ( !popup ) | if ( !popup ) | ||
− | popup = this. | + | popup = this._leaflet.marker.bindPopup().getPopup(); |
− | + | var info = "<img src='" + this.data.logo + "'><br/>"; | |
+ | var l = this.data.location, s = this.data.spacefed; | ||
+ | info += l.address; | ||
− | + | if ( l.ext_floor ) | |
+ | info += ", floor " + l.ext_floor; | ||
+ | if ( l.ext_room ) | ||
+ | info += ", room " + l.ext_room; | ||
+ | info += "<br/>" + (s.spacenet ? "✔" : "❌") + ' <a target="blank" href="Spacenet">spacenet</a>'; | ||
+ | info += "<br/>" + (s.ext_spacenet5g ? "✔" : "❌") + " spacenet (5GHz)"; | ||
+ | info += "<br/>" + (s.spacesaml ? "✔" : "❌") + " spacesaml"; | ||
+ | info += "<br/>" + (s.ext_spaceconnect ? "✔" : "❌") + " spaceconnect"; | ||
+ | info += "<br/>" + (s.spacephone ? "✔" : "❌") + ' <a target="blank" href="Spacephone">spacephone</a>'; | ||
+ | if ( s.ext_spacephone_extension ) | ||
+ | info += ": +" + s.ext_spacephone_extension; | ||
+ | |||
+ | popup.setContent( info ); | ||
+ | |||
+ | this._leaflet.marker.openPopup(); | ||
+ | //popup.update(); | ||
} | } | ||
− | + | ||
+ | if ( this._leaflet.follow ) | ||
{ | { | ||
− | // | + | // Determine the bounding box to 'follow |
− | + | var bounds = L.latLngBounds( this._leaflet.beacons.map( function( _beacon ) | |
− | + | { | |
− | + | return _beacon.point; | |
− | this. | + | } ) ); |
+ | |||
+ | // If we don't have Hackers on a Bike, include the home location together with the other beacons | ||
+ | if ( !bHoaB ) | ||
+ | bounds.extend( this._leaflet.point ); | ||
+ | |||
+ | this._leaflet.map.fitBounds( bounds ); | ||
} | } | ||
− | |||
− | |||
− | |||
− | |||
− | |||
} | } | ||
}; | }; | ||
Line 338: | Line 491: | ||
} | } | ||
} | } | ||
− | + | var state; | |
− | + | //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|escape:urlpathinfo}-->", <!--{$interval|validate:int|default:0}-->, "<!--{$features|escape:'quotes'}-->" ); | ||
state.start(); | state.start(); | ||
Revision as of 15:54, 15 March 2017
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=20px |padding=8px |interval=20 |float=right |features= }}
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.