// some circles made of text
const cols = 50;
const rows = 50;
const sym = '.';
const body = document.body;
Object.assign(body.style, {
userSelect: 'none',
fontFamily: 'Courier, monospace',
position: 'fixed',
width: '100%',
height: '100%',
margin: 0
});
const el = body.appendChild(
document.createElement('span')
);
el.innerHTML = sym;
Object.assign(el.style, {
position: 'absolute',
left: '50%',
top: '50%',
wordWrap: 'break-word',
cursor: 'pointer'
});
const charSize = el.getBoundingClientRect().width;
const elWidth = charSize * cols;
el.style.display = 'block'
el.style.width = `${elWidth}px`;
const info = body.appendChild(
document.createElement('div')
);
Object.assign(info.style, {
background: '#fff',
padding: '4px',
position: 'absolute'
})
info.innerHTML = 'click/tap and hold for different fx';
function resize() {
const scl = Math.min(
1.23,
Math.min(innerWidth, innerHeight) / elWidth * .93
);
el.style.transform = `translate(-50%, -50%) scale(${scl}, ${scl * .55})`
}
addEventListener('resize', resize);
resize();
const size = cols * rows;
const pix = sym.repeat(size);
el.innerHTML = pix;
let cells = pix.split('')
const blank = cells.concat();
function setSym(x, y, col) {
const idx = x + y * cols;
if (cells[idx] != null) {
cells[idx] = col;
}
return setSym
}
const grad = '::;|0UU888NN';
function circ(shooter) {
let x = Math.round(Math.random() * cols);
let y = Math.round(Math.random() * rows);
const rad = Math.round(
shooter ? Math.random() * 2 :
Math.random() * Math.random() * 13 + 1
);
const sym = shooter ? '#' : grad.charAt(rad % grad.length);
let speed = rad / 10 + .1;
let dir = Math.random() * 2 - 1;
return () => {
drawCircle(x, y, rad, sym, shooter);
y += speed;
if (shooter) x += speed * 3 * dir;
if (y > rows + 10) y = -14;
}
}
const circs = [];
const NUM = 40;
for (let i = 0; i < NUM; i++) {
circs.push(circ(Math.random() > 0.5))
}
let down;
document.addEventListener('mousedown', () => {
down = true;
});
document.addEventListener('mouseup', () => {
down = false;
});
document.addEventListener('touchstart', () => {
down = true;
});
document.addEventListener('touchend', () => {
down = false;
});
let tweak;
let tweakChoice;
let tweakChance = 0.4;
const clear = () => cells = blank.concat();
function draw() {
if (!down) {
tweak = false;
tweakChoice = Math.random();
clear();
} else {
if (tweakChoice < tweakChance) {
tweak = true;
clear();
}
}
circs.forEach(circ => circ());
el.innerHTML = cells.join('');
}
// 60fps is too fast, so use 30ms interval
setInterval(draw, 30);
function hLine(xp, yp, w, col) {
for (let i = 0; i < w; i++) {
setSym(xp + i, yp, col);
}
return hLine;
}
// bresenham circle
function drawCircle(xp, yp, radius, sym = '@', isFilled) {
if (isFilled && tweak) sym = '';
xp = parseInt(xp, 10);
yp = parseInt(yp, 10);
radius = parseInt(radius, 10);
let balance = -radius,
xoff = 0,
yoff = radius;
while (xoff <= yoff) {
const p0 = xp - xoff;
const p1 = xp + xoff;
const p2 = yp + yoff;
const p3 = yp - yoff;
const p4 = yp + xoff;
const p5 = xp + yoff;
const p6 = xp - yoff;
const p7 = yp - xoff;
if (isFilled) {
const w0 = xoff + xoff;
const w1 = yoff + yoff;
hLine
(p0, yp + yoff, w0, sym)
(p0, yp - yoff, w0, sym)
(p6, yp + xoff, w1, sym)
(p6, yp - xoff, w1, sym);
} else {
setSym
(p1, p2, sym)
(p0, p2, sym)
(p0, p3, sym)
(p1, p3, sym)
(p5, p4, sym)
(p6, p4, sym)
(p6, p7, sym)
(p5, p7, sym);
}
// never been able to find the original
// source for the below condition
// more info here: https://actionsnippet.com/?p=492
if ((balance += xoff++ + xoff) >= 0) {
balance -= --yoff + yoff;
}
}
}