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

Faster than save/restore HTML5 canvas

  1. const canvas = document.createElement('canvas')
  2. const c = canvas.getContext('2d')
  3.  
  4. canvas.width = innerWidth
  5. canvas.height = innerHeight
  6.  
  7. document.body.append(canvas)
  8.  
  9. c.fillStyle = 'black'
  10. c.fillRect(0, 0, canvas.width, canvas.height)
  11.  
  12. class Shooter {
  13.   constructor() {
  14.     this.x = innerWidth / 2
  15.     this.y = innerHeight / 2
  16.     this.vx = Math.random() * 10 - 5
  17.     this.vy = Math.random() * 10 - 5
  18.     this.color = 'rgba(255, 0, 0, 0.5)'
  19.     this.size = 10
  20.     this.halfSize = this.size / 2
  21.   }
  22.   draw() {
  23.     this.x += this.vx
  24.     this.y += this.vy
  25.  
  26.     if (this.x < 0) {
  27.       this.x = innerWidth
  28.     } else if (this.x > innerWidth) {
  29.       this.x = 0
  30.     }
  31.  
  32.     if (this.y < 0) {
  33.       this.y = innerHeight
  34.     } else if (this.y > innerHeight) {
  35.       this.y = 0
  36.     }
  37.  
  38.     c.fillStyle = this.color
  39.     c.translate(this.x, this.y)
  40.     c.fillRect(-this.halfSize, -this.halfSize, this.size, this.size)
  41.  
  42.     c.setTransform(1, 0, 0, 1, 0, 0)
  43.   }
  44. }
  45.  
  46. const NUM = 1000
  47. const shooters = []
  48. for (let i = 0; i < NUM; i++) {
  49.   shooters.push(new Shooter())
  50. }
  51.  
  52. function loop() {
  53.   c.fillStyle = 'rgba(0, 0, 0, 0.1)'
  54.   c.fillRect(0, 0, innerWidth, innerHeight)
  55.  
  56.   for (let i = 0; i < NUM; i++) {
  57.     shooters[i].draw()
  58.   }
  59.   requestAnimationFrame(loop)
  60. }
  61. loop()

Using setTransform(1, 0, 0, 1, 0, 0) is faster than using save and restore. If you don’t need to save context info like fills, line styles etc… consider this method.

Validate Anagram

  1. function normalizeString(word) {
  2.   word = word.toLowerCase()
  3.   const result = normalizeString.memo[word]
  4.   if (result) return result
  5.   return normalizeString.memo[word] =
  6.     [...word.replace(/\s/g, '')]
  7.       .sort() + ''
  8. }
  9. normalizeString.memo = {}
  10.  
  11. const checkAnagram = (word, source) =>
  12.   normalizeString(word) === normalizeString(source)
  13.  
  14.  
  15. // try it out 
  16.  
  17. const target = 'adorn hair'
  18. const anagrams = [
  19.   'hoard rain',
  20.   'hair radon',
  21.   'hadron air',
  22.   'hairdo ran',
  23.   'radian rho',
  24.   'au revoir fail'
  25. ];
  26.  
  27. anagrams.forEach(anigram => { 
  28.   console.log(anigram, '=', checkAnagram(anigram, target))
  29. })

Check if two strings are anagrams of one another.

Log All Class Method Calls

  1. class ConfusingClass {
  2.   constructor() {
  3.     logMethodCalls(this)
  4.     this.confuseMe = 1
  5.     this.someFn(300)
  6.   }
  7.   someFn(startVal = 1) {
  8.     this.confuseMe = startVal
  9.     this.testFn(() => this.otherFn(123))
  10.   }
  11.   testFn(fn) {
  12.     this.confuseMe += 1
  13.     fn(this.confuseMe)
  14.   }
  15.   otherFn(value = 111) {
  16.     this.confuseMe += 2
  17.     this.testFn(() => this.confuseMe += value)
  18.  
  19.     this.confuseMe = this.add(this.confuseMe, 999)
  20.     console.log(this.confuseMe)
  21.   }
  22.   add(a, b) {
  23.     return a + b
  24.   }
  25. }
  26. const confusing = new ConfusingClass()
  27.  
  28. function logMethodCalls(target) { 
  29.   const keys = Object.getOwnPropertyNames(target.constructor.prototype)
  30.   for (let i = 0; i < keys.length; i++) {
  31.     const key = keys[i]
  32.     const propOrMethod = target[key]
  33.     if (typeof propOrMethod === 'function') {
  34.       target[key] = function(...args) {
  35.         console.log(key, '(', args.join(', '), ') - was run')
  36.         return propOrMethod.apply(target, args);
  37.       }
  38.     }
  39.   }
  40. }

This one is good for dealing with confusing classes with lots of method calls. It logs any time a method is called, what its name is and what arguments were passed to it. Sometimes this really beats stepping through breakpoints, at least in my experience…

Simple Way to Validate CSS Colors

  1. function isColor(col) {
  2.   const cache = isColor[col]
  3.   if (cache != null) {
  4.     console.log('- reading cache')
  5.     return cache
  6.   }
  7.   isColor.el.style = ''
  8.   isColor.el.style.color = col
  9.   return isColor[col] = !!isColor.el.style.color
  10. }
  11. isColor.el = document.createElement('div')
  12.  
  13.  
  14. console.log('is "red" a color?', isColor('red'))
  15. console.log('from the cache: ', isColor('red'))
  16.  
  17. console.log('is "rgbx(1, 2, 3)" a color?', isColor('rgbx(1, 2, 3)'))
  18.  
  19. console.log('is "#0f0" a color?', isColor('#0f0'))
  20.  
  21. console.log('is "hsl(192, 50%, 50%)" a color?', isColor('hsl(192, 50%, 50%)'))
  22. console.log('from the cache: ', isColor('hsl(192, 50%, 50%)'))
  23.  
  24. console.log('is "lab(2000.1337% -8.6911 -159.131231 / .987189732)" ?',
  25.   isColor('lab(2000.1337% -8.6911 -159.131231 / .987189732)'))
  26.  
  27. console.log('is "snippetZone" ?', isColor('snippetZone'))

I find this technique is usually good enough to validate colors…

// color // css // dom // graphics // hacks // hex // html // javascript // tricks

x.x()

  1. function x() {
  2.   return { x }
  3. }
  4. x.x = x
  5.  
  6. x(x(x.x.x).x(x)).x(
  7.   x().x(x.x())
  8. ).x
  9. .x
  10. .x
  11. .x.x.x.x()
// hacks // tricks
snippet.zone ~ 2021-24 /// {s/z}