Skip to content

Instantly share code, notes, and snippets.

@brainno722
Last active February 17, 2024 11:04
Show Gist options
  • Save brainno722/77e9d3e2c4e45447182e226ac6153bd3 to your computer and use it in GitHub Desktop.
Save brainno722/77e9d3e2c4e45447182e226ac6153bd3 to your computer and use it in GitHub Desktop.
Medium widget with circle assets

Circle info widgets

Instructions

  1. Install Scriptable for iOS
  2. Copy/Paste the code into a new file
  3. Adjust colors/font
  4. Add the script to a widget (medium)
  5. It should appear similar to the screenshots

Transparent/no background

To make a "transparent" background (simulating your current background image), follow these steps:

  1. Go to Automators.fm
  2. Download (copy/paste) the scripts into the Scriptables folder
  3. Run the No Background Config script
  4. Follow the instructions on the website, but basically, insert the code into your script, changing the position as necessary (for example, this screenshot is a medium top widget, so await nobg.getSlice('medium-top')
  5. ???
  6. Profit!

circles with no bg

// Variables used by Scriptable.
// These must be at the very top of the file. Do not edit.
// icon-color: purple; icon-glyph: magic;
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(today.getFullYear())) ? 366 : 365;
let daysThisMonth = daysInMonth(thisMonth+1, thisYear)
const dateFormatter = new DateFormatter()
dateFormatter.dateFormat = "MMM"
const canvSize = 200;
const canvTextSize = 24;
const canvas = new DrawContext();
canvas.opaque = false;
const battCircleRemainColor = new Color('#799351'); //Battery remaining color
const battCircleDepletedColor = new Color('#d54062'); //Battery depleted color
const battCircleBGColor = new Color('#000'); //Widget background color
const battCircleTextColor = new Color('#fff'); //Widget text color (use same color as above to hide text)
const remainColor = new Color('#dddddd')
const monthCircleColor = new Color('#ffa36c')
const dayCircleColor = new Color('#ebdc87')
const dayNCircleColor = new Color('#318fb5')
const canvWidth = 16; //Battery circle thickness
const canvRadius = 80; //Battery circle radius
canvas.size = new Size(canvSize, canvSize);
canvas.respectScreenScale = true;
const batteryLevel = Device.batteryLevel();
/*
BEGIN Widget Layout
*/
let widget = new ListWidget();
widget.setPadding(0,0,0,0);
let mainStack = widget.addStack();
mainStack.layoutHorizontally();
mainStack.setPadding(0,0,0,0);
drawArc(
Math.floor(batteryLevel * 100 * 3.6),
battCircleRemainColor,
battCircleDepletedColor,
battCircleTextColor,
Math.floor(batteryLevel * 100).toString(),
"⚡️"
)
mainStack.addImage(canvas.getImage())
drawArc(
Math.floor(((thisMonth+1)/12)*100 * 3.6),
monthCircleColor,
remainColor,
battCircleTextColor,
dateFormatter.string(today),
"🗓"
)
mainStack.addImage(canvas.getImage())
drawArc(
Math.floor((thisDayDate/daysThisMonth)*100 * 3.6),
dayCircleColor,
remainColor,
battCircleTextColor,
thisDayDate.toString(),
"⭐️"
)
mainStack.addImage(canvas.getImage())
drawArc(
Math.floor(dayNumber/daysYear*100 * 3.6),
dayNCircleColor,
remainColor,
battCircleTextColor,
dayNumber.toString(),
'☑️'
)
mainStack.addImage(canvas.getImage())
// additional script required to make transparent background image
// const nobg = importModule('no-background.js')
// widget.backgroundImage = await nobg.getSlice('medium-top')
widget.backgroundColor = Color.gray()
Script.setWidget(widget);
widget.presentMedium();
Script.complete();
/*
END Widget Layout
*/
function sinDeg(deg) {
return Math.sin((deg * Math.PI) / 180);
}
function cosDeg(deg) {
return Math.cos((deg * Math.PI) / 180);
}
function drawArc(deg, fillColor, strokeColor, txtColor, text, label) {
let ctr = new Point(canvSize / 2, canvSize / 2),
bgx = ctr.x - canvRadius;
bgy = ctr.y - canvRadius;
bgd = 2 * canvRadius;
bgr = new Rect(bgx, bgy, bgd, bgd);
// canvas.opaque = false;
canvas.setFillColor(fillColor);
canvas.setStrokeColor(strokeColor);
canvas.setLineWidth(canvWidth);
canvas.strokeEllipse(bgr);
for (t = 0; t < deg; t++) {
rect_x = ctr.x + canvRadius * sinDeg(t) - canvWidth / 2;
rect_y = ctr.y - canvRadius * cosDeg(t) - canvWidth / 2;
rect_r = new Rect(rect_x, rect_y, canvWidth, canvWidth);
canvas.fillEllipse(rect_r);
}
// attempt to draw info text
const canvTextRect = new Rect(
0,
100 - canvTextSize / 2,
canvSize,
canvTextSize
);
const canvLabelRect = new Rect(
0,
(100 - canvTextSize / 2)-30,
canvSize,
canvTextSize+5
);
canvas.setTextAlignedCenter();
canvas.setTextColor(txtColor);
canvas.setFont(Font.boldSystemFont(canvTextSize));
canvas.drawTextInRect(text, canvTextRect);
canvas.drawTextInRect(label, canvLabelRect);
// return canvas.getImage()
}
function leapYear(year) {
return ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0);
}
// Month here is 1-indexed (January is 1, February is 2, etc). This is
// because we're using 0 as the day so that it returns the last day
// of the last month, so you have to add 1 to the month number
// so it returns the correct amount of days
function daysInMonth (month, year) {
return new Date(year, month, 0).getDate();
}
// Variables used by Scriptable.
// These must be at the very top of the file. Do not edit.
// icon-color: purple; icon-glyph: magic;
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(today.getFullYear())) ? 366 : 365;
let daysThisMonth = daysInMonth(thisMonth+1, thisYear)
const dateFormatter = new DateFormatter()
dateFormatter.dateFormat = "MMM"
const canvSize = 200;
const canvTextSize = 32;
const canvas = new DrawContext();
const battCircleRemainColor = new Color('#799351'); //Battery remaining color
const battCircleDepletedColor = new Color('#d54062'); //Battery depleted color
const battCircleBGColor = new Color('#000'); //Widget background color
const battCircleTextColor = new Color('#000'); //Widget text color (use same color as above to hide text)
const remainColor = new Color('#dddddd')
const monthCircleColor = new Color('#ffa36c')
const dayCircleColor = new Color('#ebdc87')
const dayNCircleColor = new Color('#318fb5')
const canvWidth = 16; //Battery circle thickness
const canvRadius = 80; //Battery circle radius
canvas.size = new Size(canvSize, canvSize);
canvas.respectScreenScale = true;
const batteryLevel = Device.batteryLevel();
/*
BEGIN Widget Layout
*/
let widget = new ListWidget();
widget.setPadding(0,0,0,0);
let mainStack = widget.addStack();
mainStack.layoutHorizontally();
mainStack.setPadding(0,0,0,0);
let batteryStack = mainStack.addStack()
let batteryArc = drawArc(
new Point(canvSize / 2, canvSize / 2),
canvRadius,
canvWidth,
Math.floor(batteryLevel * 100 * 3.6),
battCircleRemainColor,
battCircleDepletedColor,
Math.floor(batteryLevel * 100).toString(),
battCircleTextColor
);
let arcImage = batteryStack.addImage(batteryArc);
let monthCirc = mainStack.addStack()
let monthArc = drawArc(
new Point(canvSize / 2, canvSize / 2),
canvRadius,
canvWidth,
Math.floor(((thisMonth+1)/12)*100 * 3.6),
monthCircleColor,
remainColor,
dateFormatter.string(today),
battCircleTextColor
);
let monthImg = monthCirc.addImage(monthArc);
let dayCirc = mainStack.addStack()
let dayArc = drawArc(
new Point(canvSize / 2, canvSize / 2),
canvRadius,
canvWidth,
Math.floor((thisDayDate/daysThisMonth)*100 * 3.6),
dayCircleColor,
remainColor,
thisDayDate.toString(),
battCircleTextColor
);
let dayImg = dayCirc.addImage(dayArc);
let dayNCirc = mainStack.addStack()
let dayNArc = drawArc(
new Point(canvSize / 2, canvSize / 2),
canvRadius,
canvWidth,
Math.floor(dayNumber/daysYear*100 * 3.6),
dayNCircleColor,
remainColor,
dayNumber.toString(),
battCircleTextColor
);
let dayNImg = dayNCirc.addImage(dayNArc);
/*
END Widget Layout
*/
// set widget
Script.setWidget(widget);
widget.presentMedium();
Script.complete();
function sinDeg(deg) {
return Math.sin((deg * Math.PI) / 180);
}
function cosDeg(deg) {
return Math.cos((deg * Math.PI) / 180);
}
function drawArc(ctr, rad, w, deg, fillColor, strokeColor, text, txtColor) {
bgx = ctr.x - rad;
bgy = ctr.y - rad;
bgd = 2 * rad;
bgr = new Rect(bgx, bgy, bgd, bgd);
// canvas background color, but not needed
// bgc = new Rect(0, 0, canvSize, canvSize);
// canvas.setFillColor(new Color(canvBackColor));
// canvas.fill(bgc);
canvas.setFillColor(fillColor);
canvas.setStrokeColor(strokeColor);
canvas.setLineWidth(w);
canvas.strokeEllipse(bgr);
for (t = 0; t < deg; t++) {
rect_x = ctr.x + rad * sinDeg(t) - w / 2;
rect_y = ctr.y - rad * cosDeg(t) - w / 2;
rect_r = new Rect(rect_x, rect_y, w, w);
canvas.fillEllipse(rect_r);
}
// attempt to draw info text
const canvTextRect = new Rect(
0,
100 - canvTextSize / 2,
canvSize,
canvTextSize
);
canvas.setTextAlignedCenter();
canvas.setTextColor(txtColor);
canvas.setFont(Font.boldSystemFont(canvTextSize));
// canvas.drawTextInRect(`${Math.floor(batteryLevel * 100)}`, canvTextRect);
canvas.drawTextInRect(text, canvTextRect);
return canvas.getImage()
}
function leapYear(year) {
return ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0);
}
// Month here is 1-indexed (January is 1, February is 2, etc). This is
// because we're using 0 as the day so that it returns the last day
// of the last month, so you have to add 1 to the month number
// so it returns the correct amount of days
function daysInMonth (month, year) {
return new Date(year, month, 0).getDate();
}
// Variables used by Scriptable.
// These must be at the very top of the file. Do not edit.
// icon-color: purple; icon-glyph: magic;
// Refactored
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(today.getFullYear())) ? 366 : 365;
let daysThisMonth = daysInMonth(thisMonth+1, thisYear)
const dateFormatter = new DateFormatter()
dateFormatter.dateFormat = "MMM"
const canvSize = 200;
const canvTextSize = 32;
const canvas = new DrawContext();
canvas.opaque = false;
const battCircleRemainColor = new Color('#799351'); //Battery remaining color
const battCircleDepletedColor = new Color('#d54062'); //Battery depleted color
const battCircleBGColor = new Color('#fff'); //Widget background color
const battCircleTextColor = new Color('#000'); //Widget text color (use same color as above to hide text)
const remainColor = new Color('#ccc')
const monthCircleColor = new Color('#ffa36c')
const dayCircleColor = new Color('#ebdc87')
const dayNCircleColor = new Color('#318fb5')
const canvWidth = 16; //Battery circle thickness
const canvRadius = 80; //Battery circle radius
canvas.size = new Size(canvSize, canvSize);
canvas.respectScreenScale = true;
const batteryLevel = Device.batteryLevel();
/*
BEGIN Widget Layout
*/
let widget = new ListWidget();
widget.setPadding(0,0,0,0);
stack1 = widget.addStack()
stack1.layoutHorizontally()
drawArc(
Math.floor(batteryLevel * 100 * 3.6),
battCircleRemainColor,
battCircleDepletedColor,
Math.floor(batteryLevel * 100).toString(),
battCircleTextColor
)
stack1.addImage(canvas.getImage())
drawArc(
Math.floor(((thisMonth+1)/12)*100 * 3.6),
monthCircleColor,
remainColor,
dateFormatter.string(today),
// (thisMonth + 1).toString(),
battCircleTextColor
)
stack1.addImage(canvas.getImage())
drawArc(
Math.floor((thisDayDate/daysThisMonth)*100 * 3.6),
dayCircleColor,
remainColor,
thisDayDate.toString(),
battCircleTextColor
)
stack1.addImage(canvas.getImage())
drawArc(
Math.floor(dayNumber/daysYear*100 * 3.6),
dayNCircleColor,
remainColor,
dayNumber.toString(),
battCircleTextColor
)
stack1.addImage(canvas.getImage())
const nobg = importModule('no-background.js')
widget.backgroundImage = await nobg.getSlice('medium-top')
Script.setWidget(widget);
widget.presentMedium();
Script.complete();
/*
END Widget Layout
*/
function sinDeg(deg) {
return Math.sin((deg * Math.PI) / 180);
}
function cosDeg(deg) {
return Math.cos((deg * Math.PI) / 180);
}
function drawArc(deg, fillColor, strokeColor, text, txtColor) {
let ctr = new Point(canvSize / 2, canvSize / 2),
bgx = ctr.x - canvRadius;
bgy = ctr.y - canvRadius;
bgd = 2 * canvRadius;
bgr = new Rect(bgx, bgy, bgd, bgd);
canvas.setFillColor(fillColor);
canvas.setStrokeColor(strokeColor);
canvas.setLineWidth(canvWidth);
canvas.strokeEllipse(bgr);
for (t = 0; t < deg; t++) {
rect_x = ctr.x + canvRadius * sinDeg(t) - canvWidth / 2;
rect_y = ctr.y - canvRadius * cosDeg(t) - canvWidth / 2;
rect_r = new Rect(rect_x, rect_y, canvWidth, canvWidth);
canvas.fillEllipse(rect_r);
}
// attempt to draw info text
const canvTextRect = new Rect(
0,
100 - canvTextSize / 2,
canvSize,
canvTextSize
);
canvas.setTextAlignedCenter();
canvas.setTextColor(txtColor);
canvas.setFont(Font.boldSystemFont(canvTextSize));
canvas.drawTextInRect(text, canvTextRect);
// return canvas.getImage()
}
function leapYear(year) {
return ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0);
}
// Month here is 1-indexed (January is 1, February is 2, etc). This is
// because we're using 0 as the day so that it returns the last day
// of the last month, so you have to add 1 to the month number
// so it returns the correct amount of days
function daysInMonth (month, year) {
return new Date(year, month, 0).getDate();
}
@brainno722
Copy link
Author

File (6)
File (5)

@brainno722
Copy link
Author

AKCFjDY
With text labels

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