Last active
November 10, 2024 16:20
-
-
Save Leibinger015/7d011a688831f8d47a1fc3ea8d99af56 to your computer and use it in GitHub Desktop.
An HomeScreen widget for a Concentric circle calendar.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// This is a "Concentric circle calendar" widget script for the iPhone app "Scriptable". | |
// Script-Code: ©️anb030.de | |
// Script-Datum: 26.10.2024 | |
// Script-Last-Edit: 01.11.2024 | |
// Version: 1.5e: BugFixes: The script has been slightly revised. Integration for calc of leap years and years with 52 or 53 calendar weeks. Fine tuning of the circular ring values. Note: Switching between light or dark mode can take a few seconds in automatic mode because the value in the script is dynamic and iOS 18.x is currently causing problems. For reason: New with manual Light/Dark mode selection per Parameter Widget-Setup. | |
// Start-Script | |
// Parameter einlesen | |
let mode = args.widgetParameter; | |
// Farben für die Ringe | |
const yearCircleColor = new Color('#FF4040'); // Außenring (Korallrot für Kalenderwochen) | |
const monthCircleColor = new Color('#00b0ba'); // Mittelring (anb030 Blau für Monat) | |
const dayCircleColor = new Color('#a69a7d'); // Innenring (light Gold für Tag) | |
// Bestimme den Darstellungsmodus | |
let isDarkMode; | |
if (mode === "Dark") { | |
isDarkMode = true; | |
} else if (mode === "Light") { | |
isDarkMode = false; | |
} else { | |
isDarkMode = Device.isUsingDarkAppearance(); | |
} | |
// Hintergrundfarbe und darauf basierende Textfarbe | |
const widgetBackgroundColor = isDarkMode ? new Color('#1c1c1e') : new Color('#ffffff'); | |
const circleTextColor = isDarkMode ? new Color('#ffffff') : new Color('#000000'); | |
const bgCircleColor = isDarkMode ? new Color('#424242') : new Color('#D8D8D8'); | |
// Datumswerte | |
let today = new Date(); | |
let dayNumber = Math.ceil((today - new Date(today.getFullYear(), 0, 1)) / 86400000); | |
let thisDayDate = today.getDate(); | |
let thisMonth = today.getMonth(); | |
let thisYear = today.getFullYear(); | |
let daysYear = (leapYear(thisYear)) ? 366 : 365; | |
let daysThisMonth = daysInMonth(thisMonth + 1, thisYear); | |
let totalWeeks = getTotalWeeksInYear(thisYear); | |
let weekNumber = getWeekNumber(today); | |
// Canvas und Layout-Einstellungen | |
const canvSize = 282; | |
const canvTextSize = 22; | |
const canvRadius = 120; // Radius des Kreises | |
const canvWidth = 22; // Breite des Kreises | |
const canvas = new DrawContext(); | |
canvas.opaque = false; | |
canvas.size = new Size(canvSize, canvSize); | |
canvas.respectScreenScale = true; | |
// Berechnung der Kreisdrehungen | |
let yearDegree = Math.floor((weekNumber / totalWeeks) * 100 * 3.6); // Für Kalenderwochen im Außenring | |
let monthDegree = Math.floor((thisMonth / 11) * 100 * 3.6); // Für den Monat im Mittelring | |
let dayDegree = Math.floor((thisDayDate / daysThisMonth) * 100 * 3.6); | |
/* | |
BEGIN Widget Layout | |
*/ | |
let widget = new ListWidget(); | |
widget.setPadding(0, 5, 1, 0); | |
// Kalenderwochen-Kreis (außen) | |
makeCircle(0, bgCircleColor, yearCircleColor, yearDegree); | |
drawMyText(thisYear.toString().slice(-2), circleTextColor, 258); // Text bleibt das aktuelle Jahr | |
// Monats-Kreis (Mitte) | |
let monthRadiusOffset = 27; | |
makeCircle(monthRadiusOffset, bgCircleColor, monthCircleColor, monthDegree); | |
drawMyText((thisMonth + 1).toString(), circleTextColor, 232); // Zeigt den aktuellen Monat (1-12) | |
// Tag-Kreis (innen) | |
let dayRadiusOffset = 54; | |
makeCircle(dayRadiusOffset, bgCircleColor, dayCircleColor, dayDegree); | |
drawMyText(thisDayDate.toString(), circleTextColor, 205); | |
// Kalenderwoche in der Mitte | |
drawMyText("KW", circleTextColor, 120, canvTextSize * 1.25); | |
drawMyText(weekNumber.toString(), circleTextColor, 155, canvTextSize * 2.25); | |
// Widget-Hintergrundfarbe und Aktualisierungsintervall | |
widget.backgroundColor = widgetBackgroundColor; | |
widget.refreshAfterDate = new Date(Date.now() + 5 * 60 * 1000); | |
widget.addImage(canvas.getImage()); | |
Script.setWidget(widget); | |
widget.presentSmall(); | |
Script.complete(); | |
/* | |
END Widget Layout | |
*/ | |
function makeCircle(radiusOffset, bgCircleColor, fgCircleColor, degree) { | |
let ctr = new Point(canvSize / 2, canvSize / 2); | |
// Hintergrundkreis | |
let bgx = ctr.x - (canvRadius - radiusOffset); | |
let bgy = ctr.y - (canvRadius - radiusOffset); | |
let bgd = 2 * (canvRadius - radiusOffset); | |
let bgr = new Rect(bgx, bgy, bgd, bgd); | |
canvas.setStrokeColor(bgCircleColor); | |
canvas.setLineWidth(canvWidth); | |
canvas.strokeEllipse(bgr); | |
// Vordergrundkreis | |
canvas.setFillColor(fgCircleColor); | |
for (let t = 0; t < degree; t++) { | |
let rect_x = ctr.x + (canvRadius - radiusOffset) * sinDeg(t) - canvWidth / 2; | |
let rect_y = ctr.y - (canvRadius - radiusOffset) * cosDeg(t) - canvWidth / 2; | |
let rect_r = new Rect(rect_x, rect_y, canvWidth, canvWidth); | |
canvas.fillEllipse(rect_r); | |
} | |
} | |
function drawMyText(txt, txtColor, txtOffset, fontSize = canvTextSize) { | |
const txtRect = new Rect( | |
canvTextSize / 2 - 10, | |
txtOffset - fontSize / 2, | |
canvSize, | |
fontSize | |
); | |
canvas.setTextColor(txtColor); | |
canvas.setFont(Font.boldSystemFont(fontSize)); | |
canvas.setTextAlignedCenter(); | |
canvas.drawTextInRect(txt, txtRect); | |
} | |
function sinDeg(deg) { | |
return Math.sin((deg * Math.PI) / 180); | |
} | |
function cosDeg(deg) { | |
return Math.cos((deg * Math.PI) / 180); | |
} | |
function leapYear(year) { | |
return ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0); | |
} | |
function daysInMonth(month, year) { | |
return new Date(year, month, 0).getDate(); | |
} | |
// Funktion zur Ermittlung der Kalenderwoche | |
function getWeekNumber(d) { | |
d = new Date(Date.UTC(d.getFullYear(), d.getMonth(), d.getDate())); | |
d.setUTCDate(d.getUTCDate() + 4 - (d.getUTCDay() || 7)); | |
let yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1)); | |
return Math.ceil(((d - yearStart) / 86400000 + 1) / 7); | |
} | |
// Funktion zur Bestimmung der Gesamtanzahl der Wochen im Jahr | |
function getTotalWeeksInYear(year) { | |
let lastDayOfYear = new Date(Date.UTC(year, 11, 31)); | |
return getWeekNumber(lastDayOfYear) === 53 ? 53 : 52; | |
} | |
// Script-Ende |
BugFixes: The script has been slightly revised. Integration for calc of leap years and years with 52 or 53 calendar weeks. Fine tuning of the circular ring values. Note: Switching between light or dark mode can take a few seconds in automatic mode because the value in the script is dynamic and iOS 18.x is currently causing problems. For reason: New with manual Light/Dark mode selection per Parameter Widget-Setup.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This is a "Concentric circle" script for the Scriptable iPhone app.
Which displays a customised widget for "year, month, day and centrically the calendar week txt" in an dynamic system colours light / dark.