Difference between revisions of "Widget:SpaceAPI"

From Hackerspace ACKspace
Jump to: navigation, search
m (added debug mode, shortened list)
(fixed popup width, added extra zoom levels, prevent too much zoom upon follow beacon, fixed space boundaries)
Line 38: Line 38:
 
(function( )
 
(function( )
 
{
 
{
    "use strict";
+
"use strict";
  
    if ( typeof SpaceAPI === "undefined" )
+
/*
    {
+
TODO:
        window.SpaceAPI = function( _width, _height, _float, _padding, _url, _interval, _features )
+
separate rooms (get latlng)
        {
+
zoom onto toolbox
            this._width = _width;
+
table island not correct (4, not 5 tables)
            this._height = _height;
+
            this._padding = _padding;
+
*/
            this._url = _url;
 
            this._interval = 1000 * _interval;
 
            this._float = _float;
 
            this._features = _features;
 
        }
 
  
        SpaceAPI.prototype.data            = null;
+
if ( typeof SpaceAPI === "undefined" )
        SpaceAPI.prototype._width          = null;
+
{
        SpaceAPI.prototype._height        = null;
+
window.SpaceAPI = function( _width, _height, _float, _padding, _url, _interval, _features )
        SpaceAPI.prototype._float          = null;
+
{
        SpaceAPI.prototype._url            = null;
+
this._width = _width;
        SpaceAPI.prototype._features      = null;
+
this._height = _height;
        SpaceAPI.prototype._interval       = null;
+
this._padding = _padding;
        SpaceAPI.prototype._intervalId    = null;
+
this._url = _url;
        SpaceAPI.prototype._node          = null;
+
this._interval = 1000 * _interval;
        SpaceAPI.prototype._leaflet        = null;
+
this._float = _float;
        SpaceAPI.prototype._msgLoading    = "Loading..";
+
this._features = _features;
        SpaceAPI.prototype._msgError      = "Error";
+
}
        SpaceAPI.prototype._msgParserError = "Failed to parse space state information";
 
        SpaceAPI.prototype._msgOpen        = "Open";
 
        SpaceAPI.prototype._msgClosed      = "Closed";
 
        SpaceAPI.prototype._msgUnknown    = "Unknown";
 
        SpaceAPI.prototype._msgSince      = "Since: ";
 
        SpaceAPI.prototype._colorOpen      = "#0f0";
 
        SpaceAPI.prototype._colorClosed    = "#f00";
 
        SpaceAPI.prototype._colorUnknown  = "#f70";
 
        SpaceAPI.prototype._debug    = null;
 
  
        SpaceAPI.prototype.start = function( )
+
SpaceAPI.prototype.data = null;
        {
+
SpaceAPI.prototype._width   = null;
            // Use interval timer id as image id
+
SpaceAPI.prototype._height = null;
 +
SpaceAPI.prototype._float   = null;
 +
SpaceAPI.prototype._url = null;
 +
SpaceAPI.prototype._features   = null;
 +
SpaceAPI.prototype._interval   = null;
 +
SpaceAPI.prototype._intervalId = null;
 +
SpaceAPI.prototype._node   = null;
 +
SpaceAPI.prototype._leaflet = null;
 +
SpaceAPI.prototype._msgLoading = "Loading..";
 +
SpaceAPI.prototype._msgError   = "Error";
 +
SpaceAPI.prototype._msgParserError = "Failed to parse space state information";
 +
SpaceAPI.prototype._msgOpen = "Open";
 +
SpaceAPI.prototype._msgClosed   = "Closed";
 +
SpaceAPI.prototype._msgUnknown = "Unknown";
 +
SpaceAPI.prototype._msgSince   = "Since: ";
 +
SpaceAPI.prototype._colorOpen   = "#0f0";
 +
SpaceAPI.prototype._colorClosed = "#f00";
 +
SpaceAPI.prototype._colorUnknown  = "#f70";
 +
SpaceAPI.prototype._debug   = null;
 +
 
 +
SpaceAPI.prototype.start = function( )
 +
{
 +
// Use interval timer id as image id
 
this._debug = ( location.hash.split("#").slice(1).indexOf("debug") !== -1 );
 
this._debug = ( location.hash.split("#").slice(1).indexOf("debug") !== -1 );
  
            this._intervalId = 0;
+
this._intervalId = 0;
            if ( this._interval > 0 )
+
if ( this._interval > 0 )
                this._intervalId = setInterval( this._fetchState.bind( this ), this._interval );
+
this._intervalId = setInterval( this._fetchState.bind( this ), this._interval );
  
            document.write( '<div id="spaceAPI' + this._intervalId + '"></div>' );
+
document.write( '<div id="spaceAPI' + this._intervalId + '"></div>' );
  
            var node = document.getElementById( "spaceAPI" + this._intervalId );
+
var node = document.getElementById( "spaceAPI" + this._intervalId );
            if ( !node )
+
if ( !node )
            {
+
{
                console && console.log( "node not found" );
+
console && console.log( "node not found" );
                return;
+
return;
            }
+
}
            node.style.width = this._width;
+
node.style.width = this._width;
            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)";
            node.style.position = "relative";
+
node.style.position = "relative";
  
            if ( this._float )
+
if ( this._float )
                node.style.float = this._float;
+
node.style.float = this._float;
  
            this._node = node.appendChild( document.createElement( "div" ) );
+
this._node = node.appendChild( document.createElement( "div" ) );
            this._node.style.height = this._height + "px";
+
this._node.style.height = this._height + "px";
            this._node.style.padding = this._padding;
+
this._node.style.padding = this._padding;
            this._node.textContent = this._msgLoading;
+
this._node.textContent = this._msgLoading;
  
            if ( this._features.split(",").indexOf( "beacon" ) >= 0 )
+
if ( this._features.split(",").indexOf( "beacon" ) >= 0 )
            {
+
{
                var srcNode;
+
var srcNode;
                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 = "276px";
+
mapNode.style.height = "276px";
               
+
                srcNode = document.createElement( "link" );
+
srcNode = document.createElement( "link" );
                srcNode.href = "/leaflet/leaflet.css";
+
srcNode.href = "/leaflet/leaflet.css";
                srcNode.rel = "stylesheet";
+
srcNode.rel = "stylesheet";
                srcNode.type = "text/css";
+
srcNode.type = "text/css";
  
                // Load the css
+
// Load the css
                ( document.head || document.documentElement ).appendChild( srcNode );
+
( document.head || document.documentElement ).appendChild( srcNode );
               
+
                srcNode = document.createElement( "script" );
+
srcNode = document.createElement( "script" );
                srcNode.src = "/leaflet/leaflet.js";
+
srcNode.src = "/leaflet/leaflet.js";
                srcNode.type = "text/javascript";
+
srcNode.type = "text/javascript";
                srcNode.addEventListener( "load", function( _evt )
+
srcNode.addEventListener( "load", function( _evt )
                {
+
{
                    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 ).setView( this._leaflet.point, 16);
  
                    L.CRS.CustomZoom = L.extend({}, L.CRS.EPSG3857,
+
L.CRS.CustomZoom = L.extend({}, L.CRS.EPSG3857,
                    {
+
{
                        scale: function( zoom ) {
+
scale: function( zoom ) {
                            //console.log( zoom );
+
if ( zoom < 24 )
                            if ( zoom < 24 )
+
return 256 * Math.pow( 2, zoom );
                                return 256 * Math.pow( 2, zoom );
 
  
                            // Freeze the actual zooming above this level to show the different floors
+
// Freeze the actual zooming above this level to show the different floors
                            // 256 * pow( 2, 23 )
+
// 256 * pow( 2, 23 )
                            return 2147483648;
+
return 2147483648;
                        }
+
}
                    });
+
});
  
 
/**********************************/
 
/**********************************/
Line 212: Line 219:
 
/*******************************/
 
/*******************************/
  
                    L.tileLayer('//{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
+
L.tileLayer('//{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
                        attribution: '&copy; <a href="//openstreetmap.org/copyright">OpenStreetMap</a> contributors',
+
attribution: '&copy; <a href="//openstreetmap.org/copyright">OpenStreetMap</a> contributors',
                        minZoom: 2,
+
minZoom: 2,
                        maxZoom: 28,
+
maxZoom: 28,
                        maxNativeZoom: 19
+
maxNativeZoom: 19
                    }).addTo( this._leaflet.map );
+
}).addTo( this._leaflet.map );
 
 
 
// Generic zoom (note that this will cause 404s
 
// Generic zoom (note that this will cause 404s
 
L.tileLayer("/images/ACK_{x}_{y}_{z}.png", {
 
L.tileLayer("/images/ACK_{x}_{y}_{z}.png", {
                        attribution: 'ACKspace',
+
attribution: 'ACKspace',
                        minZoom: 24,
+
minZoom: 24,
                        maxZoom: 28,
+
maxZoom: 28,
                        maxNativeZoom: 23
+
maxNativeZoom: 23
                    }).addTo( this._leaflet.map );
+
}).addTo( this._leaflet.map );
  
 
// special zoom
 
// special zoom
                    var funcLayer = new L.TileLayer.Functional( function( view )
+
var funcLayer = new L.TileLayer.Functional( function( view )
                    {
+
{
 
var bounds = {
 
var bounds = {
 +
16 : { cl: 33855, ch: 33855, rl: 21971, rh: 21971 },
 +
17 : { cl: 67710, ch: 67710, rl: 43942, rh: 43942 },
 +
18 : { cl: 135420, ch: 135420, rl: 87884, rh: 87884 },
 +
19 : { cl: 270840, ch: 270840, rl:  175768, rh:  175768 },
 +
20 : { cl: 541680, ch: 541680, rl:  351536, rh:  351537},
 
21 : { cl:  1083360, ch:  1083361, rl:  703073, rh:  703074 },
 
21 : { cl:  1083360, ch:  1083361, rl:  703073, rh:  703074 },
 
22 : { cl:  2166720, ch:  2166723, rl:  1406146, rh:  1406148 },
 
22 : { cl:  2166720, ch:  2166723, rl:  1406146, rh:  1406148 },
Line 253: Line 265:
 
.replace('{x}', view.tile.column)
 
.replace('{x}', view.tile.column)
 
.replace('{s}', view.subdomain);
 
.replace('{s}', view.subdomain);
                       
+
                        return url;
+
return url;
                    },
+
},
                    {
+
{
                        attribution: 'ACKspace',
+
attribution: 'ACKspace',
                        minZoom: 21,
+
minZoom: 16,
                        maxZoom: 28
+
maxZoom: 28
                    } ).addTo( this._leaflet.map );
+
} ).addTo( this._leaflet.map );
 
 
 
this._leaflet.map.on('zoomend', function( _event )
 
this._leaflet.map.on('zoomend', function( _event )
 
{
 
{
 +
var o = 1, z = _event.target.getZoom();
 +
 +
/*
 +
// Infinite zoom
 +
if ( z > 27 )
 +
{
 +
// boundingbox contains center and zoom > 27
 +
// then zoom out
 +
// setView/panTo/setZoom/fitBounds/etc.
 +
//_event.target.getCenter()
 +
_event.target.setZoom( 2, true );
 +
}
 +
*/
 +
 +
if ( !this._leaflet.temperatures["28151767050000a0"] )
 +
return;
 +
 
// zoom 18->23 opacity 1->0
 
// zoom 18->23 opacity 1->0
var o = 1, z = _event.target.getZoom();
 
 
if ( z > 17 )
 
if ( z > 17 )
 
o = Math.max( (23-z) / 5, 0 );
 
o = Math.max( (23-z) / 5, 0 );
Line 294: Line 322:
 
}
 
}
  
                    // "Follow" control
+
// "Follow" control
                    this._leaflet.follow = null;
+
this._leaflet.follow = null;
                    L.Control.Command = L.Control.extend(
+
L.Control.Command = L.Control.extend(
                    {
+
{
                        options:
+
options:
                        {
+
{
                            position: 'topleft',
+
position: 'topleft',
                        },
+
},
               
+
                        onAdd: function( _map )
+
onAdd: function( _map )
                        {
+
{
                            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._leaflet.follow ? " toggle" : ""), controlDiv );
+
var controlUI = L.DomUtil.create( "a", "leaflet-clickable" + (this._leaflet.follow ? " toggle" : ""), controlDiv );
                            controlUI.innerHTML = "&#8982;";
+
controlUI.innerHTML = "&#8982;";
                            controlUI.style.fontSize = "35px";
+
controlUI.style.fontSize = "35px";
                            controlUI.title = 'Follow beacon';
+
controlUI.title = 'Follow beacon';
               
+
                            L.DomEvent.addListener( controlUI, 'click', function( _evt )
+
L.DomEvent.addListener( controlUI, 'click', function( _evt )
                            {
+
{
                                this._leaflet.follow = !this._leaflet.follow;
+
this._leaflet.follow = !this._leaflet.follow;
                                _evt.currentTarget.className = "leaflet-clickable" + (this._leaflet.follow ? " toggle" : "");
+
_evt.currentTarget.className = "leaflet-clickable" + (this._leaflet.follow ? " toggle" : "");
  
                                // Update the map immediately
+
// Update the map immediately
                                if ( this._leaflet.follow )
+
if ( this._leaflet.follow )
                                {
+
{
                                    // Determine the bounding box to 'follow
+
// Determine the bounding box to 'follow
                                    var bounds = L.latLngBounds( this._leaflet.beacons.map( function( _beacon )
+
var bounds = L.latLngBounds( this._leaflet.beacons.map( function( _beacon )
                                    {
+
{
                                        return _beacon.point;
+
return _beacon.point;
                                    } ) );
+
} ) );
  
                                    if ( !this._leaflet.beacons.length )
+
if ( !this._leaflet.beacons.length )
                                        bounds.extend( this._leaflet.point );
+
bounds.extend( this._leaflet.point );
  
                                    this._leaflet.map.fitBounds( bounds );
+
this._leaflet.map.fitBounds( bounds );
                                }
+
if ( this._leaflet.map.getZoom() > 18 )
                            }.bind( this ) );
+
this._leaflet.map.setZoom( 18 );
               
+
}
                            return controlDiv;
+
}.bind( this ) );
                        }.bind( this )
+
                    } );
+
return controlDiv;
 +
}.bind( this )
 +
} );
  
                    this._leaflet.map.addControl( new L.Control.Command() );
+
this._leaflet.map.addControl( new L.Control.Command() );
  
                    // Icons
+
// Icons
                    this._leaflet.icons = {
+
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',
                            iconSize: [32, 32],
+
iconSize: [32, 32],
                            iconAnchor: [16, 26],
+
iconAnchor: [16, 26],
                            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],
+
shadowSize: [59, 32],
                            shadowAnchor: [16, 26]
+
shadowAnchor: [16, 26]
                        } )
+
} )
                    };
+
};
                    this._leaflet.descriptions = {
+
this._leaflet.descriptions = {
                        "HoaB" : "Hackers on a Bike"
+
"HoaB" : "Hackers on a Bike"
                    };
+
};
  
                    this._leaflet.marker = L.marker( this._leaflet.point ).addTo( this._leaflet.map );
+
this._leaflet.marker = L.marker( this._leaflet.point ).addTo( this._leaflet.map );
                    this._leaflet.beacons = [];
+
this._leaflet.beacons = [];
                    this._leaflet.temperatures = {
+
this._leaflet.temperatures = {
                        // outside
+
// 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 ),
+
"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
+
// 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 ),
+
"28151767050000a0" : 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 )
//{lat: 50.89277067395246, lng: 5.971342250704766}
+
// hot zone
                        // hot zone
+
/*"288a13670500002a" : null*/
                        /*"288a13670500002a" : null*/
+
};
                    };
+
}.bind( this ) );
                }.bind( this ) );
 
  
                // Load the script
+
// Load the script
                ( document.head || document.documentElement ).appendChild( srcNode );
+
( document.head || document.documentElement ).appendChild( srcNode );
            }
+
}
  
            // 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 )
+
SpaceAPI.prototype._determineColor = function( _temperature )
        {
+
{
            var tempteratureColors = [
+
var tempteratureColors = [
                [ -10,  0,  0,  0], // black
+
[ -10,  0,  0,  0], // black
                [  0,  0,  0,255], // blue
+
[  0,  0,  0,255], // blue
                [  15, 255,255,  0], // yellow
+
[  15, 255,255,  0], // yellow
                [  35, 255,  0,  0], // red
+
[  35, 255,  0,  0], // red
                [  45, 255,255,255], // white
+
[  45, 255,255,255], // white
                [5000, 255,255,255]  // white, blink
+
[5000, 255,255,255]  // white, blink
            ];
+
];
            var index;
+
var index;
            var ratio;
+
var ratio;
  
            for ( var nTemp = tempteratureColors.length - 1; nTemp; nTemp-- )
+
for ( var nTemp = tempteratureColors.length - 1; nTemp; nTemp-- )
            {
+
{
                if ( _temperature >= tempteratureColors[ nTemp ][0] )
+
if ( _temperature >= tempteratureColors[ nTemp ][0] )
                    break;
+
break;
  
                ratio = 0;
+
ratio = 0;
                if ( index = nTemp )
+
if ( index = nTemp )
                    ratio = (_temperature - tempteratureColors[ nTemp - 1 ][0]) / ( tempteratureColors[ nTemp ][0] - tempteratureColors[ nTemp - 1 ][0] );
+
ratio = (_temperature - tempteratureColors[ nTemp - 1 ][0]) / ( tempteratureColors[ nTemp ][0] - tempteratureColors[ nTemp - 1 ][0] );
            }
+
}
  
            var lo = tempteratureColors[ index ? index - 1 : 0 ];
+
var lo = tempteratureColors[ index ? index - 1 : 0 ];
            var hi = tempteratureColors[ index ];
+
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))+")";
+
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 )
+
SpaceAPI.prototype._nlsTime = function( _time )
        {
+
{
            var postfix;
+
var postfix;
            if ( _time < 2 )
+
if ( _time < 2 )
            {
+
{
                return "moments";
+
return "moments";
            }
+
}
  
            if ( _time > 31556952 )
+
if ( _time > 31556952 )
            {
+
{
                _time /= 31556952;
+
_time /= 31556952;
                postfix = "Year";
+
postfix = "Year";
            }
+
}
            else if ( _time > 2629746 )
+
else if ( _time > 2629746 )
            {
+
{
                _time /= 2629746;
+
_time /= 2629746;
                postfix = "Month";
+
postfix = "Month";
            }
+
}
            else if ( _time > 604800 )
+
else if ( _time > 604800 )
            {
+
{
                _time /= 604800;
+
_time /= 604800;
                postfix = "Week";
+
postfix = "Week";
            }
+
}
            else if ( _time > 86400 )
+
else if ( _time > 86400 )
            {
+
{
                _time /= 86400;
+
_time /= 86400;
                postfix = "day";
+
postfix = "day";
            }
+
}
            else if ( _time > 3600 )
+
else if ( _time > 3600 )
            {
+
{
                _time /= 3600;
+
_time /= 3600;
                postfix = "hour";
+
postfix = "hour";
            }
+
}
            else if ( _time > 60 )
+
else if ( _time > 60 )
            {
+
{
                _time /= 60;
+
_time /= 60;
                postfix = "minute";
+
postfix = "minute";
            }
+
}
            else
+
else
            {
+
{
                postfix = "second";
+
postfix = "second";
            }
+
}
  
            _time = Math.round( _time );
+
_time = Math.round( _time );
            return _time + " " + postfix + (_time !== 1 ? "s" : "");
+
return _time + " " + postfix + (_time !== 1 ? "s" : "");
        };
+
};
  
        SpaceAPI.prototype._fetchState = function( )
+
SpaceAPI.prototype._fetchState = function( )
        {
+
{
            this._node.className = "processing";
+
this._node.className = "processing";
            var xhr = new XMLHttpRequest( );
+
var xhr = new XMLHttpRequest( );
            if ( !!( "onload" in xhr ) )
+
if ( !!( "onload" in xhr ) )
            {
+
{
                xhr.onreadystatechange = function( _event )
+
xhr.onreadystatechange = function( _event )
                {
+
{
                    if ( _event.target.readyState !== 4 )
+
if ( _event.target.readyState !== 4 )
                        return;
+
return;
                    if ( _event.target.status === 200 )
+
if ( _event.target.status === 200 )
                        this._xhr_onload.apply( this, arguments );
+
this._xhr_onload.apply( this, arguments );
                    else
+
else
                        this._xhr_onerror.apply( this, arguments );
+
this._xhr_onerror.apply( this, arguments );
                }.bind( this );
+
}.bind( this );
            }
+
}
            else
+
else
            {
+
{
                // Modern xhr
+
// Modern xhr
                xhr.onload = this._xhr_onload.bind( this );
+
xhr.onload = this._xhr_onload.bind( this );
                xhr.onerror = this._xhr_onerror.bind( this );
+
xhr.onerror = this._xhr_onerror.bind( this );
            }
+
}
  
            xhr.open( "GET", this._url, true );
+
xhr.open( "GET", this._url, true );
  
            // Tells server that this call is made for ajax purposes.
+
// Tells server that this call is made for ajax purposes.
            // Most libraries like jQuery/Prototype/Dojo do this
+
// Most libraries like jQuery/Prototype/Dojo do this
            xhr.setRequestHeader( "X-Requested-With", "XMLHttpRequest" );
+
xhr.setRequestHeader( "X-Requested-With", "XMLHttpRequest" );
  
            // No data needs to be sent along with the request.
+
// No data needs to be sent along with the request.
            xhr.send( null );
+
xhr.send( null );
        };
+
};
  
        SpaceAPI.prototype._updateState = function( _message, _color, _title )
+
SpaceAPI.prototype._updateState = function( _message, _color, _title )
        {
+
{
            this._node.className = "";
+
this._node.className = "";
            this._node.textContent = _message;
+
this._node.textContent = _message;
            this._node.style.backgroundColor = _color;
+
this._node.style.backgroundColor = _color;
            if ( _title )
+
if ( _title )
                this._node.title = _title;
+
this._node.title = _title;
            else
+
else
                this._node.title = "";
+
this._node.title = "";
        };
+
};
  
        SpaceAPI.prototype._xhr_onload = function( _event )
+
SpaceAPI.prototype._xhr_onload = function( _event )
        {
+
{
            var open = null;
+
var open = null;
            var message = null;
+
var message = null;
            var title = null;
+
var title = null;
  
            try
+
try
            {
+
{
                this.data = JSON.parse( _event.target.responseText );
+
this.data = JSON.parse( _event.target.responseText );
                open = this.data.state.open;
+
open = this.data.state.open;
                message = this.data.state.message;
+
message = this.data.state.message;
  
                // Start as epoch timestamp (NOTE: check if timezone doesn't mess things up)
+
// Start as epoch timestamp (NOTE: check if timezone doesn't mess things up)
                var d = new Date( 0 );
+
var d = new Date( 0 );
                d.setUTCSeconds( this.data.state.lastchange );
+
d.setUTCSeconds( this.data.state.lastchange );
                title = this._msgSince + d.toLocaleString( );
+
title = this._msgSince + d.toLocaleString( );
            }
+
}
            catch( _e )
+
catch( _e )
            {
+
{
                message = this._msgParserError;
+
message = this._msgParserError;
            }
+
}
  
            if ( open )
+
if ( open )
                this._updateState( message || this._msgOpen, this._colorOpen, title );
+
this._updateState( message || this._msgOpen, this._colorOpen, title );
            else if ( open === false )
+
else if ( open === false )
                this._updateState( message || this._msgClosed, this._colorClosed, title );
+
this._updateState( message || this._msgClosed, this._colorClosed, title );
            else
+
else
                this._updateState( message || this._msgUnknown, this._colorUnknown, title );
+
this._updateState( message || this._msgUnknown, this._colorUnknown, title );
  
            if ( this._leaflet )
+
if ( this._leaflet )
            {
+
{
                // Handle temperatures
+
// Handle temperatures
                if ( this.data.sensors && this.data.sensors.temperature && this.data.sensors.temperature.length )
+
if ( this.data.sensors && this.data.sensors.temperature && this.data.sensors.temperature.length )
                {
+
{
                    // Iterate the sensors and match a local sensor name
+
// Iterate the sensors and match a local sensor name
                    this.data.sensors.temperature.forEach( function( _apiTemp )
+
this.data.sensors.temperature.forEach( function( _apiTemp )
                    {
+
{
                        var temp = this._leaflet.temperatures[ _apiTemp.name ];
+
var temp = this._leaflet.temperatures[ _apiTemp.name ];
                        if ( temp )
+
if ( temp )
                        {
+
{
                            temp.setStyle({color: this._determineColor( _apiTemp.value )});
+
temp.setStyle({color: this._determineColor( _apiTemp.value )});
  
                            var delta = (Date.now() - new Date( _apiTemp.ext_lastchange * 1000 )) / 1000;
+
var delta = (Date.now() - new Date( _apiTemp.ext_lastchange * 1000 )) / 1000;
                            temp.custom = {
+
temp.custom = {
                                description: _apiTemp.description | _apiTemp.name,
+
description: _apiTemp.description | _apiTemp.name,
                                location: _apiTemp.location | null,
+
location: _apiTemp.location | null,
                                value: _apiTemp.value,
+
value: _apiTemp.value,
                                lastchange: _apiTemp.ext_lastchange
+
lastchange: _apiTemp.ext_lastchange
                            }
+
}
                            //updatePopup( temp
+
//updatePopup( temp
  
                            temp.bindPopup( "Description: " + _apiTemp.description + "<br/>Location: " + _apiTemp.location + "<br/>Value: " + _apiTemp.value + _apiTemp.unit + "<br/>Last update: " + this._nlsTime( delta ) + " ago" );
+
temp.bindPopup( "Description: " + _apiTemp.description + "<br/>Location: " + _apiTemp.location + "<br/>Value: " + _apiTemp.value + _apiTemp.unit + "<br/>Last update: " + this._nlsTime( delta ) + " ago" );
                        }
+
}
                    }, this );
+
}, this );
                }
+
}
  
                // 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 )
                {
+
{
                    var bHoaB = false;
+
var bHoaB = false;
                    var beacons = this.data.sensors.beacon.map( function( _apiBeacon )
+
var beacons = this.data.sensors.beacon.map( function( _apiBeacon )
                    {
+
{
                        var beacon = {};
+
var beacon = {};
  
                        beacon.point  = L.latLng( _apiBeacon.location.lat,_apiBeacon.location.lon );
+
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.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 );
+
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;
+
var delta = (Date.now() - new Date( _apiBeacon.ext_lastchange * 1000 )) / 1000;
  
                        // Closure variable
+
// Closure variable
                        if ( ( delta < 3600 ) && ( _apiBeacon.name === "HoaB" ) )
+
if ( ( delta < 3600 ) && ( _apiBeacon.name === "HoaB" ) )
                            bHoaB = true;
+
bHoaB = true;
  
                        if ( this._leaflet.icons[ _apiBeacon.name ] )
+
if ( this._leaflet.icons[ _apiBeacon.name ] )
                            this._leaflet.icons[ _apiBeacon.name ].options.className = delta > 60 ? "disconnected" : "";
+
this._leaflet.icons[ _apiBeacon.name ].options.className = delta > 60 ? "disconnected" : "";
  
                        var popup = beacon.marker.getPopup();
+
var popup = beacon.marker.getPopup();
                        if ( !popup )
+
if ( !popup )
                            popup = beacon.marker.bindPopup().getPopup();
+
popup = beacon.marker.bindPopup().getPopup();
  
                        popup.setContent( ( this._leaflet.descriptions[ _apiBeacon.name ] || _apiBeacon.name ) + "<br/>Last update: " + this._nlsTime( delta ) + " ago" );
+
popup.setContent( ( this._leaflet.descriptions[ _apiBeacon.name ] || _apiBeacon.name ) + "<br/>Last update: " + this._nlsTime( delta ) + " ago" );
  
                        return beacon;
+
return beacon;
                    }, this );
+
}, this );
  
                    // TODO: clean up old beacons!!
+
// TODO: clean up old beacons!!
                    this._leaflet.beacons.forEach( function( _beacon )
+
this._leaflet.beacons.forEach( function( _beacon )
                    {
+
{
                        // Destroy popup
+
// Destroy popup
                        _beacon.marker.unbindPopup( );
+
_beacon.marker.unbindPopup( );
  
                        // Remove marker and circle
+
// Remove marker and circle
                        this._leaflet.map.removeLayer( _beacon.marker );
+
this._leaflet.map.removeLayer( _beacon.marker );
                        this._leaflet.map.removeLayer( _beacon.circle );
+
this._leaflet.map.removeLayer( _beacon.circle );
                    }, this );
+
}, this );
                    /*
+
/*
                    for ( var b = 0; b < Math.min( this._leaflet.beacons.length, beacons, length ); b++ )
+
for ( var b = 0; b < Math.min( this._leaflet.beacons.length, beacons, length ); b++ )
                    {
+
{
                        // Update position, icon, radius, tooltip
+
// Update position, icon, radius, tooltip
                        this._leaflet.beacons[ b ]
+
this._leaflet.beacons[ b ]
                    }
+
}
                    */
+
*/
                    this._leaflet.beacons = beacons;
+
this._leaflet.beacons = beacons;
  
                    // Only follow beacons automatically initially if there is a HoaB among it
+
// Only follow beacons automatically initially if there is a HoaB among it
                    if ( bHoaB && this._leaflet.follow === null )
+
if ( bHoaB && this._leaflet.follow === null )
                    {
+
{
                        this._leaflet.follow = true;
+
this._leaflet.follow = true;
                        document.querySelector( "div.leaflet-bar > a.leaflet-clickable" ).className = "leaflet-clickable toggle";
+
document.querySelector( "div.leaflet-bar > a.leaflet-clickable" ).className = "leaflet-clickable toggle";
                    }
+
}
                }
+
}
  
  
                // TODO: Update if coordinate is incorrect
+
// TODO: Update if coordinate is incorrect
                if ( this._leaflet.follow === null )
+
if ( this._leaflet.follow === null )
                {
+
{
                    this._leaflet.follow = false;
+
this._leaflet.follow = false;
  
                    // Update location
+
// Update location
                    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 );
  
                    // Set popup data and open it
+
// Set popup data and open it
                    var popup = this._leaflet.marker.getPopup();
+
var popup = this._leaflet.marker.getPopup();
                    if ( !popup )
+
if ( !popup )
                        popup = this._leaflet.marker.bindPopup().getPopup();
+
popup = this._leaflet.marker.bindPopup().getPopup();
  
                    var info = "<img src='" + this.data.logo + "'><br/>";
+
var info = "<img src='" + this.data.logo + "'><br/>";
                    var l = this.data.location, s = this.data.spacefed;
+
var l = this.data.location, s = this.data.spacefed;
                    info += l.address;
+
info += l.address+"<br/>";
  
                    if ( l.ext_floor )
+
if ( l.ext_floor )
                        info += ", floor " + l.ext_floor;
+
info += "floor " + l.ext_floor;
                    if ( l.ext_room )
+
if ( l.ext_room )
                        info += ", room " + l.ext_room;
+
info += ", room " + l.ext_room;
                    info += "<br/>" + (s.spacenet ? "&#x2714;" : "&#x274C;") + ' <a target="blank" href="Spacenet">spacenet</a>';
+
info += "<br/>" + (s.spacenet ? "&#x2714;" : "&#x274C;") + ' <a target="blank" href="Spacenet">spacenet</a>';
                    info += "<br/>" + (s.ext_spacenet5g ? "&#x2714;" : "&#x274C;") + " spacenet (5GHz)";
+
info += "<br/>" + (s.ext_spacenet5g ? "&#x2714;" : "&#x274C;") + " spacenet (5GHz)";
                    info += "<br/>" + (s.spacesaml ? "&#x2714;" : "&#x274C;") + " spacesaml";
+
info += "<br/>" + (s.spacesaml ? "&#x2714;" : "&#x274C;") + " spacesaml";
                    info += "<br/>" + (s.ext_spaceconnect ? "&#x2714;" : "&#x274C;") + " spaceconnect";
+
info += "<br/>" + (s.ext_spaceconnect ? "&#x2714;" : "&#x274C;") + " spaceconnect";
                    info += "<br/>" + (s.spacephone ? "&#x2714;" : "&#x274C;") + ' <a target="blank" href="Spacephone">spacephone</a>';
+
info += "<br/>" + (s.spacephone ? "&#x2714;" : "&#x274C;") + ' <a target="blank" href="Spacephone">spacephone</a>';
                    if ( s.ext_spacephone_extension )
+
if ( s.ext_spacephone_extension )
                        info += ": +" + s.ext_spacephone_extension;
+
info += ": +" + s.ext_spacephone_extension;
  
                    popup.setContent( info );
+
popup.setContent( info );
  
                    this._leaflet.marker.openPopup();
+
this._leaflet.marker.openPopup();
                    //popup.update();
+
//popup.update();
                }
+
}
  
                if ( this._leaflet.follow )
+
if ( this._leaflet.follow )
                {
+
{
                    // Determine the bounding box to 'follow
+
// Determine the bounding box to 'follow
                    var bounds = L.latLngBounds( this._leaflet.beacons.map( function( _beacon )
+
var bounds = L.latLngBounds( this._leaflet.beacons.map( function( _beacon )
                    {
+
{
                        return _beacon.point;
+
return _beacon.point;
                    } ) );
+
} ) );
  
                    // If we don't have Hackers on a Bike, include the home location together with the other beacons
+
// If we don't have Hackers on a Bike, include the home location together with the other beacons
                    if ( !bHoaB )
+
if ( !bHoaB )
                        bounds.extend( this._leaflet.point );
+
bounds.extend( this._leaflet.point );
  
                    this._leaflet.map.fitBounds( bounds );
+
this._leaflet.map.fitBounds( bounds );
                }
+
if ( this._leaflet.map.getZoom() > 18 )
            }
+
this._leaflet.map.setZoom( 18 );
        };
+
}
 +
}
 +
};
  
        SpaceAPI.prototype._xhr_onerror = function( )
+
SpaceAPI.prototype._xhr_onerror = function( )
        {
+
{
            // Something has failed, show the error
+
// Something has failed, show the error
            this._updateState( this._msgError, this._colorUnknown );
+
this._updateState( this._msgError, this._colorUnknown );
        }
+
}
    }
+
}
    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|escape:urlpathinfo}-->", <!--{$interval|validate:int|default:0}-->, "<!--{$features|escape:'quotes'}-->" );
+
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();
  
 
}( ));
 
}( ));
 
</script>
 
</script>
 
</includeonly>
 
</includeonly>

Revision as of 10:26, 9 May 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.