Difference between revisions of "Widget:SpaceAPI"
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"; | |
− | + | /* | |
− | + | TODO: | |
− | + | separate rooms (get latlng) | |
− | + | zoom onto toolbox | |
− | + | table island not correct (4, not 5 tables) | |
− | + | ||
− | + | */ | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | + | if ( typeof SpaceAPI === "undefined" ) | |
− | + | { | |
− | + | window.SpaceAPI = function( _width, _height, _float, _padding, _url, _interval, _features ) | |
− | + | { | |
− | + | this._width = _width; | |
− | + | this._height = _height; | |
− | + | this._padding = _padding; | |
− | + | this._url = _url; | |
− | + | this._interval = 1000 * _interval; | |
− | + | this._float = _float; | |
− | + | this._features = _features; | |
− | + | } | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | + | SpaceAPI.prototype.data = null; | |
− | + | SpaceAPI.prototype._width = null; | |
− | + | 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; | |
− | + | if ( this._interval > 0 ) | |
− | + | this._intervalId = setInterval( this._fetchState.bind( this ), this._interval ); | |
− | + | document.write( '<div id="spaceAPI' + this._intervalId + '"></div>' ); | |
− | + | var node = document.getElementById( "spaceAPI" + this._intervalId ); | |
− | + | if ( !node ) | |
− | + | { | |
− | + | console && console.log( "node not found" ); | |
− | + | return; | |
− | + | } | |
− | + | node.style.width = this._width; | |
− | + | node.style.textAlign = "center"; | |
− | + | node.style.BoxShadow = "3px 3px 4px rgba(0,0,0,0.2)"; | |
− | + | node.style.position = "relative"; | |
− | + | if ( this._float ) | |
− | + | node.style.float = this._float; | |
− | + | this._node = node.appendChild( document.createElement( "div" ) ); | |
− | + | this._node.style.height = this._height + "px"; | |
− | + | this._node.style.padding = this._padding; | |
− | + | this._node.textContent = this._msgLoading; | |
− | + | if ( this._features.split(",").indexOf( "beacon" ) >= 0 ) | |
− | + | { | |
− | + | var srcNode; | |
− | + | var mapNode = node.appendChild( document.createElement( "div" ) ); | |
− | + | mapNode.style.width = "100%"; | |
− | + | mapNode.style.height = "276px"; | |
− | + | ||
− | + | srcNode = document.createElement( "link" ); | |
− | + | srcNode.href = "/leaflet/leaflet.css"; | |
− | + | srcNode.rel = "stylesheet"; | |
− | + | srcNode.type = "text/css"; | |
− | + | // Load the css | |
− | + | ( document.head || document.documentElement ).appendChild( srcNode ); | |
− | + | ||
− | + | srcNode = document.createElement( "script" ); | |
− | + | srcNode.src = "/leaflet/leaflet.js"; | |
− | + | srcNode.type = "text/javascript"; | |
− | + | srcNode.addEventListener( "load", function( _evt ) | |
− | + | { | |
− | + | this._leaflet = {}; | |
− | + | this._leaflet.point = L.latLng( 50.8925,5.9713 ); | |
− | + | this._leaflet.map = L.map( mapNode ).setView( this._leaflet.point, 16); | |
− | + | L.CRS.CustomZoom = L.extend({}, L.CRS.EPSG3857, | |
− | + | { | |
− | + | scale: function( zoom ) { | |
− | + | if ( zoom < 24 ) | |
− | + | return 256 * Math.pow( 2, zoom ); | |
− | |||
− | + | // Freeze the actual zooming above this level to show the different floors | |
− | + | // 256 * pow( 2, 23 ) | |
− | + | return 2147483648; | |
− | + | } | |
− | + | }); | |
/**********************************/ | /**********************************/ | ||
Line 212: | Line 219: | ||
/*******************************/ | /*******************************/ | ||
− | + | L.tileLayer('//{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { | |
− | + | attribution: '© <a href="//openstreetmap.org/copyright">OpenStreetMap</a> contributors', | |
− | + | minZoom: 2, | |
− | + | maxZoom: 28, | |
− | + | maxNativeZoom: 19 | |
− | + | }).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', | |
− | + | minZoom: 24, | |
− | + | maxZoom: 28, | |
− | + | maxNativeZoom: 23 | |
− | + | }).addTo( this._leaflet.map ); | |
// special zoom | // special zoom | ||
− | + | 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; | |
− | + | }, | |
− | + | { | |
− | + | attribution: 'ACKspace', | |
− | + | minZoom: 16, | |
− | + | maxZoom: 28 | |
− | + | } ).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 | ||
− | |||
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 | |
− | + | this._leaflet.follow = null; | |
− | + | L.Control.Command = L.Control.extend( | |
− | + | { | |
− | + | options: | |
− | + | { | |
− | + | position: 'topleft', | |
− | + | }, | |
− | + | ||
− | + | onAdd: function( _map ) | |
− | + | { | |
− | + | var controlDiv = L.DomUtil.create( "div", "leaflet-bar" ); | |
− | + | var controlUI = L.DomUtil.create( "a", "leaflet-clickable" + (this._leaflet.follow ? " toggle" : ""), controlDiv ); | |
− | + | controlUI.innerHTML = "⌖"; | |
− | + | controlUI.style.fontSize = "35px"; | |
− | + | controlUI.title = 'Follow beacon'; | |
− | + | ||
− | + | L.DomEvent.addListener( controlUI, 'click', function( _evt ) | |
− | + | { | |
− | + | this._leaflet.follow = !this._leaflet.follow; | |
− | + | _evt.currentTarget.className = "leaflet-clickable" + (this._leaflet.follow ? " toggle" : ""); | |
− | + | // Update the map immediately | |
− | + | if ( this._leaflet.follow ) | |
− | + | { | |
− | + | // 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 ); | |
− | + | if ( this._leaflet.map.getZoom() > 18 ) | |
− | + | this._leaflet.map.setZoom( 18 ); | |
− | + | } | |
− | + | }.bind( this ) ); | |
− | + | ||
− | + | return controlDiv; | |
+ | }.bind( this ) | ||
+ | } ); | ||
− | + | this._leaflet.map.addControl( new L.Control.Command() ); | |
− | + | // Icons | |
− | + | this._leaflet.icons = { | |
− | + | "HoaB" : L.icon( { | |
− | + | iconUrl: '//maps.google.com/intl/en_us/mapfiles/ms/micons/cycling.png', | |
− | + | iconSize: [32, 32], | |
− | + | iconAnchor: [16, 26], | |
− | + | popupAnchor: [0, -26], | |
− | + | shadowUrl: '//maps.google.com/intl/en_us/mapfiles/ms/micons/cycling.shadow.png', | |
− | + | shadowSize: [59, 32], | |
− | + | 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.8924743319376, 5.9711186739150435], [50.89251872057557, 5.97115655487869]], {stroke:0,fillOpacity:0.8} ).addTo( this._leaflet.map ), | |
− | + | // barbecue | |
− | + | "DEADBEEF0" : L.circle( [ 50.89277, 5.97134 ], 1, {stroke:0,fillOpacity:0.8} ).addTo( this._leaflet.map ) | |
− | + | // hot zone | |
− | + | /*"288a13670500002a" : null*/ | |
− | + | }; | |
− | + | }.bind( this ) ); | |
− | |||
− | + | // Load the script | |
− | + | ( document.head || document.documentElement ).appendChild( srcNode ); | |
− | + | } | |
− | + | // Update the space state immediately | |
− | + | 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 < 2 ) | |
− | + | { | |
− | + | return "moments"; | |
− | + | } | |
− | + | 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" : ""); | |
− | + | }; | |
− | + | SpaceAPI.prototype._fetchState = function( ) | |
− | + | { | |
− | + | this._node.className = "processing"; | |
− | + | var xhr = new XMLHttpRequest( ); | |
− | + | if ( !!( "onload" in xhr ) ) | |
− | + | { | |
− | + | xhr.onreadystatechange = function( _event ) | |
− | + | { | |
− | + | if ( _event.target.readyState !== 4 ) | |
− | + | return; | |
− | + | if ( _event.target.status === 200 ) | |
− | + | this._xhr_onload.apply( this, arguments ); | |
− | + | else | |
− | + | this._xhr_onerror.apply( this, arguments ); | |
− | + | }.bind( this ); | |
− | + | } | |
− | + | else | |
− | + | { | |
− | + | // Modern xhr | |
− | + | xhr.onload = this._xhr_onload.bind( this ); | |
− | + | xhr.onerror = this._xhr_onerror.bind( this ); | |
− | + | } | |
− | + | xhr.open( "GET", this._url, true ); | |
− | + | // Tells server that this call is made for ajax purposes. | |
− | + | // Most libraries like jQuery/Prototype/Dojo do this | |
− | + | xhr.setRequestHeader( "X-Requested-With", "XMLHttpRequest" ); | |
− | + | // No data needs to be sent along with the request. | |
− | + | xhr.send( null ); | |
− | + | }; | |
− | + | SpaceAPI.prototype._updateState = function( _message, _color, _title ) | |
− | + | { | |
− | + | this._node.className = ""; | |
− | + | this._node.textContent = _message; | |
− | + | this._node.style.backgroundColor = _color; | |
− | + | if ( _title ) | |
− | + | this._node.title = _title; | |
− | + | else | |
− | + | this._node.title = ""; | |
− | + | }; | |
− | + | SpaceAPI.prototype._xhr_onload = function( _event ) | |
− | + | { | |
− | + | var open = null; | |
− | + | var message = null; | |
− | + | var title = null; | |
− | + | try | |
− | + | { | |
− | + | this.data = JSON.parse( _event.target.responseText ); | |
− | + | open = this.data.state.open; | |
− | + | message = this.data.state.message; | |
− | + | // Start as epoch timestamp (NOTE: check if timezone doesn't mess things up) | |
− | + | var d = new Date( 0 ); | |
− | + | d.setUTCSeconds( this.data.state.lastchange ); | |
− | + | title = this._msgSince + d.toLocaleString( ); | |
− | + | } | |
− | + | catch( _e ) | |
− | + | { | |
− | + | message = this._msgParserError; | |
− | + | } | |
− | + | if ( open ) | |
− | + | this._updateState( message || this._msgOpen, this._colorOpen, title ); | |
− | + | else if ( open === false ) | |
− | + | this._updateState( message || this._msgClosed, this._colorClosed, title ); | |
− | + | else | |
− | + | this._updateState( message || this._msgUnknown, this._colorUnknown, title ); | |
− | + | 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.custom = { | |
− | + | description: _apiTemp.description | _apiTemp.name, | |
− | + | location: _apiTemp.location | null, | |
− | + | value: _apiTemp.value, | |
− | + | lastchange: _apiTemp.ext_lastchange | |
− | + | } | |
− | + | //updatePopup( temp | |
− | + | temp.bindPopup( "Description: " + _apiTemp.description + "<br/>Location: " + _apiTemp.location + "<br/>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 ) | |
− | + | { | |
− | + | 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(); | |
− | + | if ( !popup ) | |
− | + | 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+"<br/>"; | |
− | + | 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; | |
− | + | } ) ); | |
− | + | // 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 ); | |
− | + | if ( this._leaflet.map.getZoom() > 18 ) | |
− | + | this._leaflet.map.setZoom( 18 ); | |
− | + | } | |
+ | } | ||
+ | }; | ||
− | + | SpaceAPI.prototype._xhr_onerror = function( ) | |
− | + | { | |
− | + | // Something has failed, show the error | |
− | + | this._updateState( this._msgError, this._colorUnknown ); | |
− | + | } | |
− | + | } | |
− | + | 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(); | |
}( )); | }( )); | ||
</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.