JSFiddle - React, Tailwind, and code Playground

by Sergei Sokolov

HTML

<button id="btn-clear">Стереть следы</button>
<button id="btn-new">Новая фигура</button>
<br>
<canvas id="canvas" width="400" height="400"></canvas>

CSS

canvas {
  border:1px solid grey;
}

JavaScript

/**
 * для вопроса https://toster.ru/q/559159
 */
const canvas = document.getElementById('canvas');
const btn_c = document.getElementById('btn-clear');
const btn_n = document.getElementById('btn-new');
const ctx = canvas.getContext('2d');

let points = getPoints(5);
console.log(points);
plot(points);
//rays(points);

btn_c.addEventListener("click", e => {
  ctx.clearRect(0,0,400,400);
  plot(points);
});

btn_n.addEventListener("click", e => {
  ctx.clearRect(0,0,400,400);
  points = getPoints(5);
  plot(points);
});

canvas.addEventListener("click", e => {
  let rect = canvas.getBoundingClientRect();
  let x = e.clientX - rect.left;
  let y = e.clientY - rect.top;
  zoomOut([x,y]);
});

function zoomOut(C) {
  let k = 1, delta = 0.95, trails = 0;
  
  function draw() {
    k *= delta;
    plot( scale( k, C, points));
    if(trails++ < 50) window.requestAnimationFrame(draw);
  }
  
  draw();
}






function scale( k, center, points) {
  return points.map( p => p.map( (x, i) => center[i] + k * (x - center[i])));
}

function getPoints(n) {
  const da = 2 * Math.PI / n;
  const p4 = Math.PI / 4;
  return Array
    .apply(null, { length:n })
    .map((e, i) => {
      let a = -p4 + da * i + da * Math.random();
      let ta = Math.tan((a + p4) % (Math.PI / 2) - p4)
      let cross;
      if(a > -p4  &&  a <= p4) { // right
        cross = [400, 200 - Math.round(ta * 200)];
      } else if( a > p4 && a <= 3 * p4) { // top
        cross = [200 + Math.round(ta * 200), 0];
      } else if( a > 3 * p4 && a <= 5 * p4) { // left
        cross = [0, 200 + Math.round(ta * 200)];
      } else if( a > 5 * p4 && a <= 7 * p4) { // bottom
        cross = [200 + Math.round(ta * 200), 400];
      } else {
        console.error('bad case. a = ', a);
      }
      return cross.map(x => 200 + Math.random() * (x - 200));
    })
  ;
}


function plot(points) {
  ctx.beginPath();
  ctx.moveTo(...points[0]);
  for(let i = 1; i < points.length; i++) {
    ctx.lineTo(...points[i]);
  }
 ...