Last active
February 2, 2021 22:26
-
-
Save stoptime/c5f21762bb8cbf75492b43e165b64532 to your computer and use it in GitHub Desktop.
JavaScript Generators and Spiral Matrices
This file contains hidden or 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
<!-- view here: https://bl.ocks.org/stoptime/raw/c5f21762bb8cbf75492b43e165b64532/ --> | |
<!doctype html> | |
<html> | |
<head> | |
<title>JavaScript Generators and Spiral Matrices</title> | |
<style type="text/css"> | |
body { | |
background-color: black; | |
color: white; | |
font-family: Helvetica, sans-serif; | |
} | |
h1 { | |
font-weight: normal; | |
font-size: 1.5rem; | |
} | |
.grid-container { | |
display: inline-grid; | |
grid-template-columns: auto auto auto; | |
background-color: purple; | |
padding: 5px; | |
grid-column-gap: 5px; | |
grid-row-gap: 5px; | |
width: 300px | |
} | |
.grid-item { | |
background-color: rgba(255, 255, 255, 0.8); | |
border: 1px solid rgba(0, 0, 0, 0.8); | |
padding: 12px 10px; | |
min-height: 20px; | |
min-width: 20px; | |
font-size: 15px; | |
text-align: center; | |
color: #333; | |
} | |
#form-container button { | |
margin-bottom: 1rem; | |
margin-left: .5rem | |
} | |
/* Desktop */ | |
@media only screen and (min-width: 1024px) { | |
.grid-container { | |
padding: 10px | |
} | |
.grid-item { | |
padding: 20px 10px; | |
min-height: 40px; | |
min-width: 40px; | |
font-size: 30px; | |
} | |
} | |
</style> | |
</head> | |
<body> | |
<h1>Fun with JavaScript Generators and Spiral Matrices</h1> | |
<div id="main"> | |
<div id="form-container"> | |
<label for="grid"># of rows/cols</label> | |
<select name="grid" id="grid-select"> | |
<option value="2">2</option> | |
<option value="3">3</option> | |
<option value="4" selected>4</option> | |
<option value="5">5</option> | |
<option value="6">6</option> | |
<option value="7">7</option> | |
<option value="8">8</option> | |
<option value="9">9</option> | |
<option value="10">10</option> | |
</select> | |
<button id="next" disabled>Gimme One</button> | |
<button id="finish" disabled>Finish It</button> | |
</div> <!-- close form container --> | |
<div class="grid-container" id="container"></div> | |
</div> <!-- close main --> | |
<script type="text/javascript"> | |
function* spiral(num) { | |
let rowStartIndex = 0 | |
let colStartIndex = 0 | |
let rowEndIndex = num - 1 | |
let colEndIndex = num - 1 | |
let counter = 1 | |
while (rowStartIndex <= rowEndIndex && colStartIndex <= colEndIndex) { | |
// make the top row | |
for (let i = colStartIndex; i <= rowEndIndex; i++) { | |
yield { 'row': rowStartIndex, 'col': i, 'counter': counter } | |
counter++ | |
} | |
rowStartIndex++ | |
// make the last col | |
for (let i = rowStartIndex; i <= rowEndIndex; i++) { | |
yield { 'col': colEndIndex, 'row': i, 'counter': counter } | |
counter++ | |
} | |
colEndIndex-- | |
// make the bottom row, in reverse | |
if (rowStartIndex <= rowEndIndex) { | |
for (let i = colEndIndex; i >= colStartIndex; i--) { | |
yield { 'row': rowEndIndex, 'col': i, 'counter': counter } | |
counter++ | |
} | |
rowEndIndex-- | |
} | |
if (colStartIndex <= colEndIndex) { | |
// make the 1st col, going up | |
for (let i = rowEndIndex; i >= rowStartIndex; i--) { | |
yield { 'col': colStartIndex, 'row': i, 'counter': counter } | |
counter++ | |
} | |
colStartIndex++ | |
} | |
} | |
} | |
function sizeGrid() { | |
const container = document.querySelector('#container') | |
let portMultiplier = 100 | |
if (Math.round(window.visualViewport.width) < 1023) portMultiplier = 50 | |
container.style.width = num * portMultiplier + 'px' | |
} | |
function makeGrid(num) { | |
const container = document.querySelector('#container') | |
// clear out any prev children | |
while (container.lastChild) container.removeChild(container.lastChild) | |
// size it | |
sizeGrid() | |
// some dynamic inline css to make our grid matrix | |
container.style.gridTemplateColumns = 'auto '.repeat(num).trim() | |
// now populate it | |
const total = num * num | |
for (let i = 0; i < num; i++) { | |
for (let item = -1; item < num - 1; item++) { | |
const el = document.createElement('div') | |
let col = item + 1 | |
el.classList.add('grid-item') | |
el.setAttribute('data-row', i) | |
el.setAttribute('data-col', col) | |
container.append(el) | |
} | |
} | |
document.querySelectorAll('button').forEach((b) => { | |
b.removeAttribute('disabled') | |
}) | |
} | |
function doNext(next, time = false) { | |
if (time) { | |
setTimeout(function () { | |
document.querySelector(`[data-row="${next.row}"][data-col="${next.col}"]`).innerText = next.counter | |
}, time) | |
} else { | |
document.querySelector(`[data-row="${next.row}"][data-col="${next.col}"]`).innerText = next.counter | |
} | |
} | |
// make the grid and our spiral generator | |
let num, spiralGen, next | |
const gridSelect = document.querySelector('#grid-select') | |
gridSelect.addEventListener('change', (event) => { | |
num = event.target.value | |
makeGrid(num) | |
spiralGen = spiral(num) | |
}) | |
document.querySelector('#next').addEventListener('click', (event) => { | |
next = spiralGen.next().value | |
doNext(next) | |
}) | |
document.querySelector('#finish').addEventListener('click', (event) => { | |
const time = 200 | |
let i = 1 | |
while (next = spiralGen.next().value) { | |
doNext(next, time * i) | |
i++ | |
} | |
}) | |
const container = document.querySelector('#container') | |
let boxes = document.querySelectorAll('.grid-item') | |
window.addEventListener('load', () => { | |
num = 4 | |
makeGrid(num) | |
spiralGen = spiral(num) | |
}) | |
window.addEventListener('resize', () => { | |
sizeGrid() | |
}) | |
</script> | |
</body> | |
<html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment