Alphabet Array Golfed
l=[]
for(i=26;i--;)l[i]=(10+i).toString(36)
console.log(l)
A nasty golfed way to fill an array with letters a-z.
I usually do (as seen in another post):
let letters = 'abcdefghijklmopqrstuvwxyz'.split``
l=[]
for(i=26;i--;)l[i]=(10+i).toString(36)
console.log(l)
A nasty golfed way to fill an array with letters a-z.
I usually do (as seen in another post):
let letters = 'abcdefghijklmopqrstuvwxyz'.split``
document.addEventListener('touchmove', (e) => e.preventDefault(), {
passive: false,
});
// this is just lazy - obviously goes in your stylesheet.... :P
document.body.innerHTML += `
<style>
body, html {
padding: 0;
height: 100%;
margin: 0;
}
</style>
`;
const temp = document.createElement('div');
temp.innerHTML = `<svg width="100%" height="100%" viewBox="0 0 500 500"></svg>`;
const svg = document.body.appendChild(temp.querySelector('svg'));
const CIRCLE_NUM = 4;
// make some randomly positioned circles
for (let i = 0; i < CIRCLE_NUM; i++) {
const x = Math.random() * 150 + 150;
const y = Math.random() * 150 + 150;
svg.innerHTML += `<circle
cx="${x}" cy="${y}" r="60"
stroke="#000" fill="rgba(81, 121, 200, 0.3)"
style="cursor:pointer" />`;
}
function touch(e) {
const pt = svg.createSVGPoint();
pt.x = e.clientX;
pt.y = e.clientY;
return pt.matrixTransform(svg.getScreenCTM().inverse());
}
let down, ox, oy, curr;
document.addEventListener('pointerdown', (e) => {
down = true;
if (e.target.tagName === 'circle') {
curr = e.target;
const { x, y } = touch(e);
ox = curr.cx.baseVal.value - x;
oy = curr.cy.baseVal.value - y;
}
});
document.addEventListener('pointermove', (e) => {
if (down && curr) {
const { x, y } = touch(e);
curr.cx.baseVal.value = x + ox;
curr.cy.baseVal.value = y + oy;
}
});
document.addEventListener('pointerup', (e) => {
down = false;
curr = null;
});
Drag some svg circles on mobile and desktop…
d = document
b = d.body
b.style.margin = 0
with(Math) {
S = min(innerHeight * 2, innerWidth * 2)
hs = S / 2
with(
b.appendChild(Object.assign(
d.createElement`canvas`, {
width: S,
height: S
})).getContext`2d`) {
// array of xy coords, closed boolean
function bezierSkin(bez, closed = true) {
const avg = calcAvgs(bez);
const leng = bez.length;
let i, n;
if (closed) {
moveTo(avg[0], avg[1]);
for (i = 2; i < leng; i += 2) {
n = i + 1;
quadraticCurveTo(bez[i], bez[n], avg[i], avg[n]);
}
quadraticCurveTo(bez[0], bez[1], avg[0], avg[1]);
} else {
moveTo(bez[0], bez[1]);
lineTo(avg[0], avg[1]);
for (i = 2; i < leng - 2; i += 2) {
n = i + 1;
quadraticCurveTo(bez[i], bez[n], avg[i], avg[n]);
}
lineTo(bez[leng - 2], bez[leng - 1]);
}
}
// create anchor points by averaging the control points
function calcAvgs(p) {
const avg = [];
const leng = p.length;
let prev;
for (var i = 2; i < leng; i++) {
prev = i - 2;
avg.push((p[prev] + p[i]) / 2);
}
// close
avg.push((p[0] + p[leng - 2]) / 2);
avg.push((p[1] + p[leng - 1]) / 2);
return avg;
}
canvas.style.transformOrigin = '0 0'
canvas.style.transform = 'scale(.4)'
rinit = _ => {
t = 0
tinc = .1
rad = hs * .8
pupil = random() * .25
radA = pupil + random() * .25
}
dx = dy = hs
cx = cy = hs
rinit()
fillStyle = 'black'
fillRect(0, 0, S, S);
fillStyle = 'white'
beginPath()
moveTo(hs, hs)
arc(hs, hs, rad, 0, 7)
fill()
outer = _ => {
dx = cx + rad * cos(t)
dy = cy + rad * sin(t)
if (t > 7 && random() < .3) {
fnIdx++
}
}
shutter = () => hs * radA + random() * hs * (.6 - pupil)
innerA = _ => {
tinc = .05
rad = shutter()
dx = cx + rad * cos(t)
dy = cy + rad * sin(t)
if (t > 21 && random() < .3) {
fnIdx++
}
}
oa = 7 * 3
innerB = _ => {
tinc = .05
T = t * random();
dx = cx + hs * radA * cos(T)
dy = cy + hs * radA * sin(T)
if (t > 28 + oa && random() < .3) {
rad = hs * .8
fnIdx++
}
}
outerA = _ => {
R = (rad - hs * .1) + random() * hs * .1;
dx = cx + R * cos(t)
dy = cy + R * sin(t)
if (t > 35 + oa && random() < .3) {
fnIdx++
}
}
outerB = _ => {
tinc = .01;
R = rad
if (random() < .5) R = shutter()
dx = cx + R * cos(t)
dy = cy + R * sin(t)
if (t > 42 + oa && random() < .3) {
fnIdx++
ct = t
}
}
t2 = 0
outerC = _ => {
tinc = .1;
t2 += .01;
R = hs * .3
RR = (R + t2 + random() * 10);
dx = cx + R * .84 + RR * cos(t)
dy = cy - R * .84 + RR * sin(t)
if (t > 70 + oa && random() < .3) {
fnIdx++
}
}
outerD = _ => {
tinc = .1;
t2 += .01;
R = hs * .1
RR = (R + t2 + random() * 10);
dx = cx + hs * .3 + RR * cos(t)
dy = cy + R * .84 + RR * sin(t)
if (t > 91 + oa && random() < .3) {
fnIdx++
}
}
outerE = _ => {
tinc = .1;
rad -= random() * .1;
dx = cx + rad * cos(t)
dy = cy + rad * sin(t)
if (t > 112 + oa && random() < .3) {
fnIdx++
}
}
count = 0
last = _ => {
done = true;
fillStyle = 'black'
fillRect(0, 0, S, S);
fillStyle = 'white'
beginPath()
moveTo(hs, hs)
arc(hs, hs, hs * .8, 0, 7)
fill()
beginPath();
moveTo(0, 0);
bezierSkin(pnts, false)
stroke()
return
count++
if (count < 1) {
rinit()
setOff()
t = 0
fnIdx = 0
}
}
fns = [outer, innerA, innerB, outerA, outerB, outerC, outerD, outerE, last]
fnIdx = 0
outer()
drawX = dx
drawY = dy
pDrawX = 0
pDrawY = 0
strokeStyle = 'rgba(0, 0, 0, 0.8)'
lineWidth = 1;
tt = 0
ox = 0;
oy = 0;
setOff = _ => {
return
ox = S * 1.2 * random() - S / 2
oy = S * 1.2 * random() - S / 2
sl = .1 + random() * .9;
}
sl = 1
pnts = []
done = false
loop = _ => {
if (done) {
return;
}
shadowColor = 'rgba(155, 255, 255, .5)';
shadowBlur = 15;
save()
scale(1, 1)
lineWidth = 2;
for (i = 0; i < 20; i++) {
t += tinc / 2
fns[fnIdx]()
drawX += ((dx + ox) * sl - drawX) / 2;
drawY += ((dy + oy) * sl - drawY) / 2;
if (drawX != 0 && pDrawX) {
beginPath()
moveTo(pDrawX, pDrawY);
lineTo(drawX, drawY);
pnts.push(drawX, drawY);
stroke()
}
pDrawX = drawX
pDrawY = drawY
}
restore()
requestAnimationFrame(loop)
}
loop()
}
}
Another thing for #genuary2022… a single curve…
const { pow, PI } = Math;
// mostly unedited code from Raphaël
var ef = {
linear: function(n) {
return n;
},
'<': function(n) {
return pow(n, 1.7);
},
'>': function(n) {
return pow(n, 0.48);
},
'<>': function(n) {
var q = 0.48 - n / 1.04,
Q = Math.sqrt(0.1734 + q * q),
x = Q - q,
X = pow(abs(x), 1 / 3) * (x < 0 ? -1 : 1),
y = -Q - q,
Y = pow(abs(y), 1 / 3) * (y < 0 ? -1 : 1),
t = X + Y + 0.5;
return (1 - t) * 3 * t * t + t * t * t;
},
backIn: function(n) {
var s = 1.70158;
return n * n * ((s + 1) * n - s);
},
backOut: function(n) {
n = n - 1;
var s = 1.70158;
return n * n * ((s + 1) * n + s) + 1;
},
elastic: function(n) {
if (n == !!n) {
return n;
}
return pow(2, -10 * n) * Math.sin(((n - 0.075) * (2 * PI)) / 0.3) + 1;
},
bounce: function(n) {
var s = 7.5625,
p = 2.75,
l;
if (n < 1 / p) {
l = s * n * n;
} else {
if (n < 2 / p) {
n -= 1.5 / p;
l = s * n * n + 0.75;
} else {
if (n < 2.5 / p) {
n -= 2.25 / p;
l = s * n * n + 0.9375;
} else {
n -= 2.625 / p;
l = s * n * n + 0.984375;
}
}
}
return l;
}
};
ef.easeIn = ef['ease-in'] = ef['<'];
ef.easeOut = ef['ease-out'] = ef['>'];
ef.easeInOut = ef['ease-in-out'] = ef['<>'];
ef['back-in'] = ef.backIn;
ef['back-out'] = ef.backOut;
// create a dot
function dot(x, y, radius, color) {
const el = document.createElement('div');
const size = `${radius * 2}px`;
Object.assign(el.style, {
position: 'absolute',
left: `${x}px`,
top: `${y}px`,
width: size,
height: size,
transform: `translate(${-radius}px, ${-radius}px)`,
borderRadius: '50%',
background: color
});
el.classList.add('dot');
document.body.appendChild(el);
return el;
}
const elA = dot(0, 40, 30, 'red');
const elB = dot(0, 110, 30, 'blue');
const elC = dot(0, 160, 20, 'green');
// how to use the easing equations:
let t = 0;
let start = Date.now();
let time = 0;
let duration = 2; // 2 seconds
function loop() {
// frame based
elA.style.left = `${ef.elastic(t) * 50}%`;
t += 0.005;
// time based
if (time <= duration) {
time = (Date.now() - start) / 1000;
const param = time / duration;
elB.style.left = `${ef.elastic(param) * 50}%`;
// green bounce example
elC.style.left = `${ef.bounce(param) * 50}%`;
}
requestAnimationFrame(loop);
}
loop();
I realized it might not be obvious how to use Raphaël’s easing equations. So I speed coded this example.
If you’d like to learn more about this kind of thing gsap is a great place to start… it is amazing… I highly recommend browsing the source.
var ef = R.easing_formulas = {
linear: function (n) {
return n;
},
"<": function (n) {
return pow(n, 1.7);
},
">": function (n) {
return pow(n, .48);
},
"<>": function (n) {
var q = .48 - n / 1.04,
Q = math.sqrt(.1734 + q * q),
x = Q - q,
X = pow(abs(x), 1 / 3) * (x < 0 ? -1 : 1),
y = -Q - q,
Y = pow(abs(y), 1 / 3) * (y < 0 ? -1 : 1),
t = X + Y + .5;
return (1 - t) * 3 * t * t + t * t * t;
},
backIn: function (n) {
var s = 1.70158;
return n * n * ((s + 1) * n - s);
},
backOut: function (n) {
n = n - 1;
var s = 1.70158;
return n * n * ((s + 1) * n + s) + 1;
},
elastic: function (n) {
if (n == !!n) {
return n;
}
return pow(2, -10 * n) * math.sin((n - .075) * (2 * PI) / .3) + 1;
},
bounce: function (n) {
var s = 7.5625,
p = 2.75,
l;
if (n < (1 / p)) {
l = s * n * n;
} else {
if (n < (2 / p)) {
n -= (1.5 / p);
l = s * n * n + .75;
} else {
if (n < (2.5 / p)) {
n -= (2.25 / p);
l = s * n * n + .9375;
} else {
n -= (2.625 / p);
l = s * n * n + .984375;
}
}
}
return l;
}
};
ef.easeIn = ef["ease-in"] = ef["<"];
ef.easeOut = ef["ease-out"] = ef[">"];
ef.easeInOut = ef["ease-in-out"] = ef["<>"];
ef["back-in"] = ef.backIn;
ef["back-out"] = ef.backOut;
Another fun chunk of code directly from the Raphaël source. Makes me think of the Penner easing equations.