code everywhere
technology, web services and applications

Building a basic Metrics dashboard using CSS / JavaScript

posted on April 10, 2017, 12:00 am in

Using some basic JavaScript and CSS, we can create a small Metrics front end to display data from various API sources.

Based on a 4x4 Grid and designed to look good on 1080p TV's.

Demo Screenshot

Code

CSS Styles

* { margin0padding0; }
img border0; }
body font-family'Roboto Condensed'sans-serifoverflowhidden; }

.
dash-wrapper {
    
width1920px;
    
height1080px;
    
positionrelative;
    
background#191919;
}    

.
dash-widget {
    
positionabsolute;
    
border-radius4px;
    
overflowhidden;                
    
box-sizingborder-box;
    
border10px solid #191919;
    
padding15px;
    
text-aligncenter;
    
background#31343B;
    
color#fff;
}
.
dash-widget .label {  color#a6a6a6; }

.dash-announcement {
    
positionabsolute;
    
box-sizingborder-box;
    
text-aligncenter;
    
color#fff;
    
background#000;
    
left0;
    
width100%;
    
height10%;
    
top90%;
    
padding10px;
    
font-size57px;
}

.
x-left0; }
.
x-left25%; }
.
x-left50%; }
.
x-left75%;}

.
y-top0; }
.
y-top22.5%; }
.
y-top45%; }
.
y-top67.5%;}

.
width-width25%; }
.
width-width50%; }
.
width-width75%; }
.
width-width100%; }

.
height-height22.5%; }
.
height-height45%; }
.
height-height67.5%; }
.
height-height90%; }

.
title, .value margin-bottom12pxtext-transformuppercase; }
.
title font-size30pxfont-weight400; }
.
value font-size80pxfont-weight700;}
.
label font-size30pxtext-transformuppercasefont-weight400;}

.
red background#d02127; }
.green background#81B72B; }
.orange background#F0A542; }
.red .label, .green .label, .orange .label color#fff !important; }

.list { margin0 20px 0 20px; }
.list .
left, .list .right floatleftwidth50%; font-size36px; }
.list .
left text-alignleft;  }
.list .
right text-alignright; }
.
clear clearboth; }

JavaScript Code

/*
* APIDash.js (Apr 10 2017)
* Copyright 2017, http://codeeverywhere.ca
* Licensed under the MIT license.
*/

(function(documentwindow) {
    
let counter 0;
    var 
APIDash = function(args) {
        const 
animationInterval 1000 10
        
const APICallInterval 1000 30
        
const uuid = () => 'uid-' counter++

        
this.init = function(className) {
            
document.querySelector(className).innerHTML = `
                <div class="dash-wrapper">
                    <div class="dash-widgets"></div>
                    <div class="dash-announcement">... text ...</div>
                </div>
            
`
        }

        
this.message = function(str){
            
document.querySelector('.dash-announcement').innerHTML str
        
}
    
        
this.textWidget = function(titleclassNamecallAPI) {

            const 
id uuid()
            const 
animate = (className) => { document.querySelector(`#${id} .data`).className = `data ${className}` }

            
let format = [{label:"no data"value"--"}]
            
let index 0

            document
.querySelector('.dash-widgets').innerHTML += `
                <div class="dash-widget 
${className} animated fadeInUp" id="${id}">
                    <div class="title">
${title}</div>
                    <div class="data">
                        <div class="value">--</div>
                        <div class="label">--</div>
                    </div>
                </div>
            
`

            const 
slideOut = () => {
                
animate('animated slideOutLeft')
                
index = (index 1) % format.length
                setTimeout
(slideIn500)
            }

            const 
slideIn = () => {
                
animate('animated slideInRight')
                
document.querySelector(`#${id} .value`).innerHTML format[index].value
                document
.querySelector(`#${id} .label`).innerHTML format[index].label
            
}

            const 
runCallAPI = () => { 
                
callAPI().then( (resp) => { format resp })
            }
            
runCallAPI()
            
setInterval(runCallAPIAPICallInterval)

            
// add some random time so the animations aren't in sync
            
setIntervalslideOutanimationInterval Math.floor(Math.random()*10000) )
        }

        
this.listWidget = (titleclassNamecallAPI) => {
        
            const 
id uuid()
            const 
animate = (className) => { document.querySelector(`#${id} .list`).className = `list ${className}` }
        
            
let format = [{label:"--"value"--"}]
        
            
document.querySelector('.dash-widgets').innerHTML += `
                <div class="dash-widget 
${className} animated fadeInUp" id="${id}">
                    <div class="title">
${title}</div>
                    <div class="list">--</div>
                </div>
            
`
                        
            const 
slideOut = () => {
                
animate('animated slideOutLeft')
                
setTimeout(slideIn500)
            }
        
            const 
slideIn = () => {
                
animate('animated slideInRight')
                
document.querySelector(`#${id} .list`).innerHTML format.reduce( ( accitem ) => acc + `
                    <div class="left">
${item.label}</div>
                    <div class="right">
${item.value}</div>
                    <div class="clear"></div>
                
`, '')
            }
        
            const 
runCallAPI = () => { callAPI().then( (resp) => { format resp }) }
            
runCallAPI()
            
setInterval(runCallAPIAPICallInterval)
        
            
setIntervalslideOutanimationInterval Math.floor(Math.random()*10000) )
        }

        return 
this;
    }
    
window.APIDash APIDash;
})(
documentwindow);

HTML Template

<!DOCTYPE html>
<
html>
    <
head>
        <
title>API Dashboard</title>
        <
link href='https://fonts.googleapis.com/css?family=Roboto+Condensed:300,400,700' rel='stylesheet' type='text/css'>
        <
link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.7.0/animate.min.css">
        <
link rel="stylesheet" href="APIDash.css">
        <
script type="text/javascript" src="APIDash.js"></script>
    </head>
    <body>
        <div class="dash-app"></div>
        
        <script type="text/javascript">
            
            // Initialize APIDash ..
            APIDash().init('.dash-app')

            APIDash().message('hello!')

            // Get weather data, get every 3 hrs
            let weather = "-- &#8451;"
            const getWeather = () => {
                const url = 'https://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20weather.forecast%20where%20woeid%20in%20(select%20woeid%20from%20geo.places(1)%20where%20text%3D%22montreal%2C%20qc%22)&format=json&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys'

                fetch(url).then((resp) => resp.json()).then(
                    data => {
                        const celsius = Math.floor((parseInt(data.query.results.channel.item.condition.temp) - 32) * .5556);
                        weather = celsius + "&#8451;"
                    },
                    fail => { }
                )
            }
            getWeather()
            setInterval(getWeather, 1000 * 60 * 60 * 3)



            // Sample Widget 1
            APIDash().textWidget('time/weather ( widget 1 )', 'width-1 height-1 x-3 y-1', () => {
                return Promise.resolve([
                    {
                        value: weather,
                        label: "weather"
                    },
                    {
                        value: new Date().toString().substr(16, 5),
                        label: new Date().toString().substr(0, 10)
                    }
                ])
            })



            // Sample Widget 2
            let outsideVar = 0
            APIDash().textWidget('active users ( widget 2 )', 'width-1 height-1 x-1 y-1 green', () => {
                return Promise.resolve([{
                    value: (outsideVar++).toLocaleString(),
                    label: "today"
                },
                {
                    value: (outsideVar * 10).toLocaleString(),
                    label: "this week"
                }])
            })



            // Sample Widget 3
            APIDash().textWidget('error rate ( widget 3 )', 'width-1 height-1 x-4 y-1 red', () => {
                return Promise.resolve([{
                    value: (999).toLocaleString(),
                    label: "past 24H"
                }])
            })



            // Sample Widget 4
            APIDash().textWidget('error rate ( widget 4 )', 'width-1 height-1 x-3 y-2', () => {
                return Promise.resolve([{
                    value: (999).toLocaleString(),
                    label: "past 24H"
                }])
            })



            // Sample Widget 5
            APIDash().listWidget('list ( widget 5 )', 'width-1 height-3 x-2 y-2', () => {
                return Promise.resolve([
                    {
                        label: "item1",
                        value: 1234
                    },
                    {
                        label: "item2",
                        value: 1234
                    },
                    {
                        label: "item3",
                        value: 1234
                    }
                ])
            })



            // Sample Widget 6
            APIDash().textWidget('long text ( widget 6 )', 'width-2 height-1 x-3 y-3', () => {
                return Promise.resolve([
                    {
                        value: (1234).toLocaleString(),
                        label: "complete"
                    },
                    {
                        value: (5678).toLocaleString(),
                        label: "failed"
                    }
                ])
            })
        </script>
    </body>
</html>

recent posts

< back