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

Mutation Observer

  1. // Select the node that will be observed for mutations
  2. const targetNode = document.getElementById('some-id');
  3.  
  4. // Options for the observer (which mutations to observe)
  5. const config = { attributes: true, childList: true, subtree: true };
  6.  
  7. // Callback function to execute when mutations are observed
  8. const callback = function(mutationsList, observer) {
  9.     // Use traditional 'for loops' for IE 11 (goodbye IE11!!!!)
  10.     for(const mutation of mutationsList) {
  11.         if (mutation.type === 'childList') {
  12.             console.log('A child node has been added or removed.');
  13.         }
  14.         else if (mutation.type === 'attributes') {
  15.             console.log('The ' + mutation.attributeName + ' attribute was modified.');
  16.         }
  17.     }
  18. };
  19.  
  20. // Create an observer instance linked to the callback function
  21. const observer = new MutationObserver(callback);
  22.  
  23. // Start observing the target node for configured mutations
  24. observer.observe(targetNode, config);
  25.  
  26. // Later, you can stop observing
  27. observer.disconnect();

This is pure gold if you haven’t used it… (from MDN)

// dom // events // graphics // html // javascript // ui

Decompose Matrix

  1. const deltaTransformPoint = (matrix, point) => {
  2.   return {
  3.     x: point.x * matrix.a + point.y * matrix.c,
  4.     y: point.x * matrix.b + point.y * matrix.d
  5.   }
  6. }
  7.  
  8. const decomposeMatrix = matrix => {
  9.   let px = deltaTransformPoint(matrix, { x: 0, y: 1 })
  10.   let py = deltaTransformPoint(matrix, { x: 1, y: 0 })
  11.   let skewX = FROM_RADS * Math.atan2(px.y, px.x) - 90
  12.   let skewY = FROM_RADS * Math.atan2(py.y, py.x)
  13.  
  14.   return {
  15.     tx: matrix.e,
  16.     ty: matrix.f,
  17.     scaleX: Math.sqrt(matrix.a * matrix.a + matrix.b * matrix.b),
  18.     scaleY: Math.sqrt(matrix.c * matrix.c + matrix.d * matrix.d),
  19.     skewX: skewX,
  20.     skewY: skewY,
  21.     rotation: skewX
  22.   }
  23. }

Get the scale, translation, rotationa and skew values from a matrix.

Great stackoverflow answer from user dave

// graphics // math // matrix

Random Color Strings Not-Golfed

  1. const { random, round } = Math
  2.  
  3. const TICK = 100
  4. const CHUNKS_PER_TICK = 4
  5. const minChunk = 3
  6. const maxChunk = 10
  7. const diffChunk = maxChunk - minChunk
  8.  
  9. const generateChance = .9 // 90% change of string generation
  10. const spaceChance = .8 // 80% chance of space
  11. const breakChance = .1 // 10% chance of line break
  12. const numbersChance = .9
  13.  
  14. const randomChunk = () => round(random() * 0xff).toString(36)
  15.   .replace(random() < numbersChance ? /[0-9]/g : '', '')
  16.  
  17. setInterval(() => {
  18.  
  19.   if (random() < generateChance) {
  20.  
  21.     Array(CHUNKS_PER_TICK).fill(0).forEach(() => { 
  22.  
  23.       const stringLeng = round(minChunk + random() * diffChunk)
  24.       let chunk = ''
  25.  
  26.       Array(stringLeng).fill(0)
  27.         .forEach(() => chunk += randomChunk())
  28.  
  29.       const span = document.createElement('span')
  30.       const hue = round(random() * 360)
  31.  
  32.       span.style.color = `hsl(${hue}, 30%, 50%)`
  33.       document.body.appendChild(span)
  34.       span.innerText = chunk
  35.  
  36.       if (random() < spaceChance) { 
  37.         document.body.appendChild(document.createTextNode(' '))
  38.       }
  39.  
  40.       if (random() < breakChance) {
  41.         const br = document.createElement('br')
  42.         document.body.appendChild(br)
  43.       }
  44.  
  45.     })
  46.   }
  47.  
  48.   scrollTo(0, document.body.scrollHeight)
  49. }, TICK)
  50.  
  51.  
  52. // just a lazy hack since snippet zone quick editor only supports js...
  53. // normally this goes in a separate file... :D
  54. document.body.innerHTML += `
  55. <style>
  56. body, html {
  57.   background: black;
  58.   font-family: Oswald, sans-serif;
  59.   overflow-wrap: break-word;
  60.   text-transform: uppercase;
  61.   letter-spacing: 1;
  62. }
  63.  
  64. br {
  65.   height: 1em;
  66.   display: block;
  67. }
  68. </style>
  69. `

An expansion on a snippet from a few days ago inspired by a friends codepen fork…

ES5 Canvas Thing

  1. var canvas = document.body.appendChild(
  2.   document.createElement('canvas')
  3. ),
  4. c = canvas.getContext("2d"),
  5. size = canvas.width,
  6. quarterSize = size / 4,
  7. eightSize = size / 8,
  8. halfSize = size / 2,
  9. TWO_PI = Math.PI * 2,
  10. bombNum = 3,
  11. bombs = [],
  12. wanderers = {}, 
  13. wandererIndex = 0,
  14. particles = {},
  15. particleIndex = 0;
  16.  
  17. canvas.width = canvas.height = 300
  18.  
  19. c.fillStyle = "rgb(100,100,100)";
  20. c.fillRect(0,0,size,size);
  21.  
  22. function Particle(x, y){
  23.   this.x = x;
  24.   this.y = y;
  25.   var rad = 3 + Math.random() * 6;
  26.   var theta = Math.random() * TWO_PI;
  27.   this.vx = rad * Math.cos(theta);
  28.   this.vy = rad * Math.sin(theta);
  29.   this.alpha = 1;
  30.   particleIndex++;
  31.   this.index = particleIndex;
  32.   particles[this.index] = this;
  33. }
  34. Particle.prototype.draw = function(){
  35.   this.x += this.vx;
  36.   this.y += this.vy;
  37.   this.vx *= 0.9;
  38.   this.vy *= 0.9;
  39.   this.alpha -= 0.05;
  40.  
  41.   if (this.alpha <= 0){
  42.     this.alpha = 0;
  43.     delete particles[this.index];
  44.  
  45.   }
  46.  
  47.   c.fillStyle = "rgba(255,255,255,"+this.alpha+")";
  48.   c.beginPath();
  49.   c.arc(this.x, this.y, 1, 0, TWO_PI, false);
  50.   c.fill();
  51. };
  52.  
  53. function Bomb(){
  54.   this.x = quarterSize + Math.random() * halfSize;
  55.   this.y = quarterSize + Math.random() * halfSize;
  56.   this.radius = 15 + Math.random() * 20;
  57. }
  58. Bomb.prototype.draw = function(){
  59.   c.fillStyle = "#e64c25";
  60.   c.beginPath();
  61.   c.arc(this.x, this.y, this.radius, 0, TWO_PI, false);
  62.   c.fill();
  63. };
  64.  
  65. function Wanderer(x, y){
  66.   this.x = x;
  67.   this.y = y;
  68.   this.vx = Math.random() * 4 - 2;
  69.   this.vy = Math.random() * 4 - 2;
  70.   particleIndex++;
  71.   this.index = particleIndex;
  72.   particles[this.index] = this;
  73. }
  74. Wanderer.prototype.die = function(){
  75.   for (var j = 0; j < 4; j++){
  76.     new Particle(this.x, this.y);
  77.   }
  78.  
  79.   delete particles[this.index];
  80. };
  81. Wanderer.prototype.draw = function(){
  82.   this.x += this.vx;
  83.   this.y += this.vy;
  84.  
  85.   if (Math.random() < 0.1){
  86.     this.vx = Math.random() * 4 - 2;
  87.     this.vy = Math.random() * 4 - 2;
  88.   }
  89.  
  90.   if (this.x < 0) this.x = size;
  91.   if (this.x > size) this.x = 0;
  92.   if (this.y < 0) this.y = size;
  93.   if (this.y > size) this.y = 0;
  94.  
  95.   c.fillStyle = "white";
  96.   c.beginPath();
  97.   c.arc(this.x, this.y, 2, 0, TWO_PI, false);
  98.   c.closePath();
  99.   c.fill();
  100.  
  101.   for (var i = 0; i < bombNum; i++){
  102.     var bomb = bombs[i];
  103.     var dx = this.x - bomb.x;
  104.     var dy = this.y - bomb.y;
  105.     if (Math.sqrt(dx * dx + dy * dy) < bomb.radius){
  106.       this.die();
  107.     }
  108.   }
  109. };
  110.  
  111. for (var i = 0; i < bombNum; i++){
  112.   bombs[i] = new Bomb();
  113. }
  114.  
  115. new Wanderer(eightSize, eightSize); 
  116.  
  117. setInterval(function(){
  118.   c.fillStyle = "rgba(100,100,100, 0.2)";
  119.   c.fillRect(0,0,size,size);
  120.   c.strokeStyle = "white";
  121.   c.beginPath();
  122.   c.arc(eightSize, eightSize, 5, 0, TWO_PI, false);
  123.   c.stroke();
  124.  
  125.   if (Math.random() < 0.02){
  126.     new Wanderer(eightSize, eightSize); 
  127.   }
  128.  
  129.   for (var i = 0; i < bombNum; i++){
  130.     bombs[i].draw();
  131.   }
  132.  
  133.   for (var i in wanderers){
  134.     wanderers[i].draw(); 
  135.   }
  136.  
  137.   for (var i in particles){
  138.     particles[i].draw();
  139.   }
  140. }, 16);

An old es5 speedcoded thing…

Cut Hole in Canvas (eraser)

  1. document.body.style.background = 'gray';
  2. const canvas = document.createElement('canvas');
  3. const c = canvas.getContext('2d');
  4.  
  5. canvas.width = 300;
  6. canvas.height = 300;
  7.  
  8. c.fillStyle='rgba(255, 0, 0, 0.8)'
  9. c.fillRect(0, 0, canvas.width, canvas.height);
  10.  
  11. c.globalCompositeOperation = 'destination-out';
  12. c.fillStyle = 'black';
  13. c.fillRect(100, 100, 150, 50);
  14.  
  15. document.body.appendChild(canvas);

destination-out is great for creating masks and eraser tools – things like that – in this case a 150×50 rectangle is cut out of a red background.

snippet.zone ~ 2021-24 /// {s/z}