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

SVG getScreenCTM

  1. const el = document.body.appendChild(
  2.   document.createElement`div`
  3. );
  4. el.innerHTML = `
  5. <svg width="200" height="200" viewBox="0 0 200 200">
  6.   <rect 
  7.     class="rect"
  8.     transform="translate(50, 50) scale(1.2) rotate(25)"
  9.     fill="purple"
  10.     x="0" y="0" width="50" height="50" />
  11. </svg>
  12. `;
  13.  
  14. const box = document.body.appendChild(
  15.   document.createElement`div`
  16. );
  17.  
  18. Object.assign(box.style, {
  19.   position: 'absolute',
  20.   left: 0, top: 0,
  21.   width: '50px',
  22.   height: '50px',
  23.   transformOrigin: '0 0',
  24.   outline: '5px solid red'
  25. });
  26.  
  27. const rect = document.querySelector('.rect');
  28. const {a, b, c, d, e, f} = rect.getScreenCTM()
  29.  
  30. box.style.transform = `
  31.   matrix(${[a, b, c, d, e, f]})
  32. `;

The transformation matrix of an SVG element can be obtained using getScreenCTM or getCTM. The latter of which will be relative to the SVG coordinate space, vs the coordinate space of the page.

Here we take the matrix data from getScreenCTM and use it on a div to place a border over an SVG rect node. This is great for layering HTML on top of SVG.

// dom // javascript // math // matrix // svg // tricks // ui

Snippet Zone Code Highlighter

I wrote a naive syntax highlighter a few weeks ago. Here it is rendering the code for itself. :

This is not a perfect highlighter, but it was fun to create and I will definitely use it in the Snippet Zone Github repository once I get that set up.

There is some css that goes with the highlighter, it’s pretty boring, but here it is anyway:

  1. .hh {
  2.   white-space: pre-wrap;
  3.   font-family: monaco, monospace;
  4.   line-height: 1.5;
  5.   font-size: .8em;
  6.   background: rgb(3, 21, 36);
  7.   color: rgba(156, 221, 254, 1);
  8.   padding: 1em;
  9. }
  10.  
  11. .hh b {
  12.   font-weight: normal;
  13. }
  14.  
  15. .hh i {
  16.   color: #1ad6ae;
  17. }
  18.  
  19. .hh u {
  20.   color: rgb(255, 195, 252);
  21.   text-decoration: none;
  22. }
  23.  
  24. .num {
  25.   color: #b5cea8;
  26. }
  27.  
  28. .str, .str b  {
  29.   color: #ce9178;
  30. }
  31.  
  32. .par {
  33.   color: white;
  34.   font-weight: bold;
  35. }
  36.  
  37. .brk {
  38.   color: white;
  39.   font-weight: bold;
  40. }
  41.  
  42. .o {
  43.   color: rgb(0, 151, 221);
  44. }
  45.  
  46. .obj {
  47.   color: rgb(52, 206, 47);
  48.   font-weight: bold !important;
  49. }
  50.  
  51. .w {
  52.   color: #1ad6ae;
  53.   font-style: italic;
  54. }
  55.  
  56. .k {
  57.   color: aqua;
  58. }
  59.  
  60. .cmt {
  61.   color: gray !important;
  62. }
  63. .cmt b {
  64.   color: gray !important;
  65. }

I have no idea why I used such bad class names there 😛

// css // dom // javascript // meta // strings // ui

Complementary HSL

  1. const a = document.body.appendChild(document.createElement('div')),
  2.       b = document.body.appendChild(document.createElement('div'));
  3. let degA = degB = 0;
  4.  
  5. const size = {
  6.   width: '100px',
  7.   height: '100px'
  8. };
  9. Object.assign(a.style, size);
  10. Object.assign(b.style, size);
  11.  
  12. function loop() {
  13.   degA += 1;
  14.   degB = degA + 180;
  15.   a.style.background = `hsl(${degA}deg, 100%, 50%)`;
  16.   b.style.background = `hsl(${degB}deg, 100%, 50%)`;
  17.   requestAnimationFrame(loop);
  18. }
  19. loop();

In HSL a hue difference of 180 degrees between two values will create a set of complimentary colors.

// animation // color // css // dom // javascript // tricks // ui

Make a Grid

  1. const cellSize = 25;
  2. const cols = 10;
  3. const rows = 20;
  4.  
  5. function makeDot(x, y) {
  6.   const dot = document.body.appendChild(
  7.     document.createElement('div')
  8.   );
  9.  
  10.   dot.classList.add('cell');
  11.  
  12.   Object.assign(dot.style, {
  13.     position: 'absolute',
  14.     left: `${x}px`,
  15.     top: `${y}px`,
  16.     width: `${cellSize}px`,
  17.     height: `${cellSize}px`,
  18.     outline: '1px solid black',
  19.     cursor: 'pointer',
  20.     background: 'gray'
  21.   });
  22.  
  23.   return dot;
  24. }
  25.  
  26. for (let y = 0; y < rows; y++) {
  27.   for (let x = 0; x < cols; x++) {
  28.     makeDot(x * cellSize, y * cellSize);
  29.   }
  30. }
  31.  
  32. // make a cell red when it is rolled over
  33. document.addEventListener('mouseover', e => {
  34.   if (e.target.classList.contains('cell')) {
  35.     e.target.style.background = 'red';
  36.   }
  37. });

Here is a simple example for arranging divs in a grid.

// css // dom // javascript // math // tricks // ui

Proxy Quick DOM

  1. const spec = {
  2.   get(o, key) {
  3.     return o[key] != null ? 
  4.       o[key] : o[key] = (...args) => {
  5.         const el = document.createElement(key);
  6.         args.forEach(arg => { 
  7.           if (typeof arg === 'string') {
  8.             const span = document.createElement('span');
  9.             span.innerHTML = arg;
  10.             el.appendChild(span);
  11.           } else if (typeof arg === 'object') {
  12.             if (arg.tagName != null) {
  13.               el.appendChild(arg);
  14.             } else {
  15.               for (let i in arg) {
  16.                 el.setAttribute(i, arg[i]);
  17.               }
  18.             }
  19.           }
  20.         });
  21.         return el;
  22.       }
  23.   },
  24.   set(o, key, v) {
  25.     o[key] = v;
  26.   }
  27. }
  28.  
  29. const dom = new Proxy({}, spec);
  30.  
  31. document.body.appendChild(
  32.   dom.div(
  33.     dom.button('cool'), 
  34.     dom.h2('some text', { style: 'font-style: italic' }), 
  35.     dom.br(), 
  36.     dom.input({ placeholder: 'zevan' })
  37.   )
  38. );
  39.  
  40. const { div, input, label } = dom;
  41. document.body.appendChild(
  42.   div(
  43.     label(
  44.       'Slider:',
  45.       { 
  46.         for: 'slider', 
  47.         style: 'padding:1em;display:block' 
  48.       },
  49.       input({ id: 'slider', type: 'range' })
  50.     )
  51.   )
  52. );

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.

// dom // hacks // javascript // proxies // tricks // ui
snippet.zone ~ 2021-24 /// {s/z}