)
}
}
)
(
}
{
)
)
(
)
(
(
{
}
)
(
)
}
)
)
{
(
(
)
)
}
)
(
}

Bring Node to Top

  1. myEl.parentNode.appendChild(myEl);

This will make an element the top most of all of its siblings…

  1. document.body.innerHTML += `
  2. <div>
  3.   <button>one</button>
  4.   <button>two</button>
  5.   <button>three</button>
  6.   <button>four</button>
  7. </div>
  8. <style>
  9.   button { display: block; cursor: pointer; }
  10. </style>
  11. `;
  12. document.addEventListener('click', e => {
  13.   if (e.target.tagName === 'BUTTON') {
  14.     e.target.parentNode.appendChild(e.target);
  15.   }
  16. });

Clicking on any button will bring it to the top most position within its parent.

// dom // javascript // tricks // ui

Letter Particles With Keyboard

  1. const Key = {
  2.   LEFT: 37,
  3.   UP: 38,
  4.   RIGHT: 39,
  5.   DOWN: 40,
  6.   disabled: false
  7. };
  8.  
  9. const keyDown = {};
  10.  
  11. function setupKeys() {
  12.   const alph = 'abcdefghijklmnopqrstuvwxyz'.split('');
  13.   const keys = {};
  14.   const aKey = 65;
  15.   alph.forEach((letter, i) => {
  16.     const idx = aKey + i;
  17.     keyDown[idx] = false;
  18.     Key[letter.toUpperCase()] = idx;
  19.   });
  20.  
  21.   keyDown.allLetters = () => {
  22.     const lettersDown = alph.filter(
  23.       letter => keyDown[Key[letter.toUpperCase()]]
  24.     );
  25.     return lettersDown;
  26.   };
  27.  
  28.   document.addEventListener('keydown', e => {
  29.     e.preventDefault();
  30.     if (!Key.disabled) {
  31.       keyDown[e.which] = true;
  32.     }
  33.   });
  34.  
  35.   document.addEventListener('keyup', e => {
  36.     e.preventDefault();
  37.     keyDown[e.which] = false;
  38.   });
  39. }
  40.  
  41. setupKeys();
  42.  
  43. // later:
  44.  
  45. const dots = {};
  46. let id = 0;
  47. function dot(letter = '') {
  48.   const el = document.createElement('div');
  49.   el.innerHTML = letter;
  50.   const size = 20;
  51.   const scale = 1 + Math.random() * 2;
  52.   const vel = (2 - scale / 2) / 4;
  53.   let x = innerWidth / 2 - size;
  54.   let y = innerHeight / 2 - size;
  55.   let vx = Math.random() * 6 - 3;
  56.   let vy = Math.random() * 6 - 3;
  57.   let life = 0;
  58.   let maxLife = Math.floor(50 + Math.random() * 30);
  59.   Object.assign(el.style, {
  60.     position: 'absolute',
  61.     left: 0,
  62.     top: 0,
  63.     transform: `translate3d(${x}px, ${y}px)`,
  64.     borderRadius: '500px',
  65.     background: 'red',
  66.     width: `${size}px`,
  67.     fontFamily: 'sans-serif',
  68.     textAlign: 'center',
  69.     color: 'white'
  70.   });
  71.  
  72.   id++;
  73.  
  74.   let props = {
  75.     el,
  76.     id,
  77.     right() {
  78.       vx += vel;
  79.     },
  80.     left() {
  81.       vx -= vel;
  82.     },
  83.     down() {
  84.       vy += vel;
  85.     },
  86.     up() {
  87.       vy -= vel;
  88.     },
  89.     run() {
  90.       life++;
  91.       if (life === maxLife) {
  92.         document.body.removeChild(dots[props.id].el);
  93.         delete dots[props.id];
  94.       }
  95.       x += vx;
  96.       y += vy;
  97.       vx *= 0.999;
  98.       vy *= 0.999;
  99.       el.style.transform = `translate(${x}px, ${y}px) scale(${scale}) `;
  100.     }
  101.   };
  102.   dots[id] = props;
  103.   document.body.appendChild(el);
  104. }
  105.  
  106. function loop() {
  107.   keyDown.allLetters().forEach(letter => {
  108.     dot(letter);
  109.   });
  110.  
  111.   for (let i in dots) {
  112.     dots[i].run();
  113.   }
  114.  
  115.   if (keyDown[Key.LEFT]) {
  116.     for (let i in dots) {
  117.       dots[i].left();
  118.     }
  119.   }
  120.  
  121.   if (keyDown[Key.DOWN]) {
  122.     for (let i in dots) {
  123.       dots[i].down();
  124.     }
  125.   }
  126.  
  127.   if (keyDown[Key.RIGHT]) {
  128.     for (let i in dots) {
  129.       dots[i].right();
  130.     }
  131.   }
  132.  
  133.   if (keyDown[Key.UP]) {
  134.     for (let i in dots) {
  135.       dots[i].up();
  136.     }
  137.   }
  138.  
  139.   requestAnimationFrame(loop);
  140. }
  141. loop();
  142.  
  143. const info = document.createElement('div')
  144. info.innerHTML = 'click here, then type letters and use arrow keys'
  145. document.body.appendChild(info)

A demo showing how to use the keyboard snippet from yesterday. Also added a function to obtain an array of all currently pressed letter keys

// animation // javascript // keys // math // random // tricks // ui

Easy Keyboard Controls JavaScript

  1. const Key = {
  2.   LEFT: 37,
  3.   UP: 38,
  4.   RIGHT: 39,
  5.   DOWN: 40,
  6.   disabled: false
  7. }
  8.  
  9. const keyDown = {}
  10.  
  11. function setupKeys() {
  12.   const alph = 'abcdefghijklmnopqrstuvwxyz'.split('')
  13.   const keys = {}
  14.   const aKey = 65
  15.   alph.forEach((letter, i) => {
  16.     const idx = aKey + i
  17.     keyDown[idx] = false
  18.     Key[letter.toUpperCase()] = idx
  19.   })
  20.  
  21.   document.addEventListener('keydown', e => {
  22.     if (!Key.disabled) {
  23.       keyDown[e.which] = true
  24.     }
  25.   })
  26.  
  27.   document.addEventListener('keyup', e => {
  28.     keyDown[e.which] = false
  29.   })
  30. }
  31.  
  32. setupKeys()
  33.  
  34. // later:
  35.  
  36. function loop() {
  37.   if (keyDown[Key.LEFT]) {
  38.     console.log('left')
  39.   }
  40.   if (keyDown[Key.UP]) {
  41.     console.log('up')
  42.   }
  43.   if (keyDown[Key.C] || keyDown[Key.D]) {
  44.     console.log('c or d key')
  45.   }
  46.   requestAnimationFrame(loop)
  47. }
  48. loop()
  49.  
  50. const info = document.createElement('div')
  51. info.innerHTML = 'click to give focus - then use C, D or LEFT keys.'
  52. document.body.appendChild(info)

Use a desktop and go into fullscreen when using the quick editor to see this in action…

This is a good way to deal with more complex key controls. event.which and event.key often won’t cut it, especially with key combos and different systems.

// javascript // keys // tricks // ui

Interesting Color Picker

  1. document.addEventListener('touchmove', e => e.preventDefault(), {
  2.   passive: false
  3. });
  4.  
  5. document.body.innerHTML += `
  6. <style>
  7.   * {
  8.     -moz-user-select: none;
  9.     -webkit-user-select: none;
  10.     -ms-user-select: none;
  11.     user-select: none;
  12.   }
  13.   body {
  14.     background: #333;
  15.   }
  16.   .select-box {
  17.     border: 1px solid white;
  18.     outline: 1px solid black;
  19.   }
  20.   .swatch {
  21.     border: none;
  22.     outline: none;
  23.   }
  24. </style>
  25. `;
  26.  
  27. const col = document.body.appendChild(document.createElement('div'));
  28. Object.assign(col.style, {
  29.   position: 'absolute',
  30.   left: 0,
  31.   top: 0,
  32.   width: '100%',
  33.   height: '200px',
  34.   background:
  35.     `linear-gradient(0, black 0%, transparent 50%, transparent 50%, white 100%), 
  36.      linear-gradient(90deg, #ff0000, #ffff00, #00ff00, #00ffff, #0000ff, #ff00ff, #ff0000)`
  37. });
  38.  
  39. const swatches = document.body.appendChild(document.createElement('div'));
  40. Object.assign(swatches.style, {
  41.   position: 'absolute',
  42.   top: '200px',
  43.   left: 0,
  44.   width: '100%'
  45. });
  46.  
  47. function box(x, y, cls = 'select-box', parent = document.body) {
  48.   const box = parent.appendChild(document.createElement`div`);
  49.   box.classList.add(cls);
  50.   Object.assign(box.style, {
  51.     position: 'absolute',
  52.     left: `${x}%`,
  53.     top: `${y}px`,
  54.     width: '40px',
  55.     height: '40px',
  56.     background: 'none',
  57.     transform: 'translate(-50%, -50%)',
  58.     cursor: 'pointer',
  59.  
  60.     color: 'white'
  61.   });
  62.   return box;
  63. }
  64.  
  65. function touch(e) {
  66.   let x = e.clientX;
  67.   let y = e.clientY;
  68.   if (e.touches != null && e.touches.length > 0) {
  69.     x = e.touches[0].clientX;
  70.     y = e.touches[0].clientY;
  71.   }
  72.   return { x, y };
  73. }
  74.  
  75. document.addEventListener('touchstart', onDown);
  76. document.addEventListener('touchmove', onMove);
  77. document.addEventListener('touchend', onUp);
  78. document.addEventListener('mousedown', onDown);
  79. document.addEventListener('mousemove', onMove);
  80. document.addEventListener('mouseup', onUp);
  81.  
  82. let down = false;
  83. let currBox;
  84. let currSwatch;
  85. let swatchHeight = 30;
  86. let id = 0;
  87.  
  88. function toHSL(x, y) {
  89.   let deg = x * 360;
  90.   return `hsl(${deg}deg, 100%, ${100 - y / 2}%)`;
  91. }
  92.  
  93. function onDown(e) {
  94.   let { x, y } = touch(e);
  95.   down = true;
  96.   let hPercent = x / innerWidth;
  97.   let color = toHSL(hPercent, y);
  98.   if (e.target.classList.contains('swatch')) {
  99.     e.target.style.outline = '2px solid red';
  100.     e.target.style.zIndex = 999;
  101.     down = false;
  102.     setTimeout(() => {
  103.       if (confirm('Would you like to remove this swatch?')) {
  104.         currBox = document.querySelector(
  105.           `.select-box[data-id="${e.target.dataset.id}"]`
  106.         );
  107.  
  108.         if (currBox != null) {
  109.           currBox.parentNode.removeChild(currBox);
  110.           e.target.parentNode.removeChild(e.target);
  111.         }
  112.       } else {
  113.         e.target.style.outline = null;
  114.         e.target.style.zIndex = null;
  115.       }
  116.     }, 250);
  117.   } else if (e.target.classList.contains('select-box')) {
  118.     currBox = e.target;
  119.     c = document.querySelector(`.swatch[data-id="${currBox.dataset.id}"]`);
  120.   } else {
  121.     currBox = box(hPercent * 100, y);
  122.     currBox.dataset.id = id++;
  123.     currSwatch = box(0, 0, 'swatch', swatches);
  124.     currSwatch.dataset.id = currBox.dataset.id;
  125.     Object.assign(currSwatch.style, {
  126.       width: '100%',
  127.       position: 'relative',
  128.       height: `${swatchHeight}px`,
  129.       transform: 'none',
  130.       background: color
  131.     });
  132.   }
  133. }
  134.  
  135. function onMove(e) {
  136.   if (down) {
  137.     let { x, y } = touch(e);
  138.     let hPercent = x / innerWidth;
  139.     let color = toHSL(hPercent, y);
  140.     Object.assign(currBox.style, {
  141.       left: `${hPercent * 100}%`,
  142.       top: `${y}px`
  143.     });
  144.     currSwatch.style.background = color;
  145.   }
  146. }
  147.  
  148. function onUp(e) {
  149.   down = false;
  150.   currBox = null;
  151. }

Click anywhere on the spectrum to add a color… color boxes can be dragged, color swatches can be deleted by clicking on them…

Just something that popped into my head awhile back so figured I’d do a speed-coded prototype. I’d like to revisit this and add more to it.

Speed Coded HTML Templating Thoughts

  1. const tmpl = `
  2.   main
  3.     h1 Welcome
  4.     hr
  5.     nav
  6.       button one
  7.       button two
  8.       button three
  9.     hr
  10.     p this is a test
  11.     p this is another test
  12.     textarea hello
  13.     ul 
  14.       li alpha
  15.       li beta
  16.       li zeta
  17.         ul 
  18.           li organize
  19.           li things
  20.       li and stuff
  21.   hr
  22.   footer 2022
  23. `
  24.  
  25. let htm = parse(tmpl);
  26. document.body.innerHTML += htm
  27. console.log(htm)
  28.  
  29. function isTag(tag) { 
  30.   return !/Unknown/.test(document.createElement(tag) + '')
  31. }
  32.  
  33. function parse(input) {
  34.   let lines = input.split(/\n/)
  35.   let html = []
  36.   let closeTags = []
  37.   let lastIndent = 0;
  38.  
  39.   for (let i = 1; i < lines.length; i++) {
  40.     let indent = 0;
  41.     let tag = '';
  42.     let content = ''
  43.     let line = lines[i]
  44.     let mode = 'start';
  45.  
  46.     for (let j = 0; j < line.length; j++) {
  47.       const char = line[j]
  48.       if (char == ' ' && mode === 'start') {
  49.         indent++;
  50.       } else if (char != ' ' && mode != 'content') {
  51.         mode = 'tag'
  52.         tag += char
  53.       } else {
  54.         mode = 'content'
  55.         content += char;
  56.       }
  57.     }
  58.  
  59.     if (indent <= lastIndent && closeTags.length > 0) {
  60.         let back = lastIndent
  61.         while(back >= indent) {
  62.           html.push(closeTags.pop())
  63.           back -= 2
  64.         }
  65.     }
  66.  
  67.     if (tag.length > 0) { 
  68.       let xtra = ''
  69.       let origTag = tag; 
  70.  
  71.       if (!isTag(tag)) {
  72.         tag = 'div'
  73.         xtra = ` class="${origTag}" `
  74.       }
  75.       closeTags.push(`</${tag}>`)
  76.       html.push(`<${tag + xtra}>`)
  77.       if (content.length > 0) html.push(content)
  78.     }
  79.  
  80.     lastIndent = indent;
  81.   }
  82.  
  83.   return [...html, ...closeTags.reverse()].join('')
  84. }

Parse a minimalistic html template inspired by the likes of jade, haml, pug etc… This is very speed-coded. I may revisit the same thing with a bit more of an elegant approach in the future.

// html // javascript // strings // ui
snippet.zone ~ 2021-24 /// {s/z}