Skip to content

Instantly share code, notes, and snippets.

@aploe
Forked from kevinkub/incidence.js
Last active November 16, 2020 08:15
Show Gist options
  • Select an option

  • Save aploe/6644b61953c3f42e7369c2de21e1b87d to your computer and use it in GitHub Desktop.

Select an option

Save aploe/6644b61953c3f42e7369c2de21e1b87d to your computer and use it in GitHub Desktop.

Revisions

  1. aploe revised this gist Nov 16, 2020. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion incidence.js
    Original file line number Diff line number Diff line change
    @@ -118,7 +118,7 @@ class IncidenceWidget {
    newinfValueStack.addSpacer(5)

    // Chart
    let chart = new LineChart(400, 98, data.timeline).configure((ctx, path) => {
    let chart = new LineChart(400, 100, data.timeline).configure((ctx, path) => {
    ctx.opaque = false;
    ctx.setFillColor(new Color("888888", .25));
    ctx.addPath(path);
  2. aploe revised this gist Nov 13, 2020. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion incidence.js
    Original file line number Diff line number Diff line change
    @@ -92,7 +92,6 @@ class IncidenceWidget {
    let stateText2 = stateStackInner.addText(data.areaNameBySide)
    stateText2.font = Font.mediumSystemFont(9)
    stateText2.textColor = Color.white()
    // valueStack.addSpacer(5)

    // Label Area
    let incidenceValueArea = incidenceStack.addText(data.areaName)
    @@ -105,6 +104,7 @@ class IncidenceWidget {
    header.font = Font.mediumSystemFont(12)
    textStack.addSpacer(1)

    // New infections stack
    let newinfStack = textStack.addStack()
    newinfStack.bottomAlignContent()
    newinfStack.addSpacer(5)
  3. aploe revised this gist Nov 13, 2020. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion incidence.js
    Original file line number Diff line number Diff line change
    @@ -1,6 +1,6 @@
    // Licence: Robert Koch-Institut (RKI), dl-de/by-2-0
    // Thanks to @rphl (https://github.com/rphl) and @tzschies (https://github.com/tzschies) for their inspiring work on this widget. See https://gist.github.com/rphl/0491c5f9cb345bf831248732374c4ef5 and https://gist.github.com/tzschies/563fab70b37609bc8f2f630d566bcbc9.
    // Thank
    // aploe: Thanks to Kevin Kub (https://gist.github.com/kevinkub)

    class IncidenceWidget {

  4. aploe revised this gist Nov 13, 2020. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion incidence.js
    Original file line number Diff line number Diff line change
    @@ -1,6 +1,6 @@
    // Licence: Robert Koch-Institut (RKI), dl-de/by-2-0

    // Thanks to @rphl (https://github.com/rphl) and @tzschies (https://github.com/tzschies) for their inspiring work on this widget. See https://gist.github.com/rphl/0491c5f9cb345bf831248732374c4ef5 and https://gist.github.com/tzschies/563fab70b37609bc8f2f630d566bcbc9.
    // Thank

    class IncidenceWidget {

  5. aploe revised this gist Nov 13, 2020. 1 changed file with 57 additions and 16 deletions.
    73 changes: 57 additions & 16 deletions incidence.js
    Original file line number Diff line number Diff line change
    @@ -5,6 +5,8 @@
    class IncidenceWidget {

    constructor() {
    this.newCasesApiUrl = `https://services7.arcgis.com/mOBPykOjAyBO2ZKk/arcgis/rest/services/RKI_COVID19/FeatureServer/0/query?f=json&where=NeuerFall%20IN(1%2C%20-1)&returnGeometry=false&spatialRel=esriSpatialRelIntersects&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`;

    this.previousDaysToShow = 31;
    this.apiUrlDistricts = (location) => `https://services7.arcgis.com/mOBPykOjAyBO2ZKk/arcgis/rest/services/RKI_Landkreisdaten/FeatureServer/0/query?where=1%3D1&outFields=RS,GEN,cases7_bl_per_100k,cases7_per_100k,BL&geometry=${location.longitude.toFixed(3)}%2C${location.latitude.toFixed(3)}&geometryType=esriGeometryPoint&inSR=4326&spatialRel=esriSpatialRelWithin&returnGeometry=false&outSR=4326&f=json`
    this.apiUrlDistrictsHistory = (districtId) => `https://services7.arcgis.com/mOBPykOjAyBO2ZKk/arcgis/rest/services/RKI_COVID19/FeatureServer/0/query?where=IdLandkreis%20%3D%20%27${districtId}%27%20AND%20Meldedatum%20%3E%3D%20TIMESTAMP%20%27${this.getDateString(-this.previousDaysToShow)}%2000%3A00%3A00%27%20AND%20Meldedatum%20%3C%3D%20TIMESTAMP%20%27${this.getDateString(1)}%2000%3A00%3A00%27&outFields=Landkreis,Meldedatum,AnzahlFall&outSR=4326&f=json`
    @@ -38,26 +40,29 @@ class IncidenceWidget {
    }

    async createWidget(items) {
    // Inzidenz data
    let data = await this.getData()
    // New Cases data
    let data2 = await this.getNewCasesData()

    // Basic widget setup
    let list = new ListWidget()
    list.setPadding(0, 0, 0, 0)
    let textStack = list.addStack()
    textStack.setPadding(14, 14, 0, 14)
    textStack.setPadding(8, 14, 0, 14)
    textStack.layoutVertically()
    textStack.topAlignContent()
    // Header

    // Header "Inzidenz"
    let header = textStack.addText("🦠 Inzidenz".toUpperCase())
    header.font = Font.mediumSystemFont(13)
    textStack.addSpacer()
    header.font = Font.mediumSystemFont(12)
    textStack.addSpacer(4)

    if(data.error) {
    if(data.error || data2.error) {
    // Error handling
    let loadingIndicator = textStack.addText(data.error.toUpperCase())
    textStack.setPadding(14, 14, 14, 14)
    loadingIndicator.font = Font.mediumSystemFont(13)
    loadingIndicator.font = Font.mediumSystemFont(12)
    loadingIndicator.textOpacity = 0.5
    let spacer = textStack.addStack()
    spacer.addSpacer();
    @@ -72,21 +77,48 @@ class IncidenceWidget {
    let incidenceValueLabel = valueStack.addText(data.incidence + data.trend)
    incidenceValueLabel.font = Font.boldSystemFont(24)
    incidenceValueLabel.textColor = data.incidence >= 100 ? new Color("9e000a") : data.incidence >= 50 ? Color.red() : data.incidence >= 35 ? Color.yellow() : Color.green();
    incidenceStack.addText(data.areaName)

    // Chip for displaying state data
    valueStack.addSpacer(4)

    // Chip for displaying state data
    valueStack.addSpacer(5)
    let stateStack = valueStack.addStack()
    let stateText = stateStack.addText(data.incidenceBySide + "\n" + data.areaNameBySide)
    stateStack.backgroundColor = new Color('888888', .5)
    stateStack.cornerRadius = 4
    stateStack.setPadding(2, 4, 2, 4)
    let stateStackInner = stateStack.addStack()
    stateStackInner.layoutVertically()
    let stateText = stateStackInner.addText(data.incidenceBySide)
    stateText.font = Font.mediumSystemFont(9)
    stateText.textColor = Color.white()
    valueStack.addSpacer()

    let stateText2 = stateStackInner.addText(data.areaNameBySide)
    stateText2.font = Font.mediumSystemFont(9)
    stateText2.textColor = Color.white()
    // valueStack.addSpacer(5)

    // Label Area
    let incidenceValueArea = incidenceStack.addText(data.areaName)
    incidenceValueArea.font = Font.mediumSystemFont(12)
    incidenceValueArea.textColor = Color.gray()

    // Header "Neuinfektionen"
    textStack.addSpacer(8)
    let header = textStack.addText("🦠 Neuinfektionen".toUpperCase())
    header.font = Font.mediumSystemFont(12)
    textStack.addSpacer(1)

    let newinfStack = textStack.addStack()
    newinfStack.bottomAlignContent()
    newinfStack.addSpacer(5)
    let newinfValue = newinfStack.addText("+" + parseInt(data2.value).toLocaleString())
    newinfValue.font = Font.boldSystemFont(20)

    let newinfValueStack = newinfStack.addStack()
    let newinfValueLabel = newinfValueStack.addText(" " + data2.areaName)
    newinfValueLabel.font = Font.mediumSystemFont(13)
    newinfValueLabel.textColor = Color.gray()
    newinfValueStack.addSpacer(5)

    // Chart
    let chart = new LineChart(400, 120, data.timeline).configure((ctx, path) => {
    let chart = new LineChart(400, 98, data.timeline).configure((ctx, path) => {
    ctx.opaque = false;
    ctx.setFillColor(new Color("888888", .25));
    ctx.addPath(path);
    @@ -99,6 +131,15 @@ class IncidenceWidget {
    }
    return list
    }

    async getNewCasesData() {
    const data = await new Request(this.newCasesApiUrl).loadJSON();
    const attr = data.features[0].attributes;
    return {
    value: attr.value,
    areaName: "DE",
    };
    }

    async getData() {
    try {
    @@ -211,4 +252,4 @@ class LineChart {

    }

    await new IncidenceWidget().run();
    await new IncidenceWidget().run();
  6. @kevinkub kevinkub revised this gist Oct 29, 2020. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion incidence.js
    Original file line number Diff line number Diff line change
    @@ -78,7 +78,7 @@ class IncidenceWidget {
    valueStack.addSpacer(4)
    let stateStack = valueStack.addStack()
    let stateText = stateStack.addText(data.incidenceBySide + "\n" + data.areaNameBySide)
    stateStack.backgroundColor = new Color('888888', .25)
    stateStack.backgroundColor = new Color('888888', .5)
    stateStack.cornerRadius = 4
    stateStack.setPadding(2, 4, 2, 4)
    stateText.font = Font.mediumSystemFont(9)
  7. @kevinkub kevinkub revised this gist Oct 28, 2020. 1 changed file with 2 additions and 0 deletions.
    2 changes: 2 additions & 0 deletions incidence.js
    Original file line number Diff line number Diff line change
    @@ -1,5 +1,7 @@
    // Licence: Robert Koch-Institut (RKI), dl-de/by-2-0

    // Thanks to @rphl (https://github.com/rphl) and @tzschies (https://github.com/tzschies) for their inspiring work on this widget. See https://gist.github.com/rphl/0491c5f9cb345bf831248732374c4ef5 and https://gist.github.com/tzschies/563fab70b37609bc8f2f630d566bcbc9.

    class IncidenceWidget {

    constructor() {
  8. @kevinkub kevinkub revised this gist Oct 28, 2020. 1 changed file with 198 additions and 55 deletions.
    253 changes: 198 additions & 55 deletions incidence.js
    Original file line number Diff line number Diff line change
    @@ -1,69 +1,212 @@
    // Licence: Robert Koch-Institut (RKI), dl-de/by-2-0
    const apiUrl = (location) => `https://services7.arcgis.com/mOBPykOjAyBO2ZKk/arcgis/rest/services/RKI_Landkreisdaten/FeatureServer/0/query?where=1%3D1&outFields=GEN,cases7_per_100k&geometry=${location.longitude.toFixed(3)}%2C${location.latitude.toFixed(3)}&geometryType=esriGeometryPoint&inSR=4326&spatialRel=esriSpatialRelWithin&returnGeometry=false&outSR=4326&f=json`
    const apiUrlStates = 'https://services7.arcgis.com/mOBPykOjAyBO2ZKk/arcgis/rest/services/Coronaf%E4lle_in_den_Bundesl%E4ndern/FeatureServer/0/query?where=1%3D1&outFields=cases7_bl_per_100k&returnGeometry=false&outSR=4326&f=json'

    const widget = await createWidget()
    if (!config.runsInWidget) {
    await widget.presentSmall()
    }
    Script.setWidget(widget)
    Script.complete()
    class IncidenceWidget {

    constructor() {
    this.previousDaysToShow = 31;
    this.apiUrlDistricts = (location) => `https://services7.arcgis.com/mOBPykOjAyBO2ZKk/arcgis/rest/services/RKI_Landkreisdaten/FeatureServer/0/query?where=1%3D1&outFields=RS,GEN,cases7_bl_per_100k,cases7_per_100k,BL&geometry=${location.longitude.toFixed(3)}%2C${location.latitude.toFixed(3)}&geometryType=esriGeometryPoint&inSR=4326&spatialRel=esriSpatialRelWithin&returnGeometry=false&outSR=4326&f=json`
    this.apiUrlDistrictsHistory = (districtId) => `https://services7.arcgis.com/mOBPykOjAyBO2ZKk/arcgis/rest/services/RKI_COVID19/FeatureServer/0/query?where=IdLandkreis%20%3D%20%27${districtId}%27%20AND%20Meldedatum%20%3E%3D%20TIMESTAMP%20%27${this.getDateString(-this.previousDaysToShow)}%2000%3A00%3A00%27%20AND%20Meldedatum%20%3C%3D%20TIMESTAMP%20%27${this.getDateString(1)}%2000%3A00%3A00%27&outFields=Landkreis,Meldedatum,AnzahlFall&outSR=4326&f=json`
    this.stateToAbbr = {
    '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'
    };
    }

    async run() {
    let widget = await this.createWidget()
    if (!config.runsInWidget) {
    await widget.presentSmall()
    }
    Script.setWidget(widget)
    Script.complete()
    }

    async function createWidget(items) {
    const data = await getData()
    const list = new ListWidget()
    const header = list.addText("🦠 Inzidenz".toUpperCase())
    header.font = Font.mediumSystemFont(13)
    if(data) {
    if(!data.shouldCache) {
    list.addSpacer(6)
    const loadingIndicator = list.addText("Ort wird ermittelt...".toUpperCase())
    async createWidget(items) {
    let data = await this.getData()

    // Basic widget setup
    let list = new ListWidget()
    list.setPadding(0, 0, 0, 0)
    let textStack = list.addStack()
    textStack.setPadding(14, 14, 0, 14)
    textStack.layoutVertically()
    textStack.topAlignContent()

    // Header
    let header = textStack.addText("🦠 Inzidenz".toUpperCase())
    header.font = Font.mediumSystemFont(13)
    textStack.addSpacer()

    if(data.error) {
    // Error handling
    let loadingIndicator = textStack.addText(data.error.toUpperCase())
    textStack.setPadding(14, 14, 14, 14)
    loadingIndicator.font = Font.mediumSystemFont(13)
    loadingIndicator.textOpacity = 0.5
    }
    list.addSpacer()
    const label = list.addText(data.incidence+"")
    label.font = Font.boldSystemFont(24)
    label.textColor = data.incidence >= 50 ? Color.red() : data.incidence >= 35 ? Color.orange() : Color.green()
    list.addText(data.areaName)
    if(data.shouldCache) {
    let spacer = textStack.addStack()
    spacer.addSpacer();
    } else {
    // Enable caching
    list.refreshAfterDate = new Date(Date.now() + 60*60*1000)

    // Main stack for value and area name
    let incidenceStack = textStack.addStack()
    let valueStack = incidenceStack.addStack()
    incidenceStack.layoutVertically()
    let incidenceValueLabel = valueStack.addText(data.incidence + data.trend)
    incidenceValueLabel.font = Font.boldSystemFont(24)
    incidenceValueLabel.textColor = data.incidence >= 100 ? new Color("9e000a") : data.incidence >= 50 ? Color.red() : data.incidence >= 35 ? Color.yellow() : Color.green();
    incidenceStack.addText(data.areaName)

    // Chip for displaying state data
    valueStack.addSpacer(4)
    let stateStack = valueStack.addStack()
    let stateText = stateStack.addText(data.incidenceBySide + "\n" + data.areaNameBySide)
    stateStack.backgroundColor = new Color('888888', .25)
    stateStack.cornerRadius = 4
    stateStack.setPadding(2, 4, 2, 4)
    stateText.font = Font.mediumSystemFont(9)
    stateText.textColor = Color.white()
    valueStack.addSpacer()

    // Chart
    let chart = new LineChart(400, 120, data.timeline).configure((ctx, path) => {
    ctx.opaque = false;
    ctx.setFillColor(new Color("888888", .25));
    ctx.addPath(path);
    ctx.fillPath(path);
    }).getImage();
    let chartStack = list.addStack()
    chartStack.setPadding(0, 0, 0, 0)
    let img = chartStack.addImage(chart)
    img.applyFittingContentMode()
    }
    } else {
    list.addSpacer()
    list.addText("Daten nicht verfügbar")
    return list
    }
    return list
    }

    async function getData() {
    try {
    const location = await getLocation()
    if(location) {
    let data = await new Request(apiUrl(location)).loadJSON()
    const attr = data.features[0].attributes
    return { incidence: attr.cases7_per_100k.toFixed(1), areaName: attr.GEN, shouldCache: true };
    } else {
    let data = await new Request(apiUrlStates).loadJSON()
    const incidencePerState = data.features.map((f) => f.attributes.cases7_bl_per_100k)
    const averageIncidence = incidencePerState.reduce((a, b) => a + b) / incidencePerState.length
    return { incidence: averageIncidence.toFixed(1), areaName: "Deutschland", shouldCache: false };

    async getData() {
    try {
    let location = await this.getLocation()
    if(location) {
    let currentData = await new Request(this.apiUrlDistricts(location)).loadJSON()
    let attr = currentData.features[0].attributes
    let historicalData = await new Request(this.apiUrlDistrictsHistory(attr.RS)).loadJSON()
    let aggregate = historicalData.features.map(f => f.attributes).reduce((dict, feature) => {
    dict[feature["Meldedatum"]] = (dict[feature["Meldedatum"]]|0) + feature["AnzahlFall"];
    return dict;
    }, {});
    let timeline = Object.keys(aggregate).sort().map(k => aggregate[k]);
    let casesYesterday7 = timeline.slice(-8, -1).reduce(this.sum);
    let casesToday7 = timeline.slice(-7).reduce(this.sum);
    let trend = (casesToday7 == casesYesterday7) ? '→' : (casesToday7 > casesYesterday7) ? '↑' : '↓';
    return {
    incidence: attr.cases7_per_100k.toFixed(0),
    areaName: attr.GEN,
    trend: trend,
    incidenceBySide:
    attr.cases7_bl_per_100k.toFixed(0),
    areaNameBySide:
    this.stateToAbbr[attr.BL],
    timeline: timeline
    };
    }
    return { error: "Standort nicht verfügbar." }
    } catch(e) {
    return { error: "Fehler bei Datenabruf." };
    }
    } catch(e) {
    return null
    }
    }

    getDateString(addDays) {
    addDays = addDays || 0;
    return new Date(Date.now() + addDays * 24 * 60 * 60 * 1000).toISOString().substring(0, 10)
    }

    async getLocation() {
    try {
    if(args.widgetParameter) {
    let fixedCoordinates = args.widgetParameter.split(",").map(parseFloat)
    return { latitude: fixedCoordinates[0], longitude: fixedCoordinates[1] }
    } else {
    Location.setAccuracyToThreeKilometers()
    return await Location.current()
    }
    } catch(e) {
    return null;
    }
    }

    sum(a, b) {
    return a + b;
    }

    }

    async function getLocation() {
    try {
    if(args.widgetParameter) {
    const fixedCoordinates = args.widgetParameter.split(",").map(parseFloat)
    return { latitude: fixedCoordinates[0], longitude: fixedCoordinates[1] }
    class LineChart {

    constructor(width, height, values) {
    this.ctx = new DrawContext()
    this.ctx.size = new Size(width, height)
    this.values = values;
    }

    _calculatePath() {
    let maxValue = Math.max(...this.values);
    let minValue = Math.min(...this.values);
    let difference = maxValue - minValue;
    let count = this.values.length;
    let step = this.ctx.size.width / (count - 1);
    let points = this.values.map((current, index, all) => {
    let x = step*index
    let y = this.ctx.size.height - (current - minValue) / difference * this.ctx.size.height;
    return new Point(x, y)
    });
    return this._getSmoothPath(points);
    }

    _getSmoothPath(points) {
    let path = new Path()
    path.move(new Point(0, this.ctx.size.height));
    path.addLine(points[0]);
    for(var i = 0; i < points.length-1; i ++) {
    let xAvg = (points[i].x + points[i+1].x) / 2;
    let yAvg = (points[i].y + points[i+1].y) / 2;
    let avg = new Point(xAvg, yAvg);
    let cp1 = new Point((xAvg + points[i].x) / 2, points[i].y);
    let next = new Point(points[i+1].x, points[i+1].y);
    let cp2 = new Point((xAvg + points[i+1].x) / 2, points[i+1].y);
    path.addQuadCurve(avg, cp1);
    path.addQuadCurve(next, cp2);
    }
    path.addLine(new Point(this.ctx.size.width, this.ctx.size.height))
    path.closeSubpath()
    return path;
    }

    configure(fn) {
    let path = this._calculatePath()
    if(fn) {
    fn(this.ctx, path);
    } else {
    Location.setAccuracyToThreeKilometers()
    return await Location.current()
    this.ctx.addPath(path);
    this.ctx.fillPath(path);
    }
    } catch(e) {
    return null;
    return this.ctx;
    }
    }

    }

    await new IncidenceWidget().run();
  9. @kevinkub kevinkub revised this gist Oct 21, 2020. 1 changed file with 53 additions and 56 deletions.
    109 changes: 53 additions & 56 deletions incidence.js
    Original file line number Diff line number Diff line change
    @@ -1,72 +1,69 @@
    // Licence: Robert Koch-Institut (RKI), dl-de/by-2-0
    const apiUrl = (location) => `https://services7.arcgis.com/mOBPykOjAyBO2ZKk/arcgis/rest/services/RKI_Landkreisdaten/FeatureServer/0/query?where=1%3D1&outFields=GEN,cases7_per_100k&geometry=${location.longitude.toFixed(3)}%2C${location.latitude.toFixed(3)}&geometryType=esriGeometryPoint&inSR=4326&spatialRel=esriSpatialRelWithin&returnGeometry=false&outSR=4326&f=json`
    const apiUrlStates = 'https://services7.arcgis.com/mOBPykOjAyBO2ZKk/arcgis/rest/services/Coronaf%E4lle_in_den_Bundesl%E4ndern/FeatureServer/0/query?where=1%3D1&outFields=cases7_bl_per_100k&returnGeometry=false&outSR=4326&f=json'

    let widget = await createWidget()
    const widget = await createWidget()
    if (!config.runsInWidget) {
    await widget.presentSmall()
    }

    Script.setWidget(widget)
    Script.complete()

    async function createWidget(items) {
    let location

    if(args.widgetParameter) {

    const fixedCoordinates = args.widgetParameter.split(",").map(parseFloat)

    location = {
    latitude: fixedCoordinates[0],
    longitude: fixedCoordinates[1]
    }

    } else {

    Location.setAccuracyToThreeKilometers()
    location = await Location.current()

    }

    const data = await new Request(apiUrl(location)).loadJSON()

    if(!data || !data.features || !data.features.length) {
    const errorList = new ListWidget()
    errorList.addText("Keine Ergebnisse für den aktuellen Ort gefunden.")
    return errorList
    }

    const attr = data.features[0].attributes
    const incidence = attr.cases7_per_100k.toFixed(1)
    const cityName = attr.GEN
    const data = await getData()
    const list = new ListWidget()

    if(Device.isUsingDarkAppearance()){
    const gradient = new LinearGradient()
    gradient.locations = [0, 1]
    gradient.colors = [
    new Color("111111"),
    new Color("222222")
    ]
    list.backgroundGradient = gradient
    }

    const header = list.addText("🦠 Inzidenz".toUpperCase())
    header.font = Font.mediumSystemFont(13)

    list.addSpacer()

    const label = list.addText(incidence+"")
    label.font = Font.boldSystemFont(24)
    label.textColor = Color.green()

    if(incidence >= 50) {
    label.textColor = Color.red()
    } else if(incidence >= 35) {
    label.textColor = Color.orange()
    if(data) {
    if(!data.shouldCache) {
    list.addSpacer(6)
    const loadingIndicator = list.addText("Ort wird ermittelt...".toUpperCase())
    loadingIndicator.font = Font.mediumSystemFont(13)
    loadingIndicator.textOpacity = 0.5
    }
    list.addSpacer()
    const label = list.addText(data.incidence+"")
    label.font = Font.boldSystemFont(24)
    label.textColor = data.incidence >= 50 ? Color.red() : data.incidence >= 35 ? Color.orange() : Color.green()
    list.addText(data.areaName)
    if(data.shouldCache) {
    list.refreshAfterDate = new Date(Date.now() + 60*60*1000)
    }
    } else {
    list.addSpacer()
    list.addText("Daten nicht verfügbar")
    }

    list.addText(cityName)

    return list
    }

    async function getData() {
    try {
    const location = await getLocation()
    if(location) {
    let data = await new Request(apiUrl(location)).loadJSON()
    const attr = data.features[0].attributes
    return { incidence: attr.cases7_per_100k.toFixed(1), areaName: attr.GEN, shouldCache: true };
    } else {
    let data = await new Request(apiUrlStates).loadJSON()
    const incidencePerState = data.features.map((f) => f.attributes.cases7_bl_per_100k)
    const averageIncidence = incidencePerState.reduce((a, b) => a + b) / incidencePerState.length
    return { incidence: averageIncidence.toFixed(1), areaName: "Deutschland", shouldCache: false };
    }
    } catch(e) {
    return null
    }
    }

    async function getLocation() {
    try {
    if(args.widgetParameter) {
    const fixedCoordinates = args.widgetParameter.split(",").map(parseFloat)
    return { latitude: fixedCoordinates[0], longitude: fixedCoordinates[1] }
    } else {
    Location.setAccuracyToThreeKilometers()
    return await Location.current()
    }
    } catch(e) {
    return null;
    }
    }
  10. @kevinkub kevinkub revised this gist Oct 19, 2020. No changes.
  11. @kevinkub kevinkub revised this gist Oct 19, 2020. 1 changed file with 24 additions and 0 deletions.
    24 changes: 24 additions & 0 deletions incidence.js
    Original file line number Diff line number Diff line change
    @@ -1,34 +1,46 @@
    // Licence: Robert Koch-Institut (RKI), dl-de/by-2-0
    const apiUrl = (location) => `https://services7.arcgis.com/mOBPykOjAyBO2ZKk/arcgis/rest/services/RKI_Landkreisdaten/FeatureServer/0/query?where=1%3D1&outFields=GEN,cases7_per_100k&geometry=${location.longitude.toFixed(3)}%2C${location.latitude.toFixed(3)}&geometryType=esriGeometryPoint&inSR=4326&spatialRel=esriSpatialRelWithin&returnGeometry=false&outSR=4326&f=json`

    let widget = await createWidget()
    if (!config.runsInWidget) {
    await widget.presentSmall()
    }

    Script.setWidget(widget)
    Script.complete()

    async function createWidget(items) {
    let location

    if(args.widgetParameter) {

    const fixedCoordinates = args.widgetParameter.split(",").map(parseFloat)

    location = {
    latitude: fixedCoordinates[0],
    longitude: fixedCoordinates[1]
    }

    } else {

    Location.setAccuracyToThreeKilometers()
    location = await Location.current()

    }

    const data = await new Request(apiUrl(location)).loadJSON()

    if(!data || !data.features || !data.features.length) {
    const errorList = new ListWidget()
    errorList.addText("Keine Ergebnisse für den aktuellen Ort gefunden.")
    return errorList
    }

    const attr = data.features[0].attributes
    const incidence = attr.cases7_per_100k.toFixed(1)
    const cityName = attr.GEN
    const list = new ListWidget()

    if(Device.isUsingDarkAppearance()){
    const gradient = new LinearGradient()
    gradient.locations = [0, 1]
    @@ -38,11 +50,23 @@ async function createWidget(items) {
    ]
    list.backgroundGradient = gradient
    }

    const header = list.addText("🦠 Inzidenz".toUpperCase())
    header.font = Font.mediumSystemFont(13)

    list.addSpacer()

    const label = list.addText(incidence+"")
    label.font = Font.boldSystemFont(24)
    label.textColor = Color.green()

    if(incidence >= 50) {
    label.textColor = Color.red()
    } else if(incidence >= 35) {
    label.textColor = Color.orange()
    }

    list.addText(cityName)

    return list
    }
  12. @kevinkub kevinkub revised this gist Oct 18, 2020. 1 changed file with 16 additions and 2 deletions.
    18 changes: 16 additions & 2 deletions incidence.js
    Original file line number Diff line number Diff line change
    @@ -8,9 +8,23 @@ Script.setWidget(widget)
    Script.complete()

    async function createWidget(items) {
    Location.setAccuracyToThreeKilometers()
    const location = await Location.current()
    let location
    if(args.widgetParameter) {
    const fixedCoordinates = args.widgetParameter.split(",").map(parseFloat)
    location = {
    latitude: fixedCoordinates[0],
    longitude: fixedCoordinates[1]
    }
    } else {
    Location.setAccuracyToThreeKilometers()
    location = await Location.current()
    }
    const data = await new Request(apiUrl(location)).loadJSON()
    if(!data || !data.features || !data.features.length) {
    const errorList = new ListWidget()
    errorList.addText("Keine Ergebnisse für den aktuellen Ort gefunden.")
    return errorList
    }
    const attr = data.features[0].attributes
    const incidence = attr.cases7_per_100k.toFixed(1)
    const cityName = attr.GEN
  13. @kevinkub kevinkub revised this gist Oct 18, 2020. 1 changed file with 12 additions and 9 deletions.
    21 changes: 12 additions & 9 deletions incidence.js
    Original file line number Diff line number Diff line change
    @@ -8,21 +8,24 @@ Script.setWidget(widget)
    Script.complete()

    async function createWidget(items) {
    Location.setAccuracyToKilometer()
    Location.setAccuracyToThreeKilometers()
    const location = await Location.current()
    const data = await new Request(apiUrl(location)).loadJSON()
    const attr = data.features[0].attributes
    const incidence = attr.cases7_per_100k.toFixed(1)
    const cityName = attr.GEN
    const gradient = new LinearGradient()
    gradient.locations = [0, 1]
    gradient.colors = [
    new Color("111111"),
    new Color("222222")
    ]
    const list = new ListWidget()
    list.backgroundGradient = gradient
    list.addText("🦠 Inzidenz")
    if(Device.isUsingDarkAppearance()){
    const gradient = new LinearGradient()
    gradient.locations = [0, 1]
    gradient.colors = [
    new Color("111111"),
    new Color("222222")
    ]
    list.backgroundGradient = gradient
    }
    const header = list.addText("🦠 Inzidenz".toUpperCase())
    header.font = Font.mediumSystemFont(13)
    list.addSpacer()
    const label = list.addText(incidence+"")
    label.font = Font.boldSystemFont(24)
  14. @kevinkub kevinkub created this gist Oct 17, 2020.
    31 changes: 31 additions & 0 deletions incidence.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,31 @@
    const apiUrl = (location) => `https://services7.arcgis.com/mOBPykOjAyBO2ZKk/arcgis/rest/services/RKI_Landkreisdaten/FeatureServer/0/query?where=1%3D1&outFields=GEN,cases7_per_100k&geometry=${location.longitude.toFixed(3)}%2C${location.latitude.toFixed(3)}&geometryType=esriGeometryPoint&inSR=4326&spatialRel=esriSpatialRelWithin&returnGeometry=false&outSR=4326&f=json`

    let widget = await createWidget()
    if (!config.runsInWidget) {
    await widget.presentSmall()
    }
    Script.setWidget(widget)
    Script.complete()

    async function createWidget(items) {
    Location.setAccuracyToKilometer()
    const location = await Location.current()
    const data = await new Request(apiUrl(location)).loadJSON()
    const attr = data.features[0].attributes
    const incidence = attr.cases7_per_100k.toFixed(1)
    const cityName = attr.GEN
    const gradient = new LinearGradient()
    gradient.locations = [0, 1]
    gradient.colors = [
    new Color("111111"),
    new Color("222222")
    ]
    const list = new ListWidget()
    list.backgroundGradient = gradient
    list.addText("🦠 Inzidenz")
    list.addSpacer()
    const label = list.addText(incidence+"")
    label.font = Font.boldSystemFont(24)
    list.addText(cityName)
    return list
    }