Одна из ниш компьютеров, которая мне всегда нравилась, — это цифровое искусство и дисплеи. Я нашел возможность сделать новый дисплей для отслеживания поступающих данных в API. Ниже я подготовил краткий отчет о том, как я преобразовывал прерывистые вызовы API в аналитический дисплей, отражающий данные в реальном времени.
Эта программа достаточно проста, чтобы ее можно было написать на одной HTML-странице со встроенным javascript. Не лучшая форма, но она выполнит работу без накладных расходов.
Общая структура программы выглядит следующим образом:
- Получить текущую сумму данных из API аналитики
- Подсчитайте, насколько эта сумма выше предыдущей, а затем рассчитайте изменение в секунду.
- Используйте setInterval() JavaScript для обновления счетчика на экране несколько раз в секунду, чтобы отразить рассчитанное изменение в секунду.
Единственная сложность этого плана заключается в том, что функция setInterval() не дает гарантий времени. Это означает, что если вы установите интервал 10 раз в секунду, Javascript будет пытаться поместить функцию в стек 10 раз в секунду, но функция может не выполняться 10 раз в секунду. Это приводит к тому, что счетчик сильно сбивается с пути, если его оставить работать достаточно долго.
Чтобы решить эту проблему, я добавил дополнительную переменную «speedUp», используемую для регулировки скорости счета как вверх, так и вниз по мере необходимости во время выполнения программы. Возможно, проще было бы просто пересчитать точную величину увеличения 10 раз в секунду, но я хотел как вызов, так и очень гладкий счетчик. Код настройки скорости можно найти в методе stepClock().
В итоге у нас есть очень простой и надежный счетчик, который можно запустить на Raspberry Pi или любом другом микрокомпьютере. Потенциальное хорошее применение для любых старых мониторов, лежащих в офисе.
Код ниже. Одна HTML-страница со встроенным скриптом и стилями. Я настоятельно рекомендую использовать файл ENV для ваших токенов и URL-адресов API.
<!DOCTYPE html> <html> <head> <title>ticker</title> </head> <body> <div class="title">Total Data</div> <div id="count" class="count">50,000</div> <div id="velocity" class="velocity">10,000 per Hour</div> <script src="https://code.jquery.com/jquery-3.2.1.min.js" integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4=" crossorigin="anonymous"></script> <script type="text/javascript"> var currentData = 0; var oldTarget = 0; var targetData = 0; var increment = 0; var perSec = 10; var intervalDate = new Date(); var speedUp = 1; var speedUpBase = 1.1; //distance between api calls in seconds var checkDistance = (10 * 60); //calculating the velocity of data function setPerHr() { var change = targetData - oldTarget; var checkToHour = (60 * 60) / checkDistance ; var perHr = change * checkToHour; document.getElementById('velocity').innerHTML = perHr.toLocaleString() + ' per Hour'; } //parsing the api response function examineData(data) { var total = data; if (currentData == 0) { currentData = total - 10000; oldTarget = total - 10000; } else { console.log('skipped amount'); console.log(targetData - currentData); currentData = targetData; oldTarget = targetData; } console.log('new target set at:') console.log(new Date().toLocaleString()); console.log(total); intervalDate = new Date(); targetData = total; increment = (targetData - currentData) / checkDistance; setPerHr(); } function updateTotals() { //token in gitignore file. return $.ajax({ 'url': [API URL HERE], 'contentType': 'application/json; charset=utf-8', 'data': [AUTH TOKEN HERE], 'type': 'POST', success: examineData }) } function stepClock(element) { var useIncrement = increment; var time = new Date(); var distanceCovered = (time - intervalDate) / (checkDistance * 1000); //if ground covered less than what should be covered var toBeCovered = (targetData - oldTarget) * (1 - distanceCovered); if ((targetData - currentData) > toBeCovered) { speedUp += 0.01; useIncrement *= speedUp; console.log('faster'); //if counter is too far ahead ~ 1% buffer } else if ((targetData - currentData) < (toBeCovered * 0.99)) { if (speedUp > speedUpBase) { speedUp = speedUpBase; } if (speedUp > 0.01) { speedUp -= 0.01; } useIncrement *= speedUp; console.log('slower'); } else { if (speedUp > (speedUpBase)) { speedUp -= 0.01; } else { speedUp = speedUpBase; } } element.innerHTML = (Math.round(currentData += (useIncrement / perSec))).toLocaleString(); //check both high and low to avoid a blast of api requests if (((time - intervalDate) > checkDistance * 1000) && ((time - intervalDate) < (checkDistance * 1000) + 10000)) { //setting this to try to reduce multiple triggers of this condition intervalDate = time; updateTotals(); } } function onStart() { var element = document.getElementById('count'); //checking the api every "checkDistance" num of seconds apart. updateTotals(); function incrementer() { stepClock(element); } //updating the on screen counter //updates the counter and checks if api needs to be rechecked. setInterval(incrementer, (1000 / perSec)); } onStart(); </script> <link href='https://fonts.googleapis.com/css?family=Orbitron' rel='stylesheet' type='text/css'> <style type="text/css"> body { background-color: black; } .count { color: #00E500; font-size: 150px; font-family: 'Orbitron', sans-serif; border-bottom: solid 5px #00E500; border-top: solid 5px #00E500; padding: 25px 30px 0px 50px; } .title { color: #00E500; font-size: 150px; font-family: 'Orbitron', sans-serif; padding: 10px 30px 10px 50px; } .velocity { color: #00E500; font-size: 40px; font-family: 'Orbitron', sans-serif; padding: 15px 30px 0px 50px; } </style> </body> </html>