import * as layout from './layout.js'; import * as pattern from './pattern.js'; const sqrt3 = Math.sqrt(3); const sqrt32 = sqrt3 / 2; const size = 50; const hs = size / 2; const hh = sqrt32 * size; const hex2px = ([q, r]) => { const x = size * (3/2 * r); const y = -size * (sqrt32 * r + sqrt3 * q); return [x, y]; }; const px2hex = ([x, y]) => { const t1 = x / size; const t2 = -y / hh / 2; const q = Math.floor( (Math.floor(-y / hh) + Math.floor(t2 - t1) + 2 ) / 3); const r = Math.floor( (Math.floor(t1 - t2) + Math.floor(t1 + t2) + 2 ) / 3); return [q, r]; } const rotate = ([x, y], a) => { return [ Math.cos(a) * x + Math.sin(a) * y, -Math.sin(a) * x + Math.cos(a) * y, ]; }; const hexagon = (ctx) => { ctx.beginPath(); ctx.moveTo(-hs, hh); ctx.lineTo(hs, hh); ctx.lineTo(size, 0); ctx.lineTo(hs, -hh); ctx.lineTo(-hs, -hh); ctx.lineTo(-size, 0); ctx.closePath(); }; const main = document.querySelector('main'); const bg = document.getElementById('canvas-bg').getContext('2d'); const fg = document.getElementById('canvas-fg').getContext('2d'); let mousePos = [0, 0]; main.onmousemove = (e) => { mousePos = [e.clientX - main.clientWidth/2, e.clientY - main.clientHeight/2]; }; document.body.onkeydown = (e) => { switch (e.key) { case 'q': layout.turn(-1); break; case 'e': layout.turn(1); break; } }; let lastCanvasSize = 0; const updateForeground = (canvasSize) => { fg.strokeStyle = '#b9bdc1'; fg.strokeWidth = 1.5; fg.canvas.width = fg.canvas.width; fg.translate(canvasSize/2, canvasSize/2); const rad = Math.ceil(canvasSize / size / 3); for (let q = -rad; q <= rad; q++) { const rMin = Math.max(-rad, -q-rad); const rMax = Math.min(rad, rad-q); for (let r = rMin; r <= rMax; r++) { fg.save(); fg.translate(...hex2px([q, r])); hexagon(fg); fg.stroke(); fg.restore(); } } }; const draw = () => { const width = window.innerWidth; const height = window.innerHeight; const canvasSize = Math.sqrt(width*width + height*height); if (canvasSize !== lastCanvasSize) { bg.canvas.width = bg.canvas.height = canvasSize; fg.canvas.width = fg.canvas.height = canvasSize; lastCanvasSize = canvasSize; updateForeground(canvasSize); } bg.canvas.width = bg.canvas.width; layout.update(); bg.translate(canvasSize/2, canvasSize/2); bg.font = `${size*0.5}px sans-serif`; bg.textAlign = 'center'; bg.textBaseline = 'middle'; bg.strokeStyle = '#ff0000'; bg.strokeWidth = 5; const rot = layout.getRot(); const [qq, rr] = layout.getSteps(); const steps = pattern.getSteps(); const length = pattern.getLength(); const rad = Math.ceil(canvasSize / size / 3); for (let q = -rad; q <= rad; q++) { const rMin = Math.max(-rad, -q-rad); const rMax = Math.min(rad, rad-q); for (let r = rMin; r <= rMax; r++) { bg.save(); bg.translate(...hex2px([q, r])); const note = q*qq + r*rr; let step = note % length; step = (step + length) % length; if (steps.includes(note)) { bg.fillStyle = '#eeeeee'; hexagon(bg); bg.fill(); } bg.rotate(-rot); bg.fillStyle = '#303336'; bg.fillText(step, 0, 0); bg.restore(); } } // const mouse = px2hex(rotate(mousePos, rot)); // bg.arc(...hex2px(mouse), 10, 0, 2*Math.PI); document.body.style.setProperty('--global-rot', `${rot}rad`); requestAnimationFrame(draw); }; draw();