HOME > Documentations > Yodeck User Manual > Count Down/Up Count Down/Up Posted by Kostas Sveronis on October 16th, 2020 Table of Contents The app’s HTML codeThe app’s JSON SchemaComplete ZIP Package The app’s HTML code The following app does the following: reads the app’s configuration and applies the required CSS for background color, font color, font family, font style, font-weight resizes text to fit the available window gets and displays time every second We also include a “js” folder with the jQuery library for easier HTML DOM manipulation. Count Down/Up index.htmlExpand source <!DOCTYPE html> <html> <head> <title>Countdown Clock</title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <style type="text/css"> html, body { background-color: transparent; font-family: tahoma; font-size: 90%; height: 100%; width: 100%; } * { margin: 0; padding: 0; } #countbox1 { height: 100%; text-align: center; white-space: nowrap; } </style> <script src="js/jquery.min.js"></script> <script src="js/moment.min.js"></script> <script src="js/moment-timezone-with-data.min.js"></script> <script language="javascript" type="text/javascript"> /*function that starts the clock*/ function countdown() { var now = moment().tz(window.widget_timezone); var timeToCompare = null; if(now < window.event_end){ timeToCompare = window.event_end } if(timeToCompare){ timeDiff = timeToCompare - now var d="",h="",m="",s=""; var amount = Math.floor(timeDiff/1000);//kill the "milliseconds" so just secs d=Math.floor(amount/86400);//days amount=amount%86400; h=Math.floor(amount/3600);//hours amount=amount%3600; m=Math.floor(amount/60);//minutes amount=amount%60; s=Math.floor(amount);//seconds s = checkTime(s); m = checkTime(m); h = checkTime(h); if(d != 0){ $('#countbox1>span').text(d + "d " + h + ":" + m + ":" + s); if (!window.days){ $('#countbox1').textfill({ maxFontPixels : $('#countbox1').height() }) window.days = true } } else if(h != 0){ $('#countbox1>span').text(h + ":" + m + ":" + s); if (!window.hours){ $('#countbox1').textfill({ maxFontPixels : $('#countbox1').height() }) window.hours = true } } else{ $('#countbox1>span').text(m + ":" + s); if (!window.minutes){ $('#countbox1').textfill({ maxFontPixels : $('#countbox1').height() }) window.minutes = true } } }else{ $('#countbox1>span').text(window.end_text); $('#countbox1').textfill({ maxFontPixels : $('#countbox1').height() }) return; } if (window.t) { clearTimeout(window.t) } /*repeat after one second*/ window.t = setTimeout(countdown, 1000); } function countup() { var now = moment().tz(window.widget_timezone); var timeToCompare = null if(now > window.event_start){ timeToCompare = window.event_start } if(timeToCompare){ timeDiff = now - timeToCompare var d="",h="",m="",s=""; var amount = Math.floor(timeDiff/1000);//kill the "milliseconds" so just secs d=Math.floor(amount/86400);//days amount=amount%86400; h=Math.floor(amount/3600);//hours amount=amount%3600; m=Math.floor(amount/60);//minutes amount=amount%60; s=Math.floor(amount);//seconds m = checkTime(m); s = checkTime(s); h = checkTime(h); if(d != 0){ $('#countbox1>span').text(d + "d " + h + ":" + m + ":" + s); if (!window.days){ $('#countbox1').textfill({ maxFontPixels : $('#countbox1').height() }) window.days = true } } else if(h != 0){ $('#countbox1>span').text(h + ":" + m + ":" + s); if (!window.hours){ $('#countbox1').textfill({ maxFontPixels : $('#countbox1').height() }) window.hours = true } } else{ $('#countbox1>span').text(m + ":" + s); if (!window.minutes){ $('#countbox1').textfill({ maxFontPixels : $('#countbox1').height() }) window.minutes = true } } }else{ $('#countbox1>span').text(window.start_text); } if (window.t) { clearTimeout(window.t) } /*repeat after one second*/ window.t = setTimeout(countup, 1000); } /*function that appends a zero to single digit numbers*/ function checkTime(i) { if (i < 10) { i = "0" + i } ; // add zero in front of numbers < 10 return i; } //function that starts the widget function init_widget(config) { if (!config) { console.log("no json configuration found"); return; } /*apply css based on configuration*/ if ("bgcolor" in config) { window.bgcolor = hexToRGBA(config.bgcolor) if (window.bgcolor) { $('body').css('background-color', window.bgcolor) } } if ("color" in config) { window.color = hexToRGBA(config.color) if (window.color) { $('#countbox1').css('color', window.color) } } window.widget_timezone = moment.tz.guess(); if ('fontfamily' in config) { $('#countbox1').css('font-family', config['fontfamily']) } if ('fontstyle' in config) { $('#countbox1').css('font-style', config['fontstyle']) } if ('fontweight' in config) { $('#countbox1').css('font-weight', config['fontweight']) } if ("event_start" in config) { window.event_start = moment(config.event_start,"YYYY-MM-DD[T]HH:mm:ss") } else{ window.event_start = moment() } if ("event_end" in config) { window.event_end = moment(config.event_end,"YYYY-MM-DD[T]HH:mm:ss") } else{ window.event_end = moment() } if("count_type" in config){ if(config['count_type'] == 'Count-up'){ window.count_up = true } else{ window.count_up = false } } if("end_text" in config){ window.end_text = config['end_text'] }else{ window.end_text = "" } if("start_text" in config){ window.start_text = config['start_text'] }else{ window.start_text = "" } window.minutes = false window.hours = false window.days = false } function start_widget() { var now = moment().tz(window.widget_timezone); var timeToCompare = null if(window.count_up){ if(now > window.event_start){ timeToCompare = window.event_start } if(!timeToCompare){ $('#countbox1>span').text(window.start_text); } countup() }else{ countdown() } $('#countbox1').show() /*resize text*/ $('#countbox1').textfill({ maxFontPixels : $('#countbox1').height() }) } function stop_widget() { if (window.t) { clearTimeout(window.t) } } /*test function to test while developing*/ function test_widget() { init_widget({ bgcolor : "black", color : "white", fontfamily : "arial", fontstyle : "normal", fontweight : "bold", event_end:"2018-06-29T11:40:50.000Z", event_start:"2018-06-29T09:37:00.000Z", count_type: "Count-down", start_text: "Starting", end_text: "Ending" }); start_widget() } /*function that turns an rgba hex to rgba css*/ function hexToRGBA(hex) { var r = parseInt(hex.substr(0, 2), 16); var g = parseInt(hex.substr(2, 2), 16); var b = parseInt(hex.substr(4, 2), 16); var a = Math.round((parseInt(hex.substr(6, 2), 16) / 255) * 100); a = a / 100; var rgba = 'rgba(' + r + ',' + g + ',' + b + ',' + a + ')'; return rgba; } /*function to resize text so that it fits to its container*/ (function($) { $.fn.textfill = function(options) { var fontSize = options.maxFontPixels; var ourText = $('span:first', this); var maxHeight = $(this).height(); var maxWidth = $(this).width(); var textHeight; var textWidth; while(true) { ourText.css('font-size', fontSize); textHeight = ourText.height(); textWidth = ourText.width(); //console.log(textHeight +' -- '+ maxHeight) //console.log(textWidth +' -- '+ maxWidth) if(fontSize < 5){ break; } if(textHeight > maxHeight){ fontSize = fontSize - Math.ceil(fontSize*(1-(maxHeight/textHeight))) continue; } if(textWidth > maxWidth){ fontSize = fontSize - Math.ceil(fontSize*(1-(maxWidth/textWidth))) continue; } break; } window.fontsize = fontSize; return this; } })(jQuery); </script> </head> <body> <div id="countbox1" hidden> <span>N/A</span> </div> </body> </html> The app’s JSON Schema we need the declare a schema for the required configuration fields: bgcolor: a color picker field that defines the widget’s background color. color: a color picker field that defines the widget’s font color. fontfamily: a select field with the available fonts fontstyle: a select field with the available font styles (normal, italic …) fontweight: a select field with the available font weight (normal, bold …) count_type: an option filed with the available Count types (Down/Up) start_text: a text field writing a before start message event_start: a time selector when the event will start end_text: a text field displaying an after end message event_end: a time selector when the event will end Count Down/Up schema.jsonExpand source { "fields": [ "bgcolor", "color", "fontfamily", "fontstyle", "fontweight", "count_type", "start_text", "event_start", "end_text", "event_end" ], "meta": { "details": "A simple timer that either counts up from an event or down to a deadline. The size of the timer gets automatically adjusted to the layout zone. Options include color and font customization.", "description": "A simple timer that either counts up from an event or down to a deadline. The size adjusts to the provided area.", "name": "Counter up/down" }, "data": { "count_type": "Count-down", "fontstyle": "<%=general_normal%>", "fontfamily": "Arial", "color": "white", "bgcolor": "black", "fontweight": "<%=general_normal%>" }, "schema": { "count_type": { "title": "<%=countupdown_counter_type%>", "type": "Select", "options": [ { "options": [ "Count-down", "Count-up" ], "hides": [ { "fields": [ "event_start", "start_text" ] }, { "fields": [ "event_end", "end_text" ] } ], "shows": [ { "fields": [ "event_end", "end_text" ] }, { "fields": [ "event_start", "start_text" ] } ] } ], "validators": [ "required" ] }, "fontstyle": { "title": "<%=general_font_style%>", "type": "Select", "options": [ "<%=general_normal%>", "<%=general_italic%>", "<%=general_oblique%>" ], "validators": [ "required" ] }, "end_text": { "type": "Text", "title": "<%=countupdown_text_after_end%>" }, "color": { "type": "SpectrumColorPicker", "title": "<%=general_font_color%>" }, "event_end": { "yearStart": 2000, "minsInterval": 1, "type": "DateTime", "yearEnd": 2030, "title": "<%=countupdown_event_end%>" }, "event_start": { "yearStart": 2000, "minsInterval": 1, "type": "DateTime", "yearEnd": 2030, "title": "<%=countupdown_event_start%>" }, "bgcolor": { "type": "SpectrumColorPicker", "title": "<%=general_background_color%>" }, "start_text": { "type": "Text", "title": "<%=countupdown_text_before_start%>" }, "fontfamily": { "title": "<%=general_font_family%>", "type": "Select", "options": [ "Arial", "Courier", "Comic Sans MS", "Georgia", "Times New Roman", "Trebuchet MS", "Verdana" ], "validators": [ "required" ] }, "fontweight": { "title": "<%=general_font_weight%>", "type": "Select", "options": [ "<%=general_normal%>", "<%=general_bold%>", "<%=general_bolder%>", "<%=general_lighter%>" ], "validators": [ "required" ] } } } Complete ZIP Package In the upload app page, we create a new app, upload the attached zip file and enter the schema given above. After that, we can create apps with the desired styling/configuration. You can download the complete ZIP file for the App from here: countdonwup.zip For any questions, you may have, reach out and our development team can help you out.