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);
plot(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) {
  return Array
    .apply(null,{length:n})
    .map(e => Array
      .apply(null,{length:2})
      .map(() => Math.floor(400 * Math.random()))
    )
  ;
}

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