JSFiddle - React, Tailwind, and code Playground
by Sergei Sokolov
HTML
<canvas width="300" height="300"></canvas>
CSS
canvas {border:1px solid #CCC}
JavaScript
/**
* для вопроса https://qna.habr.com/q/1031618
* Как нарисовать неправильный многоугольник?
*/
const ctx = document.querySelector('canvas')
.getContext('2d');
ctx.translate(150, 150); // (0, 0) в центр канвы
// стиль линий
ctx.strokeStyle = "darkslategrey";
ctx.lineWidth = 2;
ctx.lineJoin = 'round';
class Arm {
constructor(length) {
this.length = length;
this.a = Math.random() * Math.PI * 2;
this.da = -0.5 + Math.random();
this.scale = 7;
}
render(dt) {
this.a += dt * this.da / 5e2; // пересчитать угол
ctx.rotate(this.a); // повернуть
ctx.translate(this.scale * this.length, 0); // отъехать
ctx.lineTo(0, 0); // нарисовать плечо
}
}
const lengths = [1, 2, 5, 8, 11]; // длины плечей
const arms = lengths.map((len) => new Arm(len));
const tail = [];
const tailLimit = 1e3; // max length
let prev = 0; // время предыдущего кадра
const render = (ts) => {
const dt = prev ? ts - prev : 0; // ск. времени прошло между кадрами
prev = ts;
ctx.clearRect(-150, -150, 300, 300); // очистить кадр
ctx.save(); // запомнить несмещенное состояние
ctx.beginPath();
ctx.moveTo(0, 0);
arms.forEach((arm) => arm.render(dt));
ctx.stroke();
addTailPoint();
ctx.restore(); // восстановить сохранённое состояние
renderTail();
requestAnimationFrame(render); // запросить рисование след. кадра
}
const addTailPoint = () => {
const tailPoint = ctx.getTransform()
.inverse().translate(150, 150).inverse()
.transformPoint(new DOMPoint(0, 0));
tail.unshift(tailPoint);
tail.length = Math.min(tailLimit, tail.length);
}
const renderTail = () => {
ctx.save();
ctx.strokeStyle = 'rgb(0, 0, 0, 0.8)';
ctx.lineWidth = 0.5;
ctx.beginPath();
tail.forEach((p) => ctx.lineTo(p.x, p.y));
ctx.stroke();
ctx.restore();
}
requestAnimationFrame(render);