Skip to content

Instantly share code, notes, and snippets.

@drewkerr
Created December 27, 2022 23:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save drewkerr/fdb892d1f295a991eeb2501a49e1ed8d to your computer and use it in GitHub Desktop.
Save drewkerr/fdb892d1f295a991eeb2501a49e1ed8d to your computer and use it in GitHub Desktop.
Suggestion to add Bézier curves to Jason Snell’s weather station Scriptable widget.
// Variables used by Scriptable.
// These must be at the very top of the file. Do not edit.
// icon-color: deep-purple; icon-glyph: chart-line;
const data = [59, 56, 52, 58, 57, 57, 52, 53]
// [points] to img of smooth (bezier) line graph
function lineGraph(points, width, height, line) {
let context = new DrawContext()
context.size = new Size(width, height)
let max = Math.max(...points)
let min = Math.min(...points)
// calculate scale factors
let fx = width / (points.length - 1)
let fy = (height - line) / (max - min)
// scale points, allowing for line width
function scalePoint([x, y]) {
let sx = x * fx
let sy = (height - 2 * line) - (y - min) * fy
return new Point(sx, sy)
}
// calculate bezier control points
function controlPoint(current, previous, next, reverse) {
const smoothing = 0.2
const p = previous || current
const n = next || current
const dx = n[0] - p[0]
const dy = n[1] - p[1]
const angle = Math.atan2(dy, dx) + (reverse ? Math.PI : 0)
const length = Math.sqrt(Math.pow(dy, 2) + Math.pow(dy, 2)) * smoothing
const x = current[0] + Math.cos(angle) * length
const y = current[1] + Math.sin(angle) * length
return [x, y]
}
// create smooth path from points
let path = new Path()
points.map((p, i) => [i, p]).forEach((p, i, a) => {
if (i === 0) {
path.move(scalePoint(p))
} else {
let cps = controlPoint(a[i - 1], a[i - 2], p)
let cpe = controlPoint(p, a[i - 1], a[i + 1], true)
path.addCurve(scalePoint(p), scalePoint(cps), scalePoint(cpe))
}
})
context.addPath(path)
context.setLineWidth(line)
context.setStrokeColor(Color.black())
context.strokePath()
return context.getImage()
}
let widget = new ListWidget()
let image = lineGraph(data, 500, 50, 2)
widget.addImage(image)
widget.presentMedium()
Script.complete()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment