Skip to content

Instantly share code, notes, and snippets.

@tzschies
Forked from rphl/incidence.js
Last active February 17, 2022 23:35
Embed
What would you like to do?
COVID-19 Inzidenz-Widget für iOS innerhalb Deutschlands 🇩🇪 (Kreis/Stadt + Bundesland + Trend)
// Variables used by Scriptable.
// These must be at the very top of the file. Do not edit.
// icon-color: red; icon-glyph: briefcase-medical;
// LICENCE: Robert Koch-Institut (RKI), dl-de/by-2-0
// BASE VERSION FORKED FROM AUTHOR: kevinkub https://gist.github.com/kevinkub/46caebfebc7e26be63403a7f0587f664
// UPDATED VERSION FORKED FROM AUTHOR: rphl https://gist.github.com/rphl/0491c5f9cb345bf831248732374c4ef5
// NEW VERSION BY AUTHOR: tzschies https://gist.github.com/tzschies/563fab70b37609bc8f2f630d566bcbc9
/*********************************************
* CONFIGURATION PARAMETERS
********************************************/
// set to 'MeldeDatum' for the day when number of cases were reported
// set to 'RefDatum' for the day of start of illness
const datumType = 'MeldeDatum'
// because there are often late registrations some days later,
// you can change the determination of the trend
// set to 1: the trend is positive, if the incidence of yesterday is higher than the week before
// set to 0: the trend is positive, if the incidence of today is higher than the week before
const trendDaysOffset = 1
// because there are often late registrations some days later,
// you can optionally display the incidence of yesterday
// in most cases this is the more realistic value
// set to true for showing Incidence of Yesterday
// set to false for showing the API-Value of today
const showIncidenceYesterday = false
/*****************************************************************
*
* END OF CONIFURATION
*
*****************************************************************/
const outputFields = 'GEN,RS,EWZ,EWZ_BL,BL_ID,cases,cases_per_100k,cases7_per_100k,cases7_bl_per_100k,last_update,BL';
const apiUrl = (location) => `https://services7.arcgis.com/mOBPykOjAyBO2ZKk/arcgis/rest/services/RKI_Landkreisdaten/FeatureServer/0/query?where=1%3D1&outFields=${outputFields}&geometry=${location.longitude.toFixed(3)}%2C${location.latitude.toFixed(3)}&geometryType=esriGeometryPoint&inSR=4326&spatialRel=esriSpatialRelWithin&returnGeometry=false&outSR=4326&f=json`
const outputFieldsStates = 'Fallzahl,LAN_ew_GEN,cases7_bl_per_100k';
const apiUrlStates = `https://services7.arcgis.com/mOBPykOjAyBO2ZKk/arcgis/rest/services/Coronaf%E4lle_in_den_Bundesl%E4ndern/FeatureServer/0/query?where=1%3D1&outFields=${outputFieldsStates}&returnGeometry=false&outSR=4326&f=json`
const apiUrlNewCasesLK = (LandkreisId) => `https://services7.arcgis.com/mOBPykOjAyBO2ZKk/arcgis/rest/services/RKI_COVID19/FeatureServer/0/query?f=json&where=NeuerFall%20IN(1%2C%20-1)+AND+IdLandkreis=${LandkreisId}&objectIds=&time=&resultType=standard&outFields=&returnIdsOnly=false&returnUniqueIdsOnly=false&returnCountOnly=false&returnDistinctValues=false&cacheHint=false&orderByFields=&groupByFieldsForStatistics=&outStatistics=%5B%7B%22statisticType%22%3A%22sum%22%2C%22onStatisticField%22%3A%22AnzahlFall%22%2C%22outStatisticFieldName%22%3A%22value%22%7D%5D&having=&resultOffset=&resultRecordCount=&sqlFormat=none&token=`
const apiUrlCasesLKDays = (LandkreisId, StartDate) => `https://services7.arcgis.com/mOBPykOjAyBO2ZKk/arcgis/rest/services/RKI_COVID19/FeatureServer/0/query?where=NeuerFall+IN%281%2C0%29+AND+IdLandkreis=${LandkreisId}+AND+${datumType}+%3E%3D+TIMESTAMP+%27${StartDate}%27&objectIds=&time=&resultType=standard&outFields=AnzahlFall%2C${datumType}&returnIdsOnly=false&returnUniqueIdsOnly=false&returnCountOnly=false&returnDistinctValues=false&cacheHint=false&orderByFields=&groupByFieldsForStatistics=${datumType}&outStatistics=%5B%7B%22statisticType%22%3A%22sum%22%2C%22onStatisticField%22%3A%22AnzahlFall%22%2C%22outStatisticFieldName%22%3A%22value%22%7D%5D%0D%0A&having=&resultOffset=&resultRecordCount=&sqlFormat=none&f=pjson&token=`
const apiUrlNewCasesBL = (BundeslandId) => `https://services7.arcgis.com/mOBPykOjAyBO2ZKk/arcgis/rest/services/RKI_COVID19/FeatureServer/0/query?f=json&where=NeuerFall%20IN(1%2C%20-1)+AND+IdBundesland=${BundeslandId}&objectIds=&time=&resultType=standard&outFields=&returnIdsOnly=false&returnUniqueIdsOnly=false&returnCountOnly=false&returnDistinctValues=false&cacheHint=false&orderByFields=&groupByFieldsForStatistics=&outStatistics=%5B%7B%22statisticType%22%3A%22sum%22%2C%22onStatisticField%22%3A%22AnzahlFall%22%2C%22outStatisticFieldName%22%3A%22value%22%7D%5D&having=&resultOffset=&resultRecordCount=&sqlFormat=none&token=`
const apiUrlCasesBLDays = (BundeslandId, StartDate) => `https://services7.arcgis.com/mOBPykOjAyBO2ZKk/arcgis/rest/services/RKI_COVID19/FeatureServer/0/query?where=NeuerFall+IN%281%2C0%29+AND+IdBundesland=${BundeslandId}+AND+${datumType}+%3E%3D+TIMESTAMP+%27${StartDate}%27&objectIds=&time=&resultType=standard&outFields=AnzahlFall%2C${datumType}&returnIdsOnly=false&returnUniqueIdsOnly=false&returnCountOnly=false&returnDistinctValues=false&cacheHint=false&orderByFields=&groupByFieldsForStatistics=${datumType}&outStatistics=%5B%7B%22statisticType%22%3A%22sum%22%2C%22onStatisticField%22%3A%22AnzahlFall%22%2C%22outStatisticFieldName%22%3A%22value%22%7D%5D%0D%0A&having=&resultOffset=&resultRecordCount=&sqlFormat=none&f=pjson&token=`
const apiUrlNewCases = `https://services7.arcgis.com/mOBPykOjAyBO2ZKk/arcgis/rest/services/RKI_COVID19/FeatureServer/0/query?f=json&where=NeuerFall%20IN(1%2C%20-1)&returnGeometry=false&geometry=42.000%2C12.000&geometryType=esriGeometryPoint&inSR=4326&spatialRel=esriSpatialRelWithin&outFields=*&outStatistics=%5B%7B%22statisticType%22%3A%22sum%22%2C%22onStatisticField%22%3A%22AnzahlFall%22%2C%22outStatisticFieldName%22%3A%22value%22%7D%5D&resultType=standard&cacheHint=true`
const apiUrlCasesDays = (StartDate) => `https://services7.arcgis.com/mOBPykOjAyBO2ZKk/arcgis/rest/services/RKI_COVID19/FeatureServer/0/query?where=NeuerFall+IN%281%2C0%29+AND+${datumType}+%3E%3D+TIMESTAMP+%27${StartDate}%27&objectIds=&time=&resultType=standard&outFields=AnzahlFall%2C${datumType}&returnIdsOnly=false&returnUniqueIdsOnly=false&returnCountOnly=false&returnDistinctValues=false&cacheHint=false&orderByFields=&groupByFieldsForStatistics=${datumType}&outStatistics=%5B%7B%22statisticType%22%3A%22sum%22%2C%22onStatisticField%22%3A%22AnzahlFall%22%2C%22outStatisticFieldName%22%3A%22value%22%7D%5D%0D%0A&having=&resultOffset=&resultRecordCount=&sqlFormat=none&f=pjson&token=`
// distance between bottom label contents
const distanceBottomLabel = 8
// default is on (switch off by setting first parameter to '0')
let graphOn = true
let SMALL = false
let MEDIUM = false
/**
* Fix Coordinates/MediumWidget
* Set First Widgetparameter for showing graph (1) or showing statistics (0)
* Set Second and Thirt Widgetparameter for Coordinates
*
* Format: ShowGraph[,LATITUDE,LONGITUDE]
*
* Examples:
*
* Show Graph of local position: 1
* Show Graph of fix position: 1,51.1244,6.7353
* Show Statistics of local position: 0
* Show Statistics of fix position: 0,51.1244,6.7353
*
*/
const LIMIT_DARKRED = 100
const LIMIT_RED = 50
const LIMIT_ORANGE = 35
const LIMIT_YELLOW = 25
const LIMIT_DARKRED_COLOR = new Color('9e000a')
const LIMIT_RED_COLOR = new Color('f6000f')
const LIMIT_ORANGE_COLOR = new Color('#ff7927')
const LIMIT_YELLOW_COLOR = new Color('F5D800')
const LIMIT_GREEN_COLOR = new Color('1CC747')
const GET_DAYS = 35; // 5 Wochen
const WEEK_IN_DAYS = 7;
const EWZ_GER = 83020000;
const INCIDENCE_DAYS = 28 // 3 Wochen
const shortGER = 'D'
const BUNDESLAENDER_SHORT = {
'Baden-Württemberg': 'BW',
'Bayern': 'BY',
'Berlin': 'BE',
'Brandenburg': 'BB',
'Bremen': 'HB',
'Hamburg': 'HH',
'Hessen': 'HE',
'Mecklenburg-Vorpommern': 'MV',
'Niedersachsen': 'NI',
'Nordrhein-Westfalen': 'NRW',
'Rheinland-Pfalz': 'RP',
'Saarland': 'SL',
'Sachsen': 'SN',
'Sachsen-Anhalt': 'ST',
'Schleswig-Holstein': 'SH',
'Thüringen': 'TH'
};
let fixedCoordinates = []
let individualName = ''
if (args.widgetParameter) {
const parameters = args.widgetParameter.split(',');
if (parameters.length >= 1) {
if (parameters[0] == 1) {
graphOn = true
} else {
graphOn = false
}
}
if (parameters.length >= 3) {
fixedCoordinates = parseLocation(args.widgetParameter)
}
if (parameters.length == 4) {
individualName = parameters[3].slice()
}
} else {}
function parseLocation(input) {
const _coords = []
const _fixedCoordinates = input.split(";").map(coords => {
return coords.split(',')
})
_fixedCoordinates.forEach(coords => {
_coords[0] = {
latitude: parseFloat(coords[1]),
longitude: parseFloat(coords[2]),
}
})
return _coords
}
let data = {}
const widget = await createWidget()
if (!config.runsInWidget) {
await widget.presentSmall()
}
Script.setWidget(widget)
Script.complete()
async function createWidget() {
if (config.widgetFamily = 'small') {
SMALL = true
} else if (config.widgetFamily = 'medium') {
MEDIUM = true
}
const _data = await getData(0)
let areaName;
if (_data && typeof _data.areaName !== 'undefined') {
areaName = _data.areaName;
data[areaName] = _data
}
const list = new ListWidget()
const headerLabel = list.addStack()
headerLabel.useDefaultPadding()
headerLabel.centerAlignContent()
list.setPadding(10, 10, 10, 10)
headerLabel.layoutHorizontally()
if (data && typeof data[areaName] !== 'undefined') {
if (!data[areaName].shouldCache) {
list.addSpacer(6)
const loadingIndicator = list.addText("Ort wird ermittelt...".toUpperCase())
loadingIndicator.font = Font.mediumSystemFont(13)
loadingIndicator.textOpacity = 0.5
} else {
list.refreshAfterDate = new Date(Date.now() + 60 * 60 * 1000)
}
const header = headerLabel.addText("🦠 ")
header.font = Font.mediumSystemFont(12)
// AREA NAME
const areanameLabel = headerLabel.addText(data[areaName].areaName)
areanameLabel.font = Font.mediumSystemFont(12)
areanameLabel.lineLimit = 1
// INCIDENCE
createIncidenceLabelBlock(list, data[areaName])
} else {
list.addSpacer()
const errorLabel = list.addText("Daten nicht verfügbar. \nReload erfolgt... Bitte warten.")
errorLabel.font = Font.mediumSystemFont(12)
errorLabel.textColor = Color.gray()
list.refreshAfterDate = new Date(Date.now() + 1 * 15 * 1000) // Reload in 15 Sekunden
}
return list
}
function getFormatedDateBeforeDays(offset) {
let today = new Date()
let offsetDate = new Date()
offsetDate.setDate(today.getDate() - offset)
let offsetTime = offsetDate.toISOString().split('T')[0]
return (offsetTime)
}
function getCasesByDates(jsonData, StartDate, EndDate) {
let cases = 0
for (i = 0; i < jsonData.features.length; i++) {
let date = new Date(jsonData.features[i].attributes[datumType])
date = date.toISOString().split('T')[0]
if (StartDate <= date && date <= EndDate) {
cases = cases + parseInt(jsonData.features[i].attributes.value)
}
}
return cases
}
function getIncidenceLastWeek(jsonData, EWZ) {
let incidence = [];
let factor = EWZ / 100000;
for (let i = 0; i < INCIDENCE_DAYS; i++) {
startDate = (showIncidenceYesterday) ? getFormatedDateBeforeDays(INCIDENCE_DAYS + 7 - i) : getFormatedDateBeforeDays(INCIDENCE_DAYS + 6 - i)
endDate = (showIncidenceYesterday) ? getFormatedDateBeforeDays(INCIDENCE_DAYS - i) : getFormatedDateBeforeDays(INCIDENCE_DAYS - 1 - i)
incidence.push((getCasesByDates(jsonData, startDate, endDate) / factor).toFixed(1))
}
console.log(incidence)
return incidence
}
function getAreaName(attr) {
if (individualName == '') {
return (attr.GEN)
} else {
return (individualName)
}
}
function getValueFromJson(data) {
if (data.features[0].attributes.value != null) {
return (parseInt(data.features[0].attributes.value))
} else {
return 0;
}
}
async function getData(useFixedCoordsIndex = false) {
try {
let dataCases = await new Request(apiUrlNewCases).loadJSON()
const cases = getValueFromJson(dataCases)
let dataStates = await new Request(apiUrlStates).loadJSON()
const incidencePerState = dataStates.features.map((f) => {
return {
BL: BUNDESLAENDER_SHORT[f.attributes.LAN_ew_GEN],
incidence: f.attributes.cases7_bl_per_100k,
cases: f.attributes.Fallzahl // ???
}
})
const averageIncidence = incidencePerState.reduce((a, b) => a + b.incidence, 0) / incidencePerState.length
const location = await getLocation(useFixedCoordsIndex)
let data = await new Request(apiUrl(location)).loadJSON()
const attr = data.features[0].attributes
let bundeslandId = parseInt(attr.BL_ID);
let landkreisId = parseInt(attr.RS);
let lkdata = await new Request(apiUrlNewCasesLK(landkreisId)).loadJSON()
const areaNewCases = getValueFromJson(lkdata)
lkdata = await new Request(apiUrlCasesLKDays(landkreisId, getFormatedDateBeforeDays(GET_DAYS))).loadJSON()
const areaCasesLastWeek = getCasesByDates(lkdata, getFormatedDateBeforeDays(7), getFormatedDateBeforeDays(0))
const areaCasesLastWeekYesterday = getCasesByDates(lkdata, getFormatedDateBeforeDays(8), getFormatedDateBeforeDays(1))
const areaCasesWeekBeforeWeek = getCasesByDates(lkdata, getFormatedDateBeforeDays(13), getFormatedDateBeforeDays(6))
const areaIncidenceLastWeek = getIncidenceLastWeek(lkdata, parseInt(attr.EWZ))
let bldata = await new Request(apiUrlNewCasesBL(bundeslandId)).loadJSON()
const blNewCases = getValueFromJson(bldata)
bldata = await new Request(apiUrlCasesBLDays(bundeslandId, getFormatedDateBeforeDays(GET_DAYS))).loadJSON()
const blCasesLastWeek = getCasesByDates(bldata, getFormatedDateBeforeDays(7), getFormatedDateBeforeDays(0))
const blCasesLastWeekYesterday = getCasesByDates(bldata, getFormatedDateBeforeDays(8), getFormatedDateBeforeDays(1))
const blCasesWeekBeforeWeek = getCasesByDates(bldata, getFormatedDateBeforeDays(13), getFormatedDateBeforeDays(6))
const blIncidenceLastWeek = getIncidenceLastWeek(bldata, parseInt(attr.EWZ_BL))
data = await new Request(apiUrlCasesDays(getFormatedDateBeforeDays(GET_DAYS))).loadJSON()
const gerCasesLastWeek = getCasesByDates(data, getFormatedDateBeforeDays(7), getFormatedDateBeforeDays(0))
const gerCasesLastWeekYesterday = getCasesByDates(data, getFormatedDateBeforeDays(8), getFormatedDateBeforeDays(1))
const gerCasesWeekBeforeWeek = getCasesByDates(data, getFormatedDateBeforeDays(13), getFormatedDateBeforeDays(6))
const gerIncidenceLastWeek = getIncidenceLastWeek(data, EWZ_GER)
const res = {
landkreisId: landkreisId,
bundeslandId: bundeslandId,
incidence: parseFloat(attr.cases7_per_100k.toFixed(1)),
incidenceBL: parseFloat(attr.cases7_bl_per_100k.toFixed(1)),
areaName: getAreaName(attr),
areaCases: parseFloat(attr.cases.toFixed(1)),
areaNewCases: areaNewCases,
areaCasesLastWeek: areaCasesLastWeek,
areaCasesLastWeekYesterday: areaCasesLastWeekYesterday,
areaCasesWeekBeforeWeek: areaCasesWeekBeforeWeek,
areaIncidenceLastWeek: areaIncidenceLastWeek,
nameBL: BUNDESLAENDER_SHORT[attr.BL],
blNewCases: blNewCases,
blCasesLastWeek: blCasesLastWeek,
blCasesWeekBeforeWeek: blCasesWeekBeforeWeek,
blCasesLastWeekYesterday: blCasesLastWeekYesterday,
blIncidenceLastWeek: blIncidenceLastWeek,
shouldCache: true,
updated: attr.last_update,
incidencePerState: incidencePerState,
averageIncidence: parseFloat(averageIncidence.toFixed(1)),
cases: cases,
gerCasesLastWeek: gerCasesLastWeek,
gerCasesLastWeekYesterday: gerCasesLastWeekYesterday,
gerCasesWeekBeforeWeek: gerCasesWeekBeforeWeek,
gerIncidenceLastWeek: gerIncidenceLastWeek,
}
return res
} catch (e) {
console.log(e)
return null
}
}
async function getLocation(fixedCoordinateIndex = false) {
try {
if (fixedCoordinates && typeof fixedCoordinates[0] !== 'undefined') {
return fixedCoordinates[0]
} else {
Location.setAccuracyToThreeKilometers()
return await Location.current()
}
} catch (e) {
return null;
}
}
function createAvgLabel(label, data) {
let bgColor = new Color('f0f0f0')
let textColor = new Color('444444')
// if (Device.isUsingDarkAppearance()) {
// bgColor = new Color('202020')
// textColor = new Color('f0f0f0')
// }
let fontsize = 9
let formatedCasesArea = ''
let formatedCasesBL = ''
let formatedCases = ''
formatedCasesArea = formatCases((data.areaCasesLastWeek / 7).toFixed(1))
formatedCasesBL = formatCases((data.blCasesLastWeek / 7).toFixed(0))
formatedCases = formatCases((data.gerCasesLastWeek / 7).toFixed(0))
let casesStack = label.addStack()
casesStack.layoutHorizontally()
casesStack.centerAlignContent()
casesStack.setPadding(2, 2, 2, 2)
casesStack.cornerRadius = 6
casesStack.backgroundColor = bgColor
casesStack.size = new Size(130, 15)
let labelCases = casesStack.addText(`Ø ${formatedCasesArea}`)
labelCases.leftAlignText()
labelCases.font = Font.systemFont(fontsize)
labelCases.textColor = textColor
casesStack.addSpacer(distanceBottomLabel)
let labelCases2 = casesStack.addText(`Ø ${formatedCasesBL}`)
labelCases2.centerAlignText()
labelCases2.font = Font.systemFont(fontsize)
labelCases2.textColor = textColor
// GER CASES
casesStack.addSpacer(distanceBottomLabel)
let labelCases3 = casesStack.addText(`Ø ${formatedCases}`)
labelCases3.rightAlignText()
labelCases3.font = Font.systemFont(fontsize)
labelCases3.textColor = textColor
}
function createGerDailyCasesLabel(label, data) {
let bgColor = new Color('f0f0f0')
let textColor = new Color('444444')
// if (Device.isUsingDarkAppearance()) {
// bgColor = new Color('202020')
// textColor = new Color('f0f0f0')
// }
let fontsize = 9
let formatedCasesArea = ''
let formatedCasesBL = ''
let formatedCases = formatCases(data.cases)
formatedCases += getTrendArrow(data.gerCasesWeekBeforeWeek, data.gerCasesLastWeekYesterday)
formatedCasesArea = getNewAreaCasesAndTrend(data)
formatedCasesBL = getNewBLCasesAndTrend(data)
let casesStack = label.addStack()
casesStack.layoutHorizontally()
casesStack.centerAlignContent()
casesStack.setPadding(2, 2, 2, 2)
casesStack.cornerRadius = 6
casesStack.backgroundColor = bgColor
casesStack.size = new Size(130, 15)
let labelCases = casesStack.addText(`${formatedCasesArea}`)
labelCases.leftAlignText()
labelCases.font = Font.systemFont(fontsize)
labelCases.textColor = textColor
casesStack.addSpacer(distanceBottomLabel)
let labelCases2 = casesStack.addText(`${formatedCasesBL}`)
labelCases2.centerAlignText()
labelCases2.font = Font.systemFont(fontsize)
labelCases2.textColor = textColor
// GER CASES
casesStack.addSpacer(distanceBottomLabel)
let labelCases3 = casesStack.addText(`+${formatedCases}`)
labelCases3.rightAlignText()
labelCases3.font = Font.systemFont(fontsize)
labelCases3.textColor = textColor
}
function formatCases(cases) {
return formatedCases = new Number(cases).toLocaleString('de-DE')
}
function getTrendArrow(preValue, currentValue) {
let arrow = ''
if (parseFloat(currentValue) < parseFloat(preValue)) {
arrow = '↓'
} else if (parseFloat(currentValue) > parseFloat(preValue)) {
arrow = '↑'
} else {
arrow = '→'
}
return (arrow)
}
function createUpdatedLabel(label, data) {
const updateLabel = label.addText(`${data.updated.substr(0, 10)} `)
updateLabel.font = Font.systemFont(8)
updateLabel.textColor = Color.gray()
updateLabel.leftAlignText()
}
function createIncidenceLabelBlock(labelBlock, data) {
let bgColor = new Color('f0f0f0')
let textColor = new Color('444444')
const mainRowWidth = 130
const mainRowHeight = 40
const fontSizeLocal = 27
const stack = labelBlock.addStack()
stack.layoutVertically()
stack.useDefaultPadding()
stack.topAlignContent()
stack.addSpacer(4)
// MAIN ROW WITH INCIDENCE
const stackMainRow = stack.addStack()
stackMainRow.layoutHorizontally()
stackMainRow.centerAlignContent()
stackMainRow.size = new Size(mainRowWidth, mainRowHeight)
// MAIN INCIDENCE
let areaIncidence = (showIncidenceYesterday) ? data.areaIncidenceLastWeek[data.areaIncidenceLastWeek.length - 1] : data.incidence
let incidence = areaIncidence >= 100 ? Math.round(areaIncidence) : parseFloat(areaIncidence).toFixed(1);
const incidenceLabel = stackMainRow.addText(incidence.toString().replace('.', ','))
incidenceLabel.font = Font.boldSystemFont(fontSizeLocal)
incidenceLabel.leftAlignText();
incidenceLabel.textColor = getIncidenceColor(incidence)
let length = data.areaIncidenceLastWeek.length
const incidenceTrend = getTrendArrow(data.areaIncidenceLastWeek[length - WEEK_IN_DAYS], data.areaIncidenceLastWeek[length - (trendDaysOffset + 1)])
const incidenceLabelTrend = stackMainRow.addText('' + incidenceTrend)
incidenceLabelTrend.font = Font.mediumSystemFont(fontSizeLocal - 4)
incidenceLabelTrend.rightAlignText();
incidenceLabelTrend.textColor = (incidenceTrend === '↑') ? LIMIT_RED_COLOR : LIMIT_GREEN_COLOR
stack.addSpacer(4)
const stackMainRight = stack.addStack()
stackMainRight.useDefaultPadding()
//stackMainRight.size = new Size(130, 15)
stackMainRight.layoutHorizontally()
// BL INCIDENCE
const stackTop = stackMainRight.addStack()
stackTop.backgroundColor = bgColor
stackTop.cornerRadius = 6
stackTop.setPadding(2, 3, 2, 3)
stackTop.size = new Size(63, 14)
stackTop.centerAlignContent()
let blIncidence = (showIncidenceYesterday) ? data.blIncidenceLastWeek[data.blIncidenceLastWeek.length - 1] : data.incidenceBL
let incidenceBL = Math.round(blIncidence)
length = data.blIncidenceLastWeek.length
const incidenceBLLabel = stackTop.addText(data.nameBL + ': ' + formatCases(incidenceBL) + getTrendArrow(data.blIncidenceLastWeek[length - WEEK_IN_DAYS], data.blIncidenceLastWeek[length - (trendDaysOffset + 1)]))
incidenceBLLabel.font = Font.mediumSystemFont(10)
incidenceBLLabel.textColor = textColor //getIncidenceColor(blIncidence)
incidenceBLLabel.lineLimit = 1
// GER INCIDENCE
stackMainRight.addSpacer(3)
const stackBottom = stackMainRight.addStack()
stackBottom.backgroundColor = bgColor
stackBottom.cornerRadius = 6
stackBottom.setPadding(2, 3, 2, 3)
stackBottom.size = new Size(63, 14)
stackBottom.centerAlignContent()
let gerIncidence = data.gerIncidenceLastWeek[data.gerIncidenceLastWeek.length - 1]
let incidenceD = Math.round(gerIncidence)
length = data.gerIncidenceLastWeek.length
const incidenceDLabel = stackBottom.addText(shortGER + ': ' + formatCases(incidenceD) + getTrendArrow(data.gerIncidenceLastWeek[length - WEEK_IN_DAYS], data.gerIncidenceLastWeek[length - (trendDaysOffset + 1)]))
incidenceDLabel.font = Font.mediumSystemFont(10)
incidenceDLabel.textColor = textColor //getIncidenceColor(gerIncidence)
incidenceDLabel.lineLimit = 1
// GRAPH OR STATISTIC
stack.addSpacer(2)
if (graphOn) {
stack.addSpacer(2)
createGraph(stack, data)
} else {
createAvgLabel(stack, data)
stack.addSpacer(2)
createGerDailyCasesLabel(stack, data)
}
stack.addSpacer(3)
// DATE
const stackDate = stack.addStack()
stackDate.layoutHorizontally()
createUpdatedLabel(stackDate, data)
}
function createGraph(row, data) {
let graphHeight = 30
let graphWidth = 130
let graphRow = row.addStack()
graphRow.centerAlignContent()
graphRow.useDefaultPadding()
graphRow.size = new Size(graphWidth, graphHeight)
let incidenceColumnData = []
for (i = 0; i < data.areaIncidenceLastWeek.length; i++) {
incidenceColumnData.push(data.areaIncidenceLastWeek[i])
}
let image = columnGraph(incidenceColumnData, graphWidth, graphHeight).getImage()
let img = graphRow.addImage(image)
img.resizable = false;
img.centerAlignImage();
}
function columnGraph(data, width, height) {
let context = new DrawContext()
context.size = new Size(width, height)
context.opaque = false
let max = Math.max(...data)
data.forEach((value, index) => {
context.setFillColor(getIncidenceColor(value))
let w = (width / data.length) - 2
let h = value / max * height
let x = (w + 2) * index
let y = height - h
let rect = new Rect(x, y, w, h)
context.fillRect(rect)
})
return context
}
function getIncidenceColor(incidence) {
let color = LIMIT_GREEN_COLOR
if (incidence >= LIMIT_DARKRED) {
color = LIMIT_DARKRED_COLOR
} else if (incidence >= LIMIT_RED) {
color = LIMIT_RED_COLOR
} else if (incidence >= LIMIT_ORANGE) {
color = LIMIT_ORANGE_COLOR
} else if (incidence >= LIMIT_YELLOW) {
color = LIMIT_YELLOW_COLOR
}
return color
}
function getNewAreaCasesAndTrend(data) {
return ("+" + formatCases(data.areaNewCases) + getTrendArrow(data.areaCasesWeekBeforeWeek, data.areaCasesLastWeekYesterday))
}
function getNewBLCasesAndTrend(data) {
return ("+" + formatCases(data.blNewCases) + getTrendArrow(data.blCasesWeekBeforeWeek, data.blCasesLastWeekYesterday))
}
@sig0815
Copy link

sig0815 commented Oct 31, 2020

Hallo!

Herzlichen Dank für die prima Leistung.
Leider gelingt es mir nicht richtige, feste Koordinaten einzugeben (Landkreis Barnim) in diesem Fall.
Wer kann mir das weiterhelfen? Zeile 111 ist doch richtig oder?
Danke.

Siglinde

@tzschies
Copy link
Author

Hallo!

Herzlichen Dank für die prima Leistung.
Leider gelingt es mir nicht richtige, feste Koordinaten einzugeben (Landkreis Barnim) in diesem Fall.
Wer kann mir das weiterhelfen? Zeile 111 ist doch richtig oder?
Danke.

Siglinde

Am besten als Parameter eingeben:
IMG_9366

@tzschies
Copy link
Author

hinter "NRW" passen keine 3-stelligen Zahlen mehr.
Wenn man (in Zeile 102) "NR" draus macht, passt es.
"NW" ist auch zu groß ...

NRW sollte mit dem neuesten Update wieder hinein passen :-)

@tzschies
Copy link
Author

Das neueste Update gibt es hier ... oder in Zukunft auch dort: https://github.com/tzschies/incidence

IMG_9370

@tzschies
Copy link
Author

tzschies commented Oct 31, 2020

...könnte man dieses Widget auf die Daten von ganz D bauen...umbauen....anstatt Stadt /Lk...????

Schau mal dort: https://github.com/tzschies/incidence/tree/graphOnly
Als Parameter 2 eingeben und du hast es für Gesamtdeutschland

@Auxler
Copy link

Auxler commented Nov 1, 2020

Das neueste Update gibt es hier ... oder in Zukunft auch dort: https://github.com/tzschies/incidence

IMG_9370

Landkreise mit einem Doppelnamen werden abgeschnitten, dank deiner eigen Namenfunktion fixbar

@App-Fan-Apple
Copy link

danke für danke für die Info, tolle Arbeit!!
einen Vorschlag hätte ich noch, ich wohne im Landkreis Regensburg, ich würde aber gerne beide Werte sehen, Landkreis und Stadt Regensburg, wenn ich beide Widgets darstelle, steht aber immer nur Regensburg:
IMG_8533

Toll wäre es, wenn das Label mit einem eigenen Text überschrieben werden könne, dann könne man z.b. "LK Regensburg" schreiben oder auch "Arbeit" oder "zu Hause"
Vorschlag zur Umsetzung: 0,49.01,12.37,LK Regensburg

Wo finde ich den Code?

@Gandalf8266
Copy link

Ganz oben 🔝

@App-Fan-Apple
Copy link

Ich habe es hinbekommen 💪🏼Wie werden die durchschnittlichen Zahlen berechnet?

@Gandalf8266
Copy link

Die kommen vom RKI

@MaHeinze
Copy link

MaHeinze commented Nov 4, 2020

Update vom 29.10.2020
Das Diagramm zeigt jetzt den Verlauf der Inzidenz des Landkreises/der Stadt der letzten 3 Wochen. Dadurch bekommt man ein besseren Eindruck des Trends.
Als vierter Parameter kann nun ein eigen gewählter Name des Landkreises/der Stadt gesetzt werden.
Also z.B.: "0,49.01,12.37,LK Regensburg" zeigt nun LK Regensburg an, statt nur Regensburg, wie von der API geliefert.

Ansonsten gibt es kleinere Design-Anpassungen, z.B. wird die Inzidenz des Bundeslands und Deutschlands nun wieder nebeneinander und etwas größer angezeigt.

IMG_9370

Vielen Dank für das tolle Widget!

Was muss man anpassen, damit es auch in einem mittleren oder großem Widget funktioniert? Im großen Widget wird nur in der Mitte ein kleines Widget angezeigt.

@Sternschnuppe362
Copy link

Neues Update:
Designanpassungen, Trendermittlung optimiert, außerdem weitere Optionen und Funktionen hinzugefügt.

Durch Übergabe des ersten Parameters kann umgeschaltet werden zwischen Kurvenanzeige und Statistik-Anzeige:

Format der Parameterübergabe
ShowGraph[,LATITUDE,LONGITUDE]

Beispiele Parameterübergabe:

  • Grafik-Anzeige aktuelle Position: 1
  • Grafik-Anzeige fixer Koordinaten: 1,51.1244,6.7353
  • Statistik-Anzeige aktuelle Position: 0
  • Statistik-Anzeige fixer Koordinaten: 0,51.1244,6.7353

Die Ansichten sehen wie folgt aus:
BildschirmfotoInzidenzHeute

Es gibt im Skript die Möglichkeit, statt der Inzidenz von Heute, die berechnete Inzidenz von Gestern anzuzeigen. Da viele Fälle meist ein Tag später beim RKI gemeldet werden, ist die heutige Inzidenz niedriger als tatsächlich.
Beispiel aus unserem LK: Am Montag wurden 5 neue Fälle vom Gesundheitsamt gemeldet. Das RKI hat am Dienstag 3 neue Fälle registriert, und heute nochmals für Montag 2 Fälle nachregistriert. D.h. die Berechnung der Inzidenz von Gestern berechnet die korrekte (gestrige) Inzidenz. Die Zahl vom RKI gestern dagegen kannte die nachgemeldeten Zahlen nicht, und war demnach niedriger.

Diese Option kann im Skript mithilfe der Variablen 'showIncidenceYesterday' (Zeile 31) de- bzw. aktiviert werden. Standardmäßig wird die Inzidenz von gestern angezeigt (='true'). Soll der Wert von Heute angezeigt werden, muss der Wert auf 'false' gesetzt werden

Mit aktivierter Option, sieht man auch, dass die Kurven (leider) weiter ansteigen:
BildschirmfotoInzidenzGestern

Außerdem gibt es eine weiteres Skript (s. https://gist.github.com/tzschies/be551cc6939e7c1469c2e8407edab517), das die aktiven Fälle, Gesamtinfizierten, Genesenen und Verstorbenen anzeigt:
BildschirmfotoCases

Ich verstehe leider nicht, wie und wo ich bestimmte Orte hinterlegen kann um mir mehrere Widgets anzulegen (Arbeitsort, Wohnort, etc.) geht das, oder geht das nur für einzelne Landkreise? Wäre super wenn mir hier jemand helfen könnte. Dankeschön!

@Typ1er
Copy link

Typ1er commented Nov 7, 2020

wenn du das widget, am Homescreen hinzugefügt hast, kannst du es bearbeiten, wenn du etwas länger drauf drückst und dort bei Parameter kann man die Daten eingeben
IMG_2430

IMG_2429

@Sternschnuppe362
Copy link

wenn du das widget, am Homescreen hinzugefügt hast, kannst du es bearbeiten, wenn du etwas länger drauf drückst und dort bei Parameter kann man die Daten eingeben
IMG_2430

IMG_2429

Das hab ich versucht. Das funktioniert aber irgendwie nicht... wollte zB die Zahlen für Offenbach sehen. Sobald ich die Daten eingebe verschwinden die Balken und es werden „nur“ noch die Zahlen angezeigt, aber auch nicht für Offenbach sondern den Main-Kinzig-Kreis

Sorry, blicke da noch nicht so ganz durch. 🙈
88165A46-DE61-4D72-B879-59EBACFEBB87
3B59B0D3-94E9-4BD4-989C-566787AE04D5

@Typ1er
Copy link

Typ1er commented Nov 7, 2020

Fehlt die 0 oder 1 davor, wird die GPS Position genommen.

mit Grafik muss eine 1 davor:
1, 50.1055002, 8.7610698
IMG_2434

mit Statistik:
0, 50.1055002, 8.7610698

@Sternschnuppe362
Copy link

Fehlt die 0 oder 1 davor, wird die GPS Position genommen.

mit Grafik muss eine 1 davor:
1, 50.1055002, 8.7610698
IMG_2434

mit Statistik:
0, 50.1055002, 8.7610698

👍🏼👍🏼👍🏼👍🏼 Super!!! Jetzt klappt es!! Vielen, vielen Dank!!

@despecial
Copy link

Bei deinem Script erhalte ich jeweils einen Pfeil nach unten bei Hamburg und Deutschland, obwohl gestern der Inzidenzwert niedriger war. Da muss was falsch sein.

https://github.com/rphl/corona-widget zeigt es korrekt an.

@tzschies
Copy link
Author

Der Trendpfeil wird wochenweise verglichen, was auch m.M.n. mehr Sinn macht, da der Trendpfeil ja sonst keine Aussagekraft hat (aufgrund von Wochenende und Nachmeldungen etc.).
Da gibt es für das Widget overviewCases auch nochmal detailliertere Beschreibung, wie sich der Trendpfeil berechnet:
https://github.com/tzschies/incidence

Inzidenz mit Trend Pfeil Der Trendpfeil bestimmt sich durch den geschätzten (!) R-Faktor. Dieser wird direkt darunter angezeigt. Ist der R-Faktor zwischen 0,95 und 1,05 bleibt die Inzidenz in etwa konstant (→), ist der R-Faktor zwischen 1,05 und 1,1 steigt die Inzidenz leicht (), über 1,1 steigt sie stark (↑). Ist der R-Fakor zwischen 0,9 und 0,95 sinkt die Inzidenz leicht (), unter 0,9 sinkt sie stark (↓).

Der einzige Unterschied zum incidence-Widget ist, dass es die schrägen Pfeile noch nicht gibt. Die prinzipielle Bestimmung bleibt aber gleich.

@despecial
Copy link

despecial commented Nov 13, 2020

Moin tzschies. Okay, das war nicht klar, dass das über eine Woche geht. Andere Frage: Du hast eine Repo, aber updatest das gist hier und die Repo nicht?

edit: nee, da stimmt definitiv etwas nicht. Stelle ich showGraph aus, zeigt mit die Statistik ebenfalls Pfeile nach unten, zB bei den Neuinfizierten und heute haben wir einen Rekordwert. Das muss nach oben zeigen.

@tzschies
Copy link
Author

tzschies commented Nov 13, 2020

Bildschirmfoto 2020-11-13 um 11 31 42
Sieht man gut an den Fallzahlen deines Beispiels von Hamburg: Letzte Woche war deutlich höher als momentan. Es scheint also abzunehmen (wochenweise betrachtet).

Moin tzschies. Okay, das war nicht klar, dass das über eine Woche geht. Andere Frage: Du hast eine Repo, aber updatest das gist hier und die Repo nicht?

Nein anders rum, zukünftige Updates gibts in der Repo, hier nicht mehr. Werde das nochmal als Hinweis in den ersten Post mit aufnehmen, danke.

@despecial
Copy link

Hast du meinen Edit noch gesehen? Die Fallzahlen beziehen sich auf die bundesweite Neuinfektionen.
Das hat ja nichts mit einem 7-Tage Wert zu tun.

@dennerforen
Copy link

Wenn man die Zahlen aus dem schwarzen Graph mit dem trendpfeil aus der Übersicht vergleicht, passt die Aussage ➡️ Doch ganz gut

IMG_5187

@tzschies
Copy link
Author

tzschies commented Nov 13, 2020

Das Problem ist wie die Fallzahlen gedeutet werden. Die Medien berichten von dem heutigen Tag. Das RKI schlüsselt aber nochmals auf, wann die neuen Fälle tatsächlich berichtet wurden (Das sieht man in der Grafiken z.B. an den orangenen Balken).

Der von den Medien als "Rekordwert" gemeldeten Fälle gilt aber nicht für den gestrigen Tag. Die 23542 Fälle teilen sich auf in 13533 Fälle von gestern, 8070 von vorgestern und 1448 von vorvorgestern auf (und nochmal ein paar wenige für Tage davor). Ich vergleiche die Daten nach Meldedatum (bzw. gibt es in dem Skript sogar die Möglichkeit auf Erkrankungsdatum umzustellen), und nicht die Daten, wann sie letztendlich nachgemeldet wurden.

Der Graph für Deutschland zeigt es ganz gut zum verdeutlichen:
Bildschirmfoto 2020-11-13 um 12 34 20
Am 5.11. dem RKI gemeldete Fälle (mit Meldedatum der Gesundheitsämter) etwas über 22000. Vorgestern (mit gestern zu vergleichen macht kein Sinn, da da noch ein Haufen Nachmeldungen nachgetragen werden) rund 20800. Mit Vorsicht kann man also sagen, dass es scheint leicht abzunehmen. (Ich habe jetzt mal außer Acht gelassen, das bei der Trendbestimmung in der aktuellen Version zusätzlich die Durchschnittswerte der letzten 7 Tage dafür verwendet werden --> Durchschnitt letzte 7 Tage verglichen mit dem Durchschnitt der letzten 7 Tage vor einer Woche).

Der von mir geschätzte R ist auch leicht unter 1. Deshalb zeigt der Pfeil in der incident-Widget Version auch nach unten. Im overviewCases-Widget zeigt die Tendenz nach rechts. Ich finde so bekommt man einen deutlich besseren Eindruck vom aktuellen Geschehen, als ständig von "Rekordmeldungen" zu sprechen.
IMG_9431

@dennerforen
Copy link

Gute Erklärung, passt für mich.

@tzschies
Copy link
Author

Für mich auch ;-) Deswegen hab ich es auch so umgesetzt.

@despecial Was ich aber bei Gelegenheit noch umsetzen werde ist, die zusätzlichen Richtungen auch im incidence-Widget hinzuzufügen (also die schrägen Pfeile, sowie den Pfeil nach rechts).

@despecial
Copy link

@tzeschies wirklich gut erklärt. Das geht aus dem kleinen Widget, den Medien und der Erfahrung durch andere Widgets überhaupt nicht so ein. Deswegen gut, dass du die Herleitung der Zahlen so erklärt hast. Das mit den schrägen/gleichbleibende Pfeilen finde ich gut. Vielleicht kann man auch optisch erwähnen, dass es sich um eine 7 Tage Tendenz handelt und keine tägliche.

@dennerforen
"Wenn man die Zahlen aus dem schwarzen Graph mit dem trendpfeil aus der Übersicht vergleicht, passt die Aussage ➡️ Doch ganz gut". Also der Trend zeigt doch eindeutig nach oben. Eine gleichbleibende Tendenz seit dem 8. November (mit kurzem Ausriss am 10.)

@dennerforen
Copy link

@despecial

Wenn ich mir den Chart vom 5-12 anschaue und den Chart vom 29.10 bis 4.11 sieht das ziemlich gleich aus.

@BoingPlatsch
Copy link

Hallo @tzschies,
eine für dich vermutlich einfache Frage: Welche Zeilen brauche ich alles, um den Inzidenz-Wert von ganz Deutschland im ursprünglichen Widget von @kevinkub einzufügen?
Meine Coding-Skills sind leider nur mehr als rudimentär... 💩

Vielen Dank für deine/eure tolle Arbeit!

Grüße
Florian alias BoingPlatsch

@korbinio
Copy link

korbinio commented Dec 6, 2020

Das Widget ist immer noch das meiner Meinung nach mit Abstand beste! Vielen Dank dafür!
Eine kleine Anregung hätte ich: Da die Werte doch sehr stark mit dem Wochentag korrelieren (z.B. Montag immer sehr kleiner Wert), fände ich es spannend den aktuellen Wert mit dem Wert von vor 7 Tagen zu vergleichen. Was müsste ich denn in dem Script ändern um das zu ermöglichen?

@Martin511
Copy link

Hallo,
eine technische Frage: Die Werte aktualisieren sich für mich nicht so, wie ich es erwarten würde.
Meist erst wenn ich auf das Widget tippe und in Scriptable das Script ausführe.
Kann man das Script so einstellen, dass es z.B. 3x täglich automatisch die Daten aktualisiert?
Viele Grüße

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment