Knit Hilbert
hilbertPointsgridSizeupdatePatternordercellSizesubCellSizecanvasSizepointdrawPatternprimaryColorbgColorshowGridshowPathsubgridminYmaxYminXmaxXshowMarkersmarkerSpacingd2xydownloadPattern
let canvas;
let hilbertPoints = [];
let gridSize;
function setup() {
updatePattern();
}
function updatePattern() {
const order = parseInt(document.getElementById('order').value);
let cellSize = parseInt(document.getElementById('cellSize').value);
if (cellSize % 3 !== 0) {
cellSize = Math.floor(cellSize / 3) * 3;
document.getElementById('cellSize').value = cellSize;
}
const n = Math.pow(2, order);
gridSize = n;
const subCellSize = cellSize / 3;
const canvasSize = gridSize * cellSize;
if (canvas) {
canvas.remove();
}
canvas = createCanvas(canvasSize, canvasSize);
canvas.parent('canvas-container');
hilbertPoints = [];
for (let i = 0; i < n * n; i++) {
const point = d2xy(n, i);
hilbertPoints.push(point);
}
drawPattern();
}
function drawPattern() {
const primaryColor = document.getElementById('primaryColor').value;
const bgColor = document.getElementById('bgColor').value;
const cellSize = parseInt(document.getElementById('cellSize').value);
const subCellSize = cellSize / 3;
const showGrid = document.getElementById('showGrid').checked;
const showPath = document.getElementById('showPath').checked;
background(bgColor);
const subgrid = [];
for (let y = 0; y < gridSize * 3; y++) {
subgrid[y] = [];
for (let x = 0; x < gridSize * 3; x++) {
subgrid[y][x] = false;
}
}
for (let i = 0; i < hilbertPoints.length; i++) {
const x = hilbertPoints[i].x * 3 + 1;
const y = hilbertPoints[i].y * 3 + 1;
subgrid[y][x] = true;
}
for (let i = 0; i < hilbertPoints.length - 1; i++) {
const x1 = hilbertPoints[i].x * 3 + 1;
const y1 = hilbertPoints[i].y * 3 + 1;
const x2 = hilbertPoints[i+1].x * 3 + 1;
const y2 = hilbertPoints[i+1].y * 3 + 1;
if (x1 === x2) {
const minY = Math.min(y1, y2);
const maxY = Math.max(y1, y2);
for (let y = minY; y <= maxY; y++) {
subgrid[y][x1] = true;
}
} else if (y1 === y2) {
const minX = Math.min(x1, x2);
const maxX = Math.max(x1, x2);
for (let x = minX; x <= maxX; x++) {
subgrid[y1][x] = true;
}
}
}
noStroke();
fill(primaryColor);
for (let y = 0; y < gridSize * 3; y++) {
for (let x = 0; x < gridSize * 3; x++) {
if (subgrid[y][x]) {
rect(x * subCellSize, y * subCellSize, subCellSize, subCellSize);
}
}
}
if (showGrid) {
stroke(200);
strokeWeight(0.5);
for (let i = 0; i <= gridSize * 3; i++) {
line(0, i * subCellSize, width, i * subCellSize);
line(i * subCellSize, 0, i * subCellSize, height);
}
}
if (showPath) {
stroke(255, 0, 0, 150);
strokeWeight(1);
noFill();
beginShape();
for (let i = 0; i < hilbertPoints.length; i++) {
const x = hilbertPoints[i].x * cellSize + cellSize / 2;
const y = hilbertPoints[i].y * cellSize + cellSize / 2;
vertex(x, y);
}
endShape();
}
const showMarkers = document.getElementById('showMarkers').checked;
if (showMarkers) {
const markerSpacing = parseInt(document.getElementById('markerSpacing').value);
stroke(255, 0, 0);
strokeWeight(2);
for (let i = 0; i <= gridSize; i += markerSpacing) {
line(0, i * cellSize, width, i * cellSize);
line(i * cellSize, 0, i * cellSize, height);
}
stroke(0);
strokeWeight(1.5);
for (let i = 0; i <= gridSize; i++) {
if (i % markerSpacing !== 0) {
line(0, i * cellSize, width, i * cellSize);
line(i * cellSize, 0, i * cellSize, height);
}
}
}
}
function d2xy(n, d) {
let x = 0, y = 0;
let t = d;
for (let s = 1; s < n; s *= 2) {
const rx = 1 & (t / 2);
const ry = 1 & (t ^ rx);
if (ry === 0) {
if (rx === 1) {
x = s - 1 - x;
y = s - 1 - y;
}
const temp = x;
x = y;
y = temp;
}
x += s * rx;
y += s * ry;
t = Math.floor(t / 4);
}
return { x, y };
}
function downloadPattern() {
saveCanvas('hilbert_knitting_pattern', 'png');
}