Sacks Spiral

by Chris Ball

HTML

<svg version="1.1" width="500" height="500" xmlns="http://www.w3.org/2000/svg" id="canvas"></svg>

JavaScript

function numbersUntil(limit, start = 1) {
	return Array.from({length: limit}, (_, i) => i + start)
}

function isSquare(n) {
	return n > 0 && Math.sqrt(n) % 1 === 0
}

const isPrime = num => {
	for (let i = 2, s = Math.sqrt(num); i <= s; i++) {
		if (num % i === 0) return false
	}
	return num > 1
}

function appendSVGChild(elementType, target, attributes = {}, text = '') {
	const element = document.createElementNS('http://www.w3.org/2000/svg', elementType)
	Object.entries(attributes).map(a => element.setAttribute(a[0],a[1]))

	if (text) {
		const textNode = document.createTextNode(text)
		element.appendChild(textNode)
	}

	target.appendChild(element)

	return element
}

const canvas = document.getElementById('canvas')
const centre = {
	x: canvas.getBoundingClientRect().width / 2,
	y: canvas.getBoundingClientRect().height / 2
}
const growthFactor = 1.05

function generateSacksSpiral(numbers) {
	for (let i = 1; i <= numbers.length; i++) {
		const R = Math.sqrt(i)
		let theta = R * 2 * Math.PI
		let x = R * Math.cos(theta) + centre.x
		let y = R * Math.sin(theta) + centre.y
		let r = isPrime(i) ? 1 : 0.3

		appendSVGChild('circle', canvas, {
			cx: x,
			cy: y,
			r: r
		})
	}
}

generateSacksSpiral(numbersUntil(5000))