toString hack
x=self+''
console.log(
x[8],x[9],x[6],' ',
x[3],x[1],x[2],' ',
x[10],x[4],x[8],' ',
x[5],x[1],x[11]
)
Hit the “Try it out” and open the console….
x=self+''
console.log(
x[8],x[9],x[6],' ',
x[3],x[1],x[2],' ',
x[10],x[4],x[8],' ',
x[5],x[1],x[11]
)Hit the “Try it out” and open the console….
const canvas = document.createElement('canvas');
const c = canvas.getContext('2d');
document.body.appendChild(canvas);
function draw() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
c.fillStyle = 'gray';
c.fillRect(0, 0, canvas.width, canvas.height);
c.strokeStyle = 'white';
c.lineWidth = 2;
c.beginPath();
c.moveTo(0, 0);
bezierSkin([10, 10, 210, 10, 10, 300, 210, 300], false);
bezierSkin([200, 10, 330, 10, 250, 300]);
bezierSkin(Array(30)
.fill(0)
.map((a, b) => (b % 2 == 0) * 300 + Math.random() * 300)
);
c.stroke();
}window.addEventListener('resize', draw);
draw();
// array of xy coords, closed booleanfunction bezierSkin(bez, closed = true) {
const avg = calcAvgs(bez);
const leng = bez.length;
let i, n;
if (closed) {
c.moveTo(avg[0], avg[1]);
for (i = 2; i < leng; i += 2) {
n = i + 1;
c.quadraticCurveTo(bez[i], bez[n], avg[i], avg[n]);
}c.quadraticCurveTo(bez[0], bez[1], avg[0], avg[1]);
} else {
c.moveTo(bez[0], bez[1]);
c.lineTo(avg[0], avg[1]);
for (i = 2; i < leng - 2; i += 2) {
n = i + 1;
c.quadraticCurveTo(bez[i], bez[n], avg[i], avg[n]);
}c.lineTo(bez[leng - 2], bez[leng - 1]);
}}// create anchor points by averaging the control pointsfunction 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);
} // closeavg.push((p[0] + p[leng - 2]) / 2);
avg.push((p[1] + p[leng - 1]) / 2);
return avg;
}Being able to draw smooth lines that connect arbitrary points is something that I find myself needing very frequently. This is a port of an old old snippet of mine that does just that. By averaging control points of a quadratic bezier curve we ensure that our resulting Bezier curves are always smooth.
It would be very cool if html5 canvas implemented the Catmull Rom Spline but it unfortunately does not. The wonderful Raphael library used to have support for it.
const oCan = (
d = document,
b = d.body,
canvas = b.appendChild(document.createElement('canvas')),
c = canvas.getContext('2d'),
props = [],
o = {},
docs = {},
cmds = [],
L, k, du, j, draw,id
) => {
;(onresize = () => {
canvas.width = innerWidth
canvas.height = innerHeight
if (draw) {
clearTimeout(id)
id = setTimeout(() => cmds.forEach(v => draw(v)), 500)
}})()
Object.assign(b.style, { margin: 0, height: '100%' })
// longer way: console.log(Object.getOwnPropertyNames(Object.getPrototypeOf(c)));for (let i in c) props.push(i)
// make alphabetical since object keys have // no orderprops.sort().map(i => {
L = i.match(/[A-Z]/)
k = i[0]
if (L) k += L[0]
du = 0
if (o[k]) {
j = 0
while (o[k]) k += i[++j]
}o[k] =
(typeof c[i])[0] == 'f'
? (...args) => c[i].apply(c, args)
: v => (c[i] = v)
docs[i] = k
})
console.log('docs:', JSON.stringify(docs, null, 2))
return (draw = (s, cmd, currFn, args = [], part, fn, num) => {
cmd = s.split(/\s+/)
cmds.push(s)
c.save()
for (let i = 0; i < cmd.length; i++) {
part = cmd[i]
fn = o[part]
if (fn && currFn != fn) {
currFn && currFn.apply(c, args)
currFn = fnargs = []
} else {
num = parseFloat(part)
args.push(!isNaN(num) ? num : part)
} }currFn && currFn.apply(c, args)
c.restore()
})
}const c = oCan()
// `font` & text not suppoted// make str a function so resize works?c(`fS #ccc
fR 0 0 400 ${innerHeight}
fS blue
fR 40 0 20 20
gCl difference
ro .25
fR 50 0 30 30
gCl source-overfS rgba(200,100,9)
fR 100 100 40 40
`)I’ve had this idea for a long time, never bothered doing it until now. I wrote it in a semi-golfed style for no reason… Anyway, this lets you write canvas code in a strange obfuscated syntax that looks like this:
c(`fS #ccc
fR 0 0 400 ${innerHeight}
fS blue
fR 40 0 20 20
gCl difference
ro .25
fR 50 0 30 30
gCl source-overfS rgba(200,100,9)
fR 100 100 40 40
`)This snippet logs out some JSON that shows all the method aliases for the canvas context.
const spec = {
get(o, key) {
return o[key] != null ?
o[key] : o[key] = (...args) => {
const el = document.createElement(key);
args.forEach(arg => {
if (typeof arg === 'string') {
const span = document.createElement('span');
span.innerHTML = arg;
el.appendChild(span);
} else if (typeof arg === 'object') {
if (arg.tagName != null) {
el.appendChild(arg);
} else {
for (let i in arg) {
el.setAttribute(i, arg[i]);
} } }});
return el;
}},
set(o, key, v) {
o[key] = v;
}}const dom = new Proxy({}, spec);
document.body.appendChild(
dom.div(
dom.button('cool'),
dom.h2('some text', { style: 'font-style: italic' }),
dom.br(),
dom.input({ placeholder: 'zevan' })
));
const { div, input, label } = dom;
document.body.appendChild(
div( label('Slider:',
{ for: 'slider',
style: 'padding:1em;display:block'
},
input({ id: 'slider', type: 'range' })
) ));
In this snippet a proxy is used that makes all html node tagNames valid methods. Each method can take strings and HTMLElements as arguments in any order to create a dom structure. This may look familiar to people who have looked a bit deeper into the inner workings of some of the popular UI libraries of the last decade.
const target = {}
let value = null;
Object.defineProperties(target, {
magic: {
get() {
console.log('- getter called::', value);
return value;
},
set(val) {
document.body.innerHTML += val + '<br>';
value = val;
} }});
target.magic = 'xyz';
target.magic = 'snippet';
target.magic = 'zone';
target.magic = '- last value';
console.log('getting', target.magic);
This snippet shows a way to add getters and setters to a specific key of an existing object. This is powerful for decorating configuration objects with special behaviors. This kind of thing can easily be created with a little more abstraction:
const image = view({
tag: 'img',
src: 'myImage.jpg',
x: '20%',
y: '20%',
size: '50%'
});
const prev = view({
tag: 'button',
x: () => image.x,
y: () => image.bottom
});
const next = view({
tag: 'button',
x: () => image.right - this.width,
y: () => image.bottom
});