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

Parametric Equation for Rectangle

  1. // from http://math.stackexchange.com/questions/69099/equation-of-a-rectangle
  2. const rect = (px, py, rx, ry, t) => ({
  3.   x: px + rx + rx * (Math.abs(Math.cos(t)) * Math.cos(t) + Math.abs(Math.sin(t)) * Math.sin(t)),
  4.   y: py + ry + ry * (Math.abs(Math.cos(t)) * Math.cos(t) - Math.abs(Math.sin(t)) * Math.sin(t))
  5. })
  6.  
  7. const SIZE = 200
  8.  
  9. const c = document.body.appendChild(
  10.   Object.assign(document.createElement`canvas`,
  11.     { width: SIZE, height: SIZE }
  12.   )).getContext`2d`
  13.  
  14. c.fillStyle = 'black'
  15. c.fillRect(0, 0, SIZE, SIZE)
  16.  
  17. let t = 0
  18. setInterval(() => {
  19.   const { x, y } = rect(20, 20, 60, 70, t)
  20.   c.fillStyle = 'rgba(255, 0, 0, .1)'
  21.   c.fillRect(x, y, 10, 10)
  22.   t += .05
  23. }, 16)

Wanted to know how to do this for something back in 2015. Great math stackexchange answer here: http://math.stackexchange.com/questions/69099/equation-of-a-rectangle

Could be optimized but leaving as is to match:

x = p(|cos t|cos t + |sin t| sin t)
y = p(|cos t|cos t - |sin t| sin t)

One small change here is to add the width and height to the offset so that it draws from the upper left hand corner instead of the center…

Sort Local Git Branches by Date

  1. git for-each-ref --sort=-committerdate refs/heads/
  2.  
  3. # Or using git branch (since version 2.7.0)
  4. git branch --sort=-committerdate  # DESC
  5. git branch --sort=committerdate  # ASC

From this stackoverflow post: https://stackoverflow.com/a/5188364/502848

The above is very useful (who knows maybe SourceTree can do it too).

// git

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…

IOS 16 Orientation Issues

With IOS 16 all my apps that support multiple orientations are now broken when rotating the device. Apple has broken my apps so many times with stuff like this. It’s so frustrating! Anyway…

Here is how I fixed it for my apps. In my main view controller I listen for orientation changes:

  1. [[NSNotificationCenter defaultCenter] addObserver:self
  2.                                       selector:@selector(orientationChange:)
  3.                                       name:UIDeviceOrientationDidChangeNotification
  4.                                       object:nil];

That has been that way for years… works fine and calls orientationChange.

  1. - (void)orientationChange:(NSNotification *)note {
  2.   UIDevice * device = note.object;
  3.   orient = device.orientation;
  4.  
  5.   // found this by searching around github https://github.com/liLeiBest/LZDependencyToolkit/blob/bca976207ef9674632d448e62ac425c22cecbc4f/LZDependencyToolkit/Classes/Category/UIViewController+LZForceRotation.m#L107
  6.   // glad that someone figured it out :D
  7.   if (@available(iOS 16, *)) {
  8.  
  9.     [self setNeedsUpdateOfSupportedInterfaceOrientations];
  10.     [self.navigationController setNeedsUpdateOfSupportedInterfaceOrientations];
  11.     NSArray *array = [[[UIApplication sharedApplication] connectedScenes] allObjects];
  12.     if (array.count) {
  13.  
  14.       UIWindowScene *scene = (UIWindowScene *)array[0];
  15.       UIWindowSceneGeometryPreferencesIOS *geometryperences = [[UIWindowSceneGeometryPreferencesIOS alloc] initWithInterfaceOrientations:(1 << orient)];
  16.       [scene requestGeometryUpdateWithPreferences:geometryperences errorHandler:^(NSError * _Nonnull error) {
  17.         NSLog(@"Orientation Error:%@", error);
  18.       }];
  19.     }
  20.   }
  21.   [self refreshUI];
  22. }

That big blob checking if IOS 16 is available is now necessary. Within my refreshUI method I use the width and height of the screen to position things. It seems that [[UIScreen mainScreen] bounds].size.height now takes a few hundred milliseconds to be updated with the current orientation. Maybe there is some new animation that needs to be disabled, but I have not been able to find it. So, I just delay 200ms and all seems ok:

  1. - (void) refreshUI {
  2.  
  3.   [self delay:0.2 callback:^(void){
  4.  
  5.     UIWindow* window=[[UIApplication sharedApplication] keyWindow];
  6.  
  7.     float t = window.safeAreaInsets.top;
  8.  
  9.     float b = window.safeAreaInsets.bottom;
  10.  
  11.     float l = window.safeAreaInsets.left;
  12.  
  13.     float r = window.safeAreaInsets.right;
  14.  
  15.     H = [[UIScreen mainScreen] bounds].size.height;
  16.     W = [[UIScreen mainScreen] bounds].size.width;
  17.  
  18.     // do some layout change stuff using `W` and `H`
  19.  
  20.   }];
  21. }

My delay method just looks like this:

  1. - (void)delay:(double)time callback:(void(^)(void))callback {
  2.   double delayInSeconds = time;
  3.   dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
  4.   dispatch_after(popTime, dispatch_get_main_queue(), callback);
  5. }

Beware of IOS dev – its riddled with this stuff…

// IOS // iPad // iPhone // ui

Remove a DOM HTML Element

  1. const button = document.createElement('button');
  2. button.innerText = 'Hello There';
  3. document.body.appendChild(button);
  4.  
  5. // click anywhere
  6. document.body.addEventListener('click', () => {
  7.   if (button.parentNode != null) {
  8.     button.parentNode.removeChild(button);
  9.   }
  10. });

In vanilla js you’ll find yourself checking if an HTML DOM element can be removed, by seeing if it has a parent (as seen above). Forgetting to do so is the source of many errors.

With the death of IE11 you can use remove()

  1. const button = document.createElement('button');
  2. button.innerText = 'Hello There 2';
  3. document.body.appendChild(button);
  4.  
  5. // click anywhere
  6. document.body.addEventListener('click', () => {
  7.    button.remove();
  8. });

No error occurs when calling remove() on something that is already removed… just like the old jQuery days 😉

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