Script zum Auslesen der corona statistik für jarvis visualisierung
Mein Setup für jarvis zur Darstellung
Für die Filter Statelist horizontal
Für die Ausgabe customHtml
Für das Aufbereiten des Designs in den Einstellungen Styles (pro)
das Script wird im javascript adapter hinterlegt:
const moment = require("moment");
//Datumsformat
moment.locale('de');
let fRkiFaktor = 1.00443;
/****** DATENPUNKTE MÜSSEN ERSTELLT WERDEN (Name Pfad frei konfigurierbar) **********/
/**role html, type string (Typ = Zeichenkette) */
let coronaHtmlDp = '0_userdata.0.vis.jarvis.coronahtml';
// verwendet in function write_corona_stats() und für die Aktivierung der Eventlistener
/**role switch, type boolean (Typ = Logikwert) */
/**FILTER: setze den Wert auf false und der ausgewählte Datenpunkt wird nicht angezeigt */
let filterDp = {
'states': '0_userdata.0.vis.jarvis.corona.filter.bundeslaender',
'cities': '0_userdata.0.vis.jarvis.corona.filter.cities',
'countries': '0_userdata.0.vis.jarvis.corona.filter.countries',
'top5': '0_userdata.0.vis.jarvis.corona.filter.top5stats',
}
/******ENDE DATENPUNKTE MÜSSEN ERSTELLT WERDEN **********/
let countrySelector = '[id=coronavirus-statistics.0.*.population]';
let oListCountry = $(countrySelector);
let stateSelector = '[id=coronavirus-statistics.0.Germany.Bundesland.*.cases]';
let oListState = $(stateSelector);
let kreisSelector = '[id=coronavirus-statistics.0.Germany.Kreis.*.BL]';
let oListKreis = $(kreisSelector);
let stadtSelector = '[id=coronavirus-statistics.0.Germany.Stadt.*.BL]';
let oListStadt = $(stadtSelector);
//Mapper für Länder und Statistiken top5 und weltweit (nicht benötigte Datenpunkte können auskommentiert werden)
let oSchemeCountry = {
'updated': { 'title': 'zuletzt aktualisiert', 'format': 'datetime' },
'population': { 'title': 'Einwohnerzahl', 'format': 'int' },
'cases': { 'title': 'Fälle gesamt', 'format': 'int' },
'active': { 'title': 'Aktuell infiziert', 'format': 'int' },
'critical': { 'title': 'Im kritischen Zustand', 'format': 'int' },
'recovered': { 'title': 'Genesene', 'format': 'int' },
'tests': { 'title': 'Testungen', 'format': 'int' },
'deaths': { 'title': 'Todesfälle', 'format': 'int' },
'todayCases': { 'title': 'Heute neu infiziert', 'format': 'int' },
'todayDeaths': { 'title': 'Heute Todesfälle', 'format': 'int' },
'todayRecovered': { 'title': 'Heute Genesene', 'format': 'int' },
};
//Mapper für Bundesländer (nicht benötigte Datenpunkte können auskommentiert werden)
let oSchemeState = {
'updated': { 'title': 'zuletzt aktualisiert', 'format': 'datetime' },
'cases': { 'title': ' COVID-19 Fälle gesamt', 'format': 'int' },
'cases7_per_100k': { 'title': '7-Tage-Inzidenz', 'format': 'float' },
'deaths': { 'title': 'COVID-19 Todesfälle', 'format': 'int' },
};
//Mapper für Stadt und Kreise (nicht benötigte Datenpunkte können auskommentiert werden)
// hat ein title den Eintrag object wird der Name des Datenpunktes verwendet
let oScheme = {
'BL': { 'title': 'object', 'format': 'string' },
'cases': { 'title': 'COVID-19 Fälle gesamt', 'format': 'int' },
// 'cases_per_100k': { 'title': 'object', 'format': 'float' },
// 'cases_per_population': { 'title': 'object', 'format': 'float' },
// 'death_rate': { 'title': 'object', 'format': 'float' },
'deaths': { 'title': 'COVID-19 Todesfälle', 'format': 'int' },
'cases7_per_100k': { 'title': '7-Tage-Inzidenz', 'format': 'float' },
};
//Mapper für grafische Darstellung 7-Tages-Inzidenz verwendet in function calcGefahrInzidenz()
let oScheme7Tg = {
'ok': { 'title': 'Status ok', 'bgcolor': 'green', 'color': '#fff' },//wert 0 - 35
'critical': { 'title': 'Status kritisch', 'bgcolor': 'orange', 'color': '#fff' }, //wert 35 - 50
'high': { 'title': 'Status hoch', 'bgcolor': 'red', 'color': '#fff' }, // 50 - 100
'veryhigh': { 'title': 'Status sehr hoch Notbremse aktiviert', 'bgcolor': 'darkred', 'color': '#fff' }// > 100
};
//Mapper für erlaubte Dinge 7-Tages-Inzidenz verwendet in function calcGefahrInzidenz()
let oSchemeAllowed = {
'ok': [// 0 - 35
{ 'title': 'Privat', 'descr': '3 Haushalte max. zehn Personen, Kinder bis 14 Jahre nicht mitgezählt' },
{ 'title': 'Geschäfte', 'descr': 'Einzelhandel mit kontrollierten Einlass' },
{ 'title': 'Freizeit', 'descr': 'Museen, Galerien, Zoos, Botanische Gärten, Gedenkstätten' },
{ 'title': 'Sport', 'descr': 'Außensport kontaktfrei (max. 10 Personen)' },
{ 'title': 'Gastronomie', 'descr': 'erst ab 22. März' },
],
'critical': [ // 35 - 50
{ 'title': 'Privat', 'descr': 'Max 5 Personen aus zwei Haushalten, Kinder bis 14 Jahre nicht mitgezählt' },
{ 'title': 'Geschäfte', 'descr': 'Einzelhandel mit kontrollierten Einlass' },
{ 'title': 'Freizeit', 'descr': 'Museen, Galerien, Zoos, Botanische Gärten, Gedenkstätten' },
{ 'title': 'Sport', 'descr': 'Außensport kontaktfrei (max. 10 Personen)' },
{ 'title': 'Gastronomie', 'descr': 'erst ab 22. März' },
],
'high': [ // 50 - 100
{ 'title': 'Privat', 'descr': 'Max 5 Personen aus zwei Haushalten, Kinder bis 14 Jahre nicht mitgezählt' },
{ 'title': 'Geschäfte', 'descr': 'Einzelhandel Click & Collect oder Click & Meet (40 Quadratmeter pro Person), Kontaktdatenerhebung' },
{ 'title': 'Freizeit', 'descr': 'Museen, Galerien, Zoos, Botanische Gärten, Gedenkstätten nur mit Terminbuchung' },
{ 'title': 'Sport', 'descr': 'Individualsport außen, max 5 Personen aus 2 Haushalten' },
{ 'title': 'Gastronomie', 'descr': 'erst ab 22. März' },
],
'veryhigh': [ // > 100
{ 'title': 'Privat', 'descr': 'ein Haushalt und eine weitere Person, nächtliche Ausgangssperre' },
{ 'title': 'Geschäfte', 'descr': 'Einzelhandel geschlossen' },
{ 'title': 'Freizeit', 'descr': 'Museen, Galerien, Zoos, Botanische Gärten, Gedenkstätten geschlossen' },
{ 'title': 'Sport', 'descr': 'Individualsport nur allein' },
{ 'title': 'Gastronomie', 'descr': 'erst ab 22. März' },
{ 'title': 'Kindergärten und Kitas', 'descr': 'geschlossen, nur Notbetreuung' },
{ 'title': 'Schulen', 'descr': 'nur Distanzunterricht' },
],
};
//Mapper für Legende Landkreise und Städte
let oSchemeLegende = {
'city': [
{ 'title': 'Hinweis', 'descr': 'Zudem gilt die sogenannte Notbremse: Steigt die 7-Tage-Inzidenz pro 100.000 Einwohner an drei aufeinander folgenden Tagen in einem Landkreis oder einer kreisfreien Stadt über 100, treten die Regeln, die vor dem 8. März gegolten hatten, wieder in Kraft.' }
],
};
//Eventlistener for filter
for (const [key, dp] of Object.entries(filterDp)) {
on({ id: dp }, write_corona_stats);
};
write_corona_stats();
function write_corona_stats() {
try {
let sStateOut = '';
let sOutSumGermany = '';
//Liste ausgewählter Bundesländer
var calcInzidenzSum = 0.00;
if (oListState.length > 0) {
let bShowStates = getState(filterDp.states).val;
sStateOut = '<div class="co-container states">';
oListState.each((item, index) => {
let iStateID = item.replace('.cases', '');
if (bShowStates === true) {
let sStateName = iStateID.replace('coronavirus-statistics.0.Germany.Bundesland.', '');
sStateOut += '<div class="co-container"><div class="co-heading state">' + sStateName + '</div>';
}
for (const [key, dp] of Object.entries(oSchemeState)) {
if (bShowStates === true) {
sStateOut += builElements(key, dp, iStateID, false, '');
}
if (key === 'cases7_per_100k') {
calcInzidenzSum += parseFloat(getState(iStateID + '.' + key).val);
}
}//End for
if (bShowStates === true) {
sStateOut += '</div>';
}
});
if (oListState.length === 16) {
let calc7IndDe = (calcInzidenzSum / oListState.length * fRkiFaktor);
let fCalc7IndDe = calc7IndDe.toFixed(2);
let sCalc7IndDe = number_format(calc7IndDe, 2, ',', '.');
let oReturn = calcGefahrInzidenz(fCalc7IndDe, sCalc7IndDe, false);
let valc7IndDe = oReturn.val;
sOutSumGermany = '<div class="co-entry de-7-inz horizontal"><div class="co-descr">7-Tage-Inzidenz</div><div class="co-val">' + valc7IndDe + '</div></div>';
}
sStateOut += '</div>';
}
//Liste ausgewählter Länder
let sCountryOut = '';
if (oListCountry.length > 0) {
let bShowTop5 = getState(filterDp.top5).val;
let bCountries = getState(filterDp.countries).val;
//only countries
if (bCountries === true) {
sCountryOut = '<div class="co-container countries">';
oListCountry.each((item, index) => {
let iCountryID = item.replace('.population', '');
if ((iCountryID.indexOf("country_Top_5") === -1 && iCountryID.indexOf("global_totals") === -1)) {
let sCountryName = iCountryID.replace('coronavirus-statistics.0.', '');
let sFlag = '<img class="co-flag" src="' + getState(iCountryID + '.flag').val + '"> ';
let sCountryNameTrans = sFlag + sCountryName;
if (sCountryName === 'Germany') {
sCountryNameTrans = sFlag + 'Deutschland';
}
sCountryOut += '<div class="co-container country"><div class="co-heading country">' + sCountryNameTrans + '</div>';
for (const [key, dp] of Object.entries(oSchemeCountry)) {
sCountryOut += builElements(key, dp, iCountryID, false, 'horizontal');
}//End for
if (sCountryName === 'Germany') {
sCountryOut += sOutSumGermany;
}
sCountryOut += '</div>';
}
});
sCountryOut += '</div>';
}
//only stats
if (bShowTop5 === true) {
sCountryOut += '<div class="co-container stats">';
oListCountry.each((item, index) => {
let iCountryID = item.replace('.population', '');
if (iCountryID.indexOf("country_Top_5") > -1 || iCountryID.indexOf("global_totals") > -1) {
let sCountryName = iCountryID.replace('coronavirus-statistics.0.', '');
let sFlag = '';
if (iCountryID.indexOf("global_totals") === -1) {
sFlag = '<img class="co-flag" src="' + getState(iCountryID + '.flag').val + '"> ';
}
let sCountryNameTrans = sFlag + sCountryName;
if (sCountryName.indexOf("country_Top_5") > -1) {
let obj = getObject(iCountryID);
sCountryNameTrans = sFlag + obj.common.name;
} else if (sCountryName.indexOf("global_totals") > -1) {
sCountryNameTrans = 'Weltweit gesamt';
}
sCountryOut += '<div class="co-container country"><div class="co-heading stats">' + sCountryNameTrans + '</div>';
for (const [key, dp] of Object.entries(oSchemeCountry)) {
sCountryOut += builElements(key, dp, iCountryID, false, '');
}//End for
sCountryOut += '</div>';
}
});
sCountryOut += '</div>';
}
}
//Liste Landkreise
let sCityCountiesOut = '';
if (oListKreis.length > 0 && getState(filterDp.cities).val === true) {
oListKreis.each((item, index) => {
let iKreisID = item.replace('.BL', '');
let sKreisName = iKreisID.replace('coronavirus-statistics.0.Germany.Kreis.', '');
sCityCountiesOut += '<div class="co-container"><div class="co-heading county">' + 'Kreis ' + sKreisName + '</div>';
for (const [key, dp] of Object.entries(oScheme)) {
sCityCountiesOut += builElements(key, dp, iKreisID, true, '');
}//End for
sCityCountiesOut += '</div>';
});//end each
}
//Liste kreisfreie Städte
if (oListStadt.length > 0 && getState(filterDp.cities).val === true) {
oListStadt.each((item, index) => {
let iStadtID = item.replace('.BL', '');
let sStadtName = iStadtID.replace('coronavirus-statistics.0.Germany.Stadt.', '');
sCityCountiesOut += '<div class="co-container"><div class="co-heading city">' + 'Stadt ' + sStadtName + '</div>';
for (const [key, dp] of Object.entries(oScheme)) {
sCityCountiesOut += builElements(key, dp, iStadtID, true, '');
}//End for
sCityCountiesOut += '</div>';
});//end each
}
if (sCityCountiesOut !== '') {
let sLegende = '<div class="co-legende">';
for (const [key, element] of Object.entries(oSchemeLegende.city)) {
sLegende += '<b>' + element.title + '</b>: ' + element.descr;
};
sLegende += '</div>';
sCityCountiesOut = '<div class="co-container cities-counties">' + sCityCountiesOut + sLegende + '</div>';
}
var sHtml = '<div class="co-overview">';
sHtml += sCountryOut + sStateOut + sCityCountiesOut;
setState(coronaHtmlDp, sHtml);
} catch (err) {
console.error('[CoronaStatus] error: ' + err.message + ', stack: ' + err.stack);
}
}
function builElements(key, dp, dpId, bAllow, cssClass) {
let descr = '';
let val = '';
let sList = '';
let sOut = '';
if (dp.title === 'object') {
let obj = getObject(dpId + '.' + key);
descr = obj.common.name;
} else {
descr = dp.title
}
if (dp.format === 'string') {
val = getState(dpId + '.' + key).val;
} else if (dp.format === 'datetime') {
let valDate = getState(dpId + '.' + key).val;
val = moment(valDate).format('DD.MM.YYYY HH:mm');
} else if (dp.format === 'int') {
val = getState(dpId + '.' + key).val;
val = number_format(val, 0, '', '.');
} else if (dp.format === 'float') {
let fVal = parseFloat(getState(dpId + '.' + key).val).toFixed(2);
val = number_format(fVal, 2, ',', '.');
if (key === 'cases7_per_100k') {
let oReturn = calcGefahrInzidenz(fVal, val, bAllow);
val = oReturn.val;
sList = (oReturn.list !== '') ? '<div class="co-allowed-list">' + oReturn.list + '</div>' : '';
}
}
sOut = '<div class="co-entry co-dp-' + key + ' ' + cssClass + '"><div class="co-descr">' + descr + '</div><div class="co-val">' + val + '</div></div>';
if (sList !== '') {
sOut += sList;
}
return sOut;
}
function calcGefahrInzidenz(fVal, sVal, isAllowed) {
let iVal = parseInt(fVal);
let val = '';
let sListAllowed = '';
if (iVal < 35) {
val = '<span class="badge" title="' + oScheme7Tg.ok.title + '" style="background-color:' + oScheme7Tg.ok.bgcolor + ';color:' + oScheme7Tg.ok.color + ';">' + sVal + '</span>';
if (isAllowed === true) {
sListAllowed = '<ul class="co-list">';
for (const [key, element] of Object.entries(oSchemeAllowed.ok)) {
sListAllowed += '<li><b>' + element.title + '</b>: ' + element.descr + '</li>';
};
sListAllowed += '</ul>';
}
} else if (iVal >= 35 && iVal < 50) {
val = '<span class="badge" title="' + oScheme7Tg.critical.title + '" style="background-color:' + oScheme7Tg.critical.bgcolor + ';color:' + oScheme7Tg.critical.color + ';">' + sVal + '</span>';
if (isAllowed === true) {
sListAllowed = '<ul class="co-list">';
for (const [key, element] of Object.entries(oSchemeAllowed.critical)) {
sListAllowed += '<li><b>' + element.title + '</b>: ' + element.descr + '</li>';
};
sListAllowed += '</ul>';
}
} else if (iVal >= 50 && iVal < 100) {
val = '<span class="badge" title="' + oScheme7Tg.high.title + '" style="background-color:' + oScheme7Tg.high.bgcolor + ';color:' + oScheme7Tg.high.color + ';">' + sVal + '</span>';
if (isAllowed === true) {
sListAllowed = '<ul class="co-list">';
for (const [key, element] of Object.entries(oSchemeAllowed.high)) {
sListAllowed += '<li><b>' + element.title + '</b>: ' + element.descr + '</li>';
};
sListAllowed += '</ul>';
}
} else if (iVal >= 100) {
val = '<span class="badge" title="' + oScheme7Tg.veryhigh.title + '" style="background-color:' + oScheme7Tg.veryhigh.bgcolor + ';color:' + oScheme7Tg.veryhigh.color + ';">' + sVal + '</span>';
if (isAllowed === true) {
sListAllowed = '<ul class="co-list">';
for (const [key, element] of Object.entries(oSchemeAllowed.veryhigh)) {
sListAllowed += '<li><b>' + element.title + '</b>: ' + element.descr + '</li>';
};
sListAllowed += '</ul>';
}
}
let oReturn = { 'val': val, 'list': sListAllowed };
return oReturn;
}
//taken from https://gist.github.com/VassilisPallas/d73632e9de4794b7dd10b7408f7948e8/bf17eccef8521b4e5869bdc6a5b09a771356fbff
function number_format(intFloatNumber, decimals, dec_point, thousands_point) {
if (intFloatNumber == null || !isFinite(intFloatNumber)) {
throw new TypeError("number is not valid");
}
if (!decimals) {
let len = intFloatNumber.toString().split('.').length;
decimals = len > 1 ? len : 0;
}
dec_point = (!dec_point) ? '.' : dec_point;
thousands_point = (!thousands_point) ? '.' : thousands_point;
intFloatNumber = parseFloat(intFloatNumber).toFixed(decimals);
intFloatNumber = intFloatNumber.replace(".", dec_point);
var splitNum = intFloatNumber.split(dec_point);
splitNum[0] = splitNum[0].replace(/\B(?=(\d{3})+(?!\d))/g, thousands_point);
intFloatNumber = splitNum.join(dec_point);
return intFloatNumber;
}
Das erforderliche Css für das Design:
/*corona*/
.co-overview{
position: relative;
width: 100% ;
display: inline-block;
box-sizing:border-box;
}
.co-container{
position: relative;
width: calc(25% - 20px);
display: inline-block;
box-sizing:border-box;
margin:10px;
vertical-align:text-top;
background-color:#f4f4f4;
border-radius:8px;
}
.co-container.stats,
.co-container.cities-counties,
.co-container.countries,
.co-container.states{
width: 100%;
background-color:#fff;
margin:0;
padding:0;
}
.co-container.stats .co-container{
width:calc(33.333% - 20px);
margin:10px;
}
.co-container.stats .co-container,
.co-container.countries .co-container,
.co-container.cities-counties .co-container,
.co-container.states .co-container{
box-shadow: 0px 2px 1px -1px rgba(0,0,0,0.2),0px 1px 1px 0px rgba(0,0,0,0.14),0px 1px 3px 0px rgba(0,0,0,0.12);
background-color:#fff;
}
.co-container.country{
width: calc(100% - 20px);
}
.co-legende{
width: calc(100% - 20px);
padding: 10px;
background: #FFCCBC;
position: relative;
margin-left: 10px;
box-sizing: border-box;
border-radius:8px;
box-shadow: 0px 2px 1px -1px rgba(0,0,0,0.2),0px 1px 1px 0px rgba(0,0,0,0.14),0px 1px 3px 0px rgba(0,0,0,0.12);
margin-bottom: 10px;
margin-top:10px;
}
.co-heading{
position: relative;
width: 100%;
display: inline-block;
font-weight:bold;
padding: 0 5px;
box-sizing: border-box;
}
.co-heading.stats,
.co-heading.country,
.co-heading.county,
.co-heading.city,
.co-heading.state{
background: #2196F3;
font-size: 14px;
line-height: 35px;
color: #fff;
font-weight: normal;
border-top-left-radius: 8px;
border-top-right-radius: 8px;
}
.co-heading.stats{
background:#F57C00;
}
.co-heading.country{
background:#880E4F;
}
.co-heading.county,
.co-heading.city{
background: #00796B;
}
img.co-flag{
height:15px;
width:auto;
}
.co-entry{
position: relative;
width: 100%;
display: inline-block;
padding: 0 10px;
box-sizing:border-box;
}
.co-entry .badge{
font-size:12px;
padding: 0px 4px;
border-radius: 4px;
}
.co-descr{
position: relative;
width: 60%;
display: inline-block;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.co-val{
position: relative;
width: 40%;
display: inline-block;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
text-align:right;
}
.co-container.states .co-entry.co-dp-updated,
.co-container.stats .co-entry.co-dp-updated{
font-size:11px;
}
.co-container.countries .co-entry.co-dp-updated.horizontal{
font-size:14px;
}
.co-entry.horizontal{
width: calc(16.6666% - 20px);
margin: 17px 10px;
background:#fff;
border-radius:8px;
padding:0;
box-shadow: 0px 2px 1px -1px rgba(0,0,0,0.2),0px 1px 1px 0px rgba(0,0,0,0.14),0px 1px 3px 0px rgba(0,0,0,0.12);
}
.co-entry.horizontal .co-descr,
.co-entry.horizontal .co-val{
width:100%;
text-align:center;
}
.co-entry.horizontal .co-val{
font-weight:bold;
}
.co-entry.horizontal .co-descr{
background: #880E4F;
font-size: 14px;
line-height: 35px;
color: #fff;
font-weight: normal;
border-top-left-radius: 8px;
border-top-right-radius: 8px;
}
.co-allowed-list{
position: relative;
width: 100%;
display: inline-block;
padding: 10px;
background-color: #EAEAB9;
border-bottom-left-radius: 8px;
box-sizing: border-box;
margin-top: 10px;
border-bottom-right-radius: 8px;
}
.co-list{
margin:0;
padding:0;
list-style:none;
position:relative;
width:100%;
display:inline-block;
}
.co-list li{
position:relative;
width:100%;
font-size:14px;
line-height:18px;
marign-bottom:4px;
}
/*corona*/
@media (max-width: 768px) {
.co-container.stats .co-container {
width: calc(50% - 20px);
}
.co-container{
width: calc(50% - 20px);
}
}
@media (max-width: 536px) {
.co-container{
width: calc(100% - 20px);
}
.co-container.stats .co-container {
width: calc(100% - 20px);
}
.co-entry.horizontal {
width: calc(50% - 20px);
}
}
Have fun!