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

Divide Rectangle Into Smaller Rectangles

  1. const rand = num => ~~(Math.random() * num)
  2.  
  3. let rectNum = 2 + rand(10)
  4. let rectCount = 0
  5.  
  6. document.body.appendChild(document.createElement('div')).innerText =
  7.   'click anywhere to regenerate'
  8.  
  9. function reset() {
  10.   ;[...document.querySelectorAll('.rect')].forEach(rect => rect.remove())
  11.   rectNum = 2 + rand(10)
  12.   rectCount = 0
  13.   newRect(300, 300, 50, 50)
  14. }
  15. reset()
  16. onpointerup = reset
  17.  
  18. function newRect(w, h, xp, yp) {
  19.   const rect = document.body.appendChild(document.createElement('div'))
  20.  
  21.   rect.classList.add('rect')
  22.   rectCount++
  23.  
  24.   Object.assign(rect.style, {
  25.     position: 'absolute',
  26.     left: `${xp}px`,
  27.     top: `${yp}px`,
  28.     width: `${w}px`,
  29.     height: `${h}px`,
  30.     outline: `1px solid black`,
  31.   })
  32.  
  33.   const props = {
  34.     x: xp,
  35.     y: yp,
  36.     height: h,
  37.     width: w,
  38.     seed: rand(3),
  39.     divide() {
  40.       const div = 2 + rand(5 * Math.random() * Math.random())
  41.       if (rand(2) == rand(2)) {
  42.         const newHeight = this.height / div
  43.  
  44.         newRect(this.width, this.height - newHeight, this.x, this.y)
  45.         newRect(this.width, newHeight, this.x, this.y + this.height - newHeight)
  46.       } else {
  47.         const newWidth = w / div
  48.         newRect(this.width - newWidth, this.height, this.x, this.y)
  49.         newRect(newWidth, this.height, this.x + this.width - newWidth, this.y)
  50.       }
  51.       rect.remove()
  52.     },
  53.   }
  54.   window.requestAnimationFrame(() => {
  55.     if (rectCount < rectNum) {
  56.       props.divide()
  57.     } else {
  58.       console.log('DONE!')
  59.     }
  60.   })
  61. }

This snippet comes to mind from time to time – one easy way to divide a rectangle into smaller rectangles- I actually went back and looked it up as it was an answer to a student question from 2006. The original one was written in ActionScript 2. Have a look:

  1. var wormNum:Number = 123;
  2. var wormCount:Number = 0;
  3. newWorm(400, 400, 0, 0);
  4. this.onEnterFrame = function() {
  5. 	if (wormCount < wormNum) {
  6. 		for (var props:String in this) {
  7. 			if (this[props]._x != undefined) {
  8. 				this[props].divide();
  9. 			}
  10. 		}
  11. 	}
  12. };
  13. function newWorm(w, h, xp, yp) {
  14. 	var currWorm:MovieClip = this.createEmptyMovieClip("box"+wormCount, this.getNextHighestDepth());
  15. 	wormCount++;
  16. 	box(w, h, currWorm, random(0xFFFFFF));
  17. 	currWorm._x = xp;
  18. 	currWorm._y = yp;
  19. 	currWorm.seed = random(3);
  20. 	currWorm.divide = function() {
  21. 		var div = random(4)+(1+Math.random()*1);
  22. 		if (random(2) == random(2)) {
  23. 			// divide vertically
  24. 			var nh:Number = this._height/div;
  25. 			newWorm(this._width, this._height-nh, this._x, this._y);
  26. 			newWorm(this._width, nh, this._x, this._y+this._height-nh);
  27. 		} else {
  28. 			// divide horizonatlly
  29. 			var nw:Number = this._width/div;
  30. 			newWorm(this._width-nw, this._height, this._x, this._y);
  31. 			newWorm(nw, this._height, this._x+this._width-nw, this._y);
  32. 		}
  33. 		this.removeMovieClip();
  34. 	};
  35. }
  36. function box(w:Number, h:Number, mc:MovieClip, col:Number):Void {
  37. 	with (mc) {
  38. 		lineStyle(0, 0, 20);
  39. 		beginFill(col, 10);
  40. 		moveTo(0, 0);
  41. 		lineTo(w, 0);
  42. 		lineTo(w, h);
  43. 		lineTo(0, h);
  44. 		endFill();
  45. 	}
  46. }

Don’t remember why I called them worms instead of rectangles, some AS2 types floating around…

Pass a Class

  1. function callMethods(evt) {
  2.   const e = new evt
  3.   e.one()
  4.   e.two()
  5. }
  6.  
  7. callMethods(class {
  8.   one() {
  9.     console.log('one')
  10.   }
  11.  
  12.   two() {
  13.     console.log('two')
  14.   }
  15. })

This is so tempting for something I want to do… but too strange to use probably… maybe…

React Vanilla

  1. <style>*{ font-family: sans-serif; margin-bottoM: .5em;}</style>
  2.  
  3. <h3>TODO</h3>
  4. <ul id=todos></ul>
  5. <label>What needs to be done?<br>
  6.   <input id=todo onchange="newTodo()"/><br>
  7. </label>
  8. <button id=add onclick="newTodo()">Add #1</button>
  9.  
  10. <script>
  11.   let count = 1
  12.   function newTodo() {
  13.     if (todo.value.length > 0) {
  14.       todos.innerHTML += `<li>${todo.value}</li>`
  15.       todo.value = ''
  16.       add.innerText = `Add #${++count}`
  17.     }
  18.   }
  19. </script>

I don’t really like React… Don’t get me wrong, I don’t mind it and I even kind of like using it – there’s something fun about it… But it’s surprising to me that UI work is still so bulky… I think React and most other UI libraries are overly complex… Every now and then I do evil style vanilla js versions of the React homepage examples as a sort of rebellion 😀 This is the React version of the above snippet:

  1. class TodoApp extends React.Component {
  2.   constructor(props) {
  3.     super(props);
  4.     this.state = { items: [], text: '' };
  5.     this.handleChange = this.handleChange.bind(this);
  6.     this.handleSubmit = this.handleSubmit.bind(this);
  7.   }
  8.  
  9.   render() {
  10.     return (
  11.       <div>
  12.         <h3>TODO</h3>
  13.         <TodoList items={this.state.items} />
  14.         <form onSubmit={this.handleSubmit}>
  15.           <label htmlFor="new-todo">
  16.             What needs to be done?
  17.           </label>
  18.           <input
  19.             id="new-todo"
  20.             onChange={this.handleChange}
  21.             value={this.state.text}
  22.           />
  23.           <button>
  24.             Add #{this.state.items.length + 1}
  25.           </button>
  26.         </form>
  27.       </div>
  28.     );
  29.   }
  30.  
  31.   handleChange(e) {
  32.     this.setState({ text: e.target.value });
  33.   }
  34.  
  35.   handleSubmit(e) {
  36.     e.preventDefault();
  37.     if (this.state.text.length === 0) {
  38.       return;
  39.     }
  40.     const newItem = {
  41.       text: this.state.text,
  42.       id: Date.now()
  43.     };
  44.     this.setState(state => ({
  45.       items: state.items.concat(newItem),
  46.       text: ''
  47.     }));
  48.   }
  49. }
  50.  
  51. class TodoList extends React.Component {
  52.   render() {
  53.     return (
  54.       <ul>
  55.         {this.props.items.map(item => (
  56.           <li key={item.id}>{item.text}</li>
  57.         ))}
  58.       </ul>
  59.     );
  60.   }
  61. }
  62.  
  63. root.render(<TodoApp />);
// dom // globals // hacks // humor // ui

Interview with Senior JS Developer in 2022

This is extremely good.

Destructure in Every Function

  1. // read through the comments of this snippet...
  2.  
  3. function dist1(x1, y1, x2, y2) {
  4.   const dx = x1 - x2
  5.   const dy = y1 - y2
  6.   return Math.sqrt(dx**2 + dy**2)
  7. }
  8.  
  9. function dist2({x1, y1, x2, y2}) {
  10.   const dx = x1 - x2
  11.   const dy = y1 - y2
  12.   return Math.sqrt(dx**2 + dy**2)
  13. }
  14.  
  15. // What's the difference here... well
  16. dist1(50, 50, 100, 100)
  17.  
  18. // vs
  19.  
  20. dist2({ x1: 50, y1: 50, x2: 100, y2: 100 })
  21.  
  22. // so what?
  23.  
  24. // With `dist2` the order of the arguments doesn't matter
  25. // and the arguments are named now as a result of being keys
  26. // in an object
  27.  
  28. // How many times have you changed a core function or method as you're
  29. // working on a project?
  30.  
  31. // Let's see another example:
  32.  
  33. // circle(100, 200, 300, 'red', 'blue', 0, 0)
  34.  
  35. // Can you guess what those arguments are? It's not really a big deal
  36. // and editors help with this, typescript helps with this... but what about:
  37.  
  38. circle({ 
  39.   x: 10, 
  40.   y: 110, 
  41.   radius: 120, 
  42.   fill: 'red', 
  43.   stroke: 'blue', 
  44.   velocityX: 0, 
  45.   velocitY: 0
  46. })
  47.  
  48. // how about...
  49. circle({ radius: 50, fill: 'blue' })
  50.  
  51. // or...
  52. circle({ stroke: 'green', x: 40, velocityX: 1 })
  53.  
  54. // etc...
  55. circle({ 
  56.   radius: 50,
  57.   stroke: 'black', x: 200, 
  58.   fill: 'teal',
  59.   velocityY: 1, velocityX: -1 })
  60.  
  61. // In combination with default arguments we end up with a very easy pattern for functions/methods
  62. // with a complex argument signature. gsap (aka TweenLite/TweenMax) has used this pattern for many
  63. // years. I've seen similar things in many languages...
  64.  
  65. // How does the circle function look?
  66.  
  67. function circle({ 
  68.   x = 0, y = 0, 
  69.   radius = 30, 
  70.   fill = 'black', 
  71.   stroke = 'transparent', 
  72.   velocityX = 0, velocityY = 0}) {
  73.  
  74.   const diam = radius * 2;
  75.  
  76.   const circle = document.body.appendChild(
  77.     Object.assign(
  78.       document.createElement('div'), 
  79.       { style: `
  80.         position: absolute;
  81.         left: ${x}px;
  82.         top: ${y}px;
  83.         width: ${diam}px;
  84.         height: ${diam}px;
  85.         background: ${fill};
  86.         border: 3px solid ${stroke};
  87.         border-radius: 100%;
  88.       `
  89.       }
  90.     )
  91.   )
  92.   if (velocityX != 0 || velocityY != 0) {
  93.     setInterval(() => {
  94.       x += velocityX
  95.       y += velocityY
  96.       circle.style.left = `${x}px`
  97.       circle.style.top = `${y}px`
  98.     }, 16)
  99.   }
  100.   return circle
  101. }
  102.  
  103.  
  104. // here is a golfed distance function - for no reason
  105. d=(a,b,c,d,e=a-c,f=b-d)=>Math.sqrt(e*e+f*f)
  106. console.log(
  107.   dist1(0, 0, 140, 140) ===
  108.   d(0, 0, 140, 140)
  109. )
snippet.zone ~ 2021-24 /// {s/z}