// 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)) | |
} |
This comment has been minimized.
This comment has been minimized.
.....sieht TOP aus...Kompliment....könnte man noch die Zahlen der aktuell Erkrankten/Infizierten im Landkreis/Stadt/Gesamt hinzufügen...??? |
This comment has been minimized.
This comment has been minimized.
Ist möglich, und hatte ich auch noch vor. Wollte auch noch ein seperates Statistik-Widget bauen mit Übersicht von Infizierten, Genesene und Verstorbenen. |
This comment has been minimized.
This comment has been minimized.
Sehr sauberer Code und du nutzt exakt den Ansatz, den ich heute auch in meinem Widget einsetzen wollte 👍🏻. Vielleicht muss ich nochmal umdenken. |
This comment has been minimized.
This comment has been minimized.
...bei den Durchschnittszahlen hast du keine Tausendertrennzeichen drin....? Absicht...? ...wegen Unterschied Komma...? |
This comment has been minimized.
This comment has been minimized.
Nein, nur vergessen zu formatieren. Danke :-) |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
Neues Update: Durch Übergabe des ersten Parameters kann umgeschaltet werden zwischen Kurvenanzeige und Statistik-Anzeige: Format der Parameterübergabe Beispiele Parameterübergabe:
Die Ansichten sehen wie folgt aus: 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. 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: Außerdem gibt es eine weiteres Skript (s. https://gist.github.com/tzschies/be551cc6939e7c1469c2e8407edab517), das die aktiven Fälle, Gesamtinfizierten, Genesenen und Verstorbenen anzeigt: |
This comment has been minimized.
This comment has been minimized.
Fallübersicht wurde verschoben in neues Depot |
This comment has been minimized.
This comment has been minimized.
Thx für die Fallübersicht. Finde ich geil, wie ich so tolle Arbeit anderer nutzen kann! Danke allen Erfindern und Forkern (sagt man das so?) |
This comment has been minimized.
This comment has been minimized.
Cooles Widget, die Parameter Übergabe um die Statistik zu sehen klappt bei mir nicht also nur die „0“ Mit Position klappt es. |
This comment has been minimized.
This comment has been minimized.
Danke nochmal für den richtig coolen Fork. Das hier ist echt das „Inziden-Widget on Steroids“. Ich habe mein eigenes Widget gerade auch aktualisiert und diesen Fork in dem Zuge hervorgehoben. Viele Grüße |
This comment has been minimized.
This comment has been minimized.
Aktualisiert. Jetzt müsste es gehen. |
This comment has been minimized.
This comment has been minimized.
Erst mal vielen Dank für die super Arbeit. Wenn ich keinen Parameter eintrage, erscheinen die Daten und der Graph. Wenn ich eine 1 eintrage (lt. Anleitung aktuelle Position mit Graph ) kommt Fehler in Zeile 108. ich wollte eigentlich die Statistik sprich Parameter 0. hier kommt jedoch „Daten nicht verfügbar“ , was eigentlich nicht sein kann, da er ja ohne Parameter einen Graph anzeigt |
This comment has been minimized.
This comment has been minimized.
Danke :-) |
This comment has been minimized.
This comment has been minimized.
Hallo, die Daten weichen aber von der RKI Seite ab, welche Datenquelle verwendest du? Gibt es eine Erläuterung was diese 6 Werte bedeuten, ich finde gerade keine Erläuterung dazu. |
This comment has been minimized.
This comment has been minimized.
Perfekt. Vielen Dank!! |
This comment has been minimized.
This comment has been minimized.
Die angezeigte Inzidenz ist kurz gesagt die berechnete Inzidenz vom Vortag unter Berücksichtigung der Nachmeldungen. Wenn du die aktuelle Inzidenz möchtest (also die vom Server aktuell ausgegeben wird), dann müsstest Du Zeile 31 auf "false" setzen, oder das aktuelles Skript laden (ich habe es nun standardmäßig deaktiviert). Ist vielleicht auf den ersten Blick verwirrend. Werde diese Option vielleicht in Zukunft als Parameter einführen. Du meinst die 6 Werte in den letzten zwei Zeilen? |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
@Gandalf8266 Ein eigener Name kann nun hinzugefügt werden :-) |
This comment has been minimized.
This comment has been minimized.
Vielen dank, tolle Arbeit 👍🏼👍🏼 |
This comment has been minimized.
This comment has been minimized.
Wäre es möglich die beiden fixen GeoPositionen in den Configurationteil zu packen? Bekomme leider auch das Mediumwidget nicht zum laufen |
This comment has been minimized.
This comment has been minimized.
hinter "NRW" passen keine 3-stelligen Zahlen mehr. |
This comment has been minimized.
This comment has been minimized.
Ich bin gerade am Umbauen des Mediumwidgets. Im Moment zeigt es dasselbe an wie das Smallwidget. Das mit den beiden Fixpositionen aus dem Ursprungs-Widget funktioniert hier nicht mehr.
Im nächsten Update wird die Inzidenz des Bundeslands wieder zwei-zeilig. Dann sollte es wieder funktionieren. |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
Hallo! Herzlichen Dank für die prima Leistung. Siglinde |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
NRW sollte mit dem neuesten Update wieder hinein passen :-) |
This comment has been minimized.
This comment has been minimized.
Das neueste Update gibt es hier ... oder in Zukunft auch dort: https://github.com/tzschies/incidence |
This comment has been minimized.
This comment has been minimized.
Schau mal dort: https://github.com/tzschies/incidence/tree/graphOnly |
This comment has been minimized.
This comment has been minimized.
Landkreise mit einem Doppelnamen werden abgeschnitten, dank deiner eigen Namenfunktion fixbar |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
Ganz oben |
This comment has been minimized.
This comment has been minimized.
Ich habe es hinbekommen 💪🏼Wie werden die durchschnittlichen Zahlen berechnet? |
This comment has been minimized.
This comment has been minimized.
Die kommen vom RKI |
This comment has been minimized.
This comment has been minimized.
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. |
This comment has been minimized.
This comment has been minimized.
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! |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
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. |
This comment has been minimized.
This comment has been minimized.
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.).
Der einzige Unterschied zum incidence-Widget ist, dass es die schrägen Pfeile noch nicht gibt. Die prinzipielle Bestimmung bleibt aber gleich. |
This comment has been minimized.
This comment has been minimized.
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. |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
Hast du meinen Edit noch gesehen? Die Fallzahlen beziehen sich auf die bundesweite Neuinfektionen. |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
Gute Erklärung, passt für mich. |
This comment has been minimized.
This comment has been minimized.
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). |
This comment has been minimized.
This comment has been minimized.
@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 |
This comment has been minimized.
This comment has been minimized.
Wenn ich mir den Chart vom 5-12 anschaue und den Chart vom 29.10 bis 4.11 sieht das ziemlich gleich aus. |
This comment has been minimized.
This comment has been minimized.
Hallo @tzschies, Vielen Dank für deine/eure tolle Arbeit! Grüße |
This comment has been minimized.
This comment has been minimized.
Das Widget ist immer noch das meiner Meinung nach mit Abstand beste! Vielen Dank dafür! |
This comment has been minimized.
UPDATE
Zukünftige Versionen werden im Repo zu finden sein:
https://github.com/tzschies/incidence
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.
Format der Parameterübergabe
ShowGraph[,LATITUDE,LONGITUDE,NAME]
Beispiele Parameterübergabe:
Fallübersicht kann hier bezogen werden: https://gist.github.com/tzschies/be551cc6939e7c1469c2e8407edab517
