Skip to content
Spirographs in a doc
Share
Explore
Spirographs in a doc

icon picker
Pack code

Here is the exact Pack code that creates these :
// basic Pack import
import * as coda from "@codahq/packs-sdk";
export const pack = coda.newPack();

pack.addFormula({
name: "DrawSpirograph",
description: "Draw a dynamic spirograph.",
resultType: coda.ValueType.String,
codaType: coda.ValueHintType.ImageReference,
parameters: [
coda.makeParameter({ //largeRadius
type: coda.ParameterType.Number,
name: "largeRadius",
description: "Radius of the large circle",
optional: false,
}),
coda.makeParameter({ //smallRadius
type: coda.ParameterType.Number,
name: "smallRadius",
description: "Radius of the small circle.",
optional: false,
}),
coda.makeParameter({ //width of the canvas
type: coda.ParameterType.Number,
name: "width",
description: "Width of the canvas.",
optional: false,
}),
coda.makeParameter({ //height of the canvas
type: coda.ParameterType.Number,
name: "height",
description: "Height of the canvas.",
optional: false,
}),
coda.makeParameter({ //color1
type: coda.ParameterType.String,
name: "color1",
description: "enter a hex code color (with the #)",
optional: false,
}),
coda.makeParameter({ //color2
type: coda.ParameterType.String,
name: "color2",
description: "enter a hex code color (with the #)",
optional: false,
}),
],

execute: function ([largeRadius, smallRadius, width, height, color1, color2]) {


//create an array of objects with startX, startY, endX, endY
const coordinateArray = [];
const xStorage = [];
const yStorage = [];


let previousX = NaN;
let previousY = NaN;

//do the math for all angles
for (let i = 0; i <= 360; i++) {
let startX = width / 2;
let startY = width / 2;

//hypocycloid equation
let xcoord = (largeRadius - smallRadius) * Math.cos(i) + smallRadius * Math.cos((largeRadius / smallRadius - 1) * i);
let ycoord = (largeRadius - smallRadius) * Math.sin(i) - smallRadius * Math.sin((largeRadius / smallRadius - 1) * i);

if (i > 0) {
startX = previousX;
startY = previousY;
}

let endX = startX + xcoord;
let endY = startY + ycoord;

//change previousEnd values
previousX = endX;
previousY = endY;

//add a color for the line
let color = color1;

if (i > 90) {
color = color2;
}

coordinateArray.push({
x1: startX,
y1: startY,
x2: endX,
y2: endY,
color: color,
});

xStorage.push(startX, endX);
yStorage.push(startY, endY);
}

const origin = {
x: width / 2,
y: height / 2,
}

//get and store differences of max X and min X, max Y and min Y
let maxX = xStorage.reduce((a, b) => Math.max(a, b));
let minX = xStorage.reduce((a, b) => Math.min(a, b));
let maxY = yStorage.reduce((a, b) => Math.max(a, b));
let minY = yStorage.reduce((a, b) => Math.min(a, b));

let xDiff = (maxX - minX) / 2;
let yDiff = (maxY - minY) / 2;

let spiroCenter = {
x: minX + xDiff,
y: minY + yDiff,
}

let xFactor = spiroCenter.x - origin.x;
let yFactor = spiroCenter.y - origin.y;

//apply differences to every X and every Y
for (let i = 0; i < coordinateArray.length; i++) {
coordinateArray[i].x1 = coordinateArray[i].x1 - xFactor;
coordinateArray[i].x2 = coordinateArray[i].x2 - xFactor;
coordinateArray[i].y1 = coordinateArray[i].y1 - yFactor;
coordinateArray[i].y2 = coordinateArray[i].y2 - yFactor;
}

//parse to the SVG string
let svgArray = [];
for (let i = 0; i < coordinateArray.length; i++) {
let startX = coordinateArray[i].x1;
let startY = coordinateArray[i].y1;
let endX = coordinateArray[i].x2;
let endY = coordinateArray[i].y2;
let color = coordinateArray[i].color;
svgArray.push(`<line x1="${startX}" y1="${startY}" x2="${endX}" y2="${endY}" stroke="${color}" />`);
}

//combine to make the SVG
const svg = `<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="${width}" height="${height}">
${svgArray.join('')}
</svg>`;

return 'data:image/svg+xml,' + encodeURIComponent(svg);

},
});
Want to print your doc?
This is not the way.
Try clicking the ⋯ next to your doc name or using a keyboard shortcut (
CtrlP
) instead.