Created
December 27, 2022 23:15
-
-
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.
This file contains 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
// 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