Intersection [circle, rectangle]

by exodus4d

HTML

<h5>Drag Circle or Rect: turns red if shapes intersect<br></h5>
<div class="ui">
  <label class="label" title="Show debug">
    <input type="checkbox" onchange="document.getElementById('canvas').classList.toggle('debug')">
  </label>
  <label class="label" title="Play">
    <input type="checkbox" value="1" onchange="document.getElementById('canvas').style.setProperty('--play', ~~this.checked)" checked>
  </label>
  <label class="label" title="Duration (ms)">
    <input type="range" min="500" max="8000" value="4000" oninput="document.getElementById('canvas').style.setProperty('--duration', this.value)">
  </label>
</div>


<canvas class="" id="canvas" width="400" height="400" style="--play: 1"></canvas>

SCSS

* {
  box-sizing: border-box;
  font-family: sans-serif;
}


#canvas {
  width: 400px;
  height: 400px;
  border: 1px solid blue;
  margin-left: 20px;
}

.ui {
  display: grid;
  grid-auto-columns: minmax(200px, 300px);
  grid-auto-rows: minmax(34px, max-content);
  column-gap: 50px;
  row-gap: 5px;
  font-size: 16px;
  max-width: 400px;
  
  .label {
    display: flex;
    align-items: center;
    column-gap: 10px;
    justify-content: space-between;
    padding: 0 8px;
    font-family: inherit;
    
    &::before {
      content: attr(title);
      white-space: nowrap;
    }
  }
}

JavaScript

class DOMCircle extends DOMPoint {
	constructor(x, y, r) {
  	super(x, y);
    this.r = r;
  }
  
  get r(){
  	return this._r || 0;
  }
  
  set r(r) {
  	this._r = parseInt(r);
  }
}

// Scenary objects
const domCirc =  new DOMCircle(70, 130, 10);
const domRect = new DOMRect(100, 100, 25, 180);

// Current activ dragging papth
let dragPath;

// Current position of dragged paths
let circPath, rectPath;

//  Circle frame history store
let circPathHistory = [];

const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');

// Set canvas origin
ctx.setTransform(1, 0, 0, 1, 100.5, 100.5);

// Set default styles
ctx.fillStyle = 'skyblue';
ctx.strokeStyle = 'black';

const rad2deg = rad => rad * (180 / Math.PI);

const domRectList = domRect => Array.from(Object.keys(DOMRect.prototype), k => domRect[k]);

class Scenary extends Map {
  
  set(key, shape) {
  	const shapeApi = {
    	shape,
    	mTranslate: new DOMMatrix(),
      mTransform: new DOMMatrix(),
      getTranslate() {
      	return this.mTranslate;
      },
      setTranslate(x = 0, y = 0){
      	this.mTranslate = new DOMMatrix([1, 0, 0, 1, x, y]);
      },
      translate(x = 0, y = 0){
      	this.mTranslate.translateSelf(x, y);
        return this;
      },
      getTransform() {
      	return this.mTransform;
      },
      setTransform(mTransform = new DOMMatrix()){
      	this.mTransform = DOMMatrix.fromMatrix(mTransform);
      },
      transform(mTransform){
      	this.mTransform.multiplySelf(mTransform);
        return this;
      },
      reset(){
      	this.setTranslate();
        this.setTransform();
      }
    };
    
    let shapeApiCustom;
  	if (shape instanceof DOMRect) {
      shapeApiCustom = {
        getShape() {
					const {x, y} = new DOMPoint(shape.x, shape.y).matrixTransform(this.getTranslate());
          return new DOMRect(x, y, this.shape.width, this.shape.height);
        },
        getCenter() {
         	return new DOMPoint(this.shape.x +...