Skip to content

Instantly share code, notes, and snippets.

@notjosh
Last active January 29, 2021 16:59
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save notjosh/cafab62e427a5d6bc12aa99d732bb02c to your computer and use it in GitHub Desktop.
Save notjosh/cafab62e427a5d6bc12aa99d732bb02c to your computer and use it in GitHub Desktop.
COVID vaccination progress in Germany
'use strict';
const CONFIG = {
dataURL: 'https://rki-vaccination-data.vercel.app/api',
alsoDrawState: undefined,
};
const fetchJSON = async (url) => {
const request = new Request(url);
const data = await request.loadJSON()
return data;
};
const drawError = (message) => {
const widget = new ListWidget();
let text = widget.addText(message);
text.font = Font.mediumSystemFont(16);
return widget;
};
const drawRegion = (
view,
title,
{ difference_to_the_previous_day: delta, vaccinated, total: population },
) => {
const percent = population > 0 ? vaccinated / population : 0;
const stack = view.addStack();
stack.layoutVertically();
stack.spacing = 4;
const titleWidget = stack.addText(title)
titleWidget.minimumScaleFactor = 0.5;
const row = stack.addStack();
row.layoutHorizontally();
row.centerAlignContent();
if (delta !== 0) {
row.addText(delta >= 0 ? '+' : '-');
}
const deltaWidget = row.addText(delta.toString(10))
deltaWidget.minimumScaleFactor = 0.8;
const ctx = new DrawContext();
const size = new Size(58, 4);
ctx.size = size;
ctx.opaque = false;
ctx.respectScreenScale = true;
const backgroundColourHex = Device.isUsingDarkAppearance() ? '#666666' : '#dddddd';
ctx.setFillColor(new Color(backgroundColourHex, 0.4));
ctx.fillRect(new Rect(0, 0, size.width, size.height));
ctx.setFillColor(Color.green());
ctx.fillRect(new Rect(0, 0, size.width * percent, size.height));
const image = ctx.getImage();
const imageWidget = stack.addImage(image);
imageWidget.cornerRadius = size.height;
return stack;
}
const extractData = (data, state) => {
let node;
if (state != null) {
node = data.states[state];
} else {
node = data;
}
// quick validation
const fields = [
'difference_to_the_previous_day',
'vaccinated',
'total',
];
if (node == null) {
throw new Error(`missing node${state != null ? ' for state: ' + state : ''}`);
}
for (const field of fields) {
if (node[field] == null) {
throw new Error(`missing data: ${field}`);
}
}
return node;
};
const drawData = (data) => {
const widget = new ListWidget();
const padding = 16;
widget.setPadding(padding, padding, padding, padding);
drawRegion(widget, '🇩🇪 Germany', extractData(data));
if (CONFIG.alsoDrawState != null) {
widget.addSpacer();
const state = CONFIG.alsoDrawState;
drawRegion(widget, state, extractData(data, state));
}
return widget;
}
const run = async () => {
if (args.widgetParameter != null) {
CONFIG.alsoDrawState = args.widgetParameter;
}
try {
const url = `${CONFIG.dataURL}?nocache=${(new Date()).getTime()}`;
const data = await fetchJSON(url);
return drawData(data);
} catch (error) {
return drawError(error.message || 'Gasp! An unknown error!');
}
};
// for testing:
if (config.runsInApp) {
//*
args = {
widgetParameter: 'Brandenburg',
...args,
}
/**/
}
const widget = await run();
Script.setWidget(widget);
Script.complete();
if (!config.runsInWidget) {
widget.presentSmall();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment