tweb/src/components/lineBlobDrawable.ts

117 lines
3.5 KiB
TypeScript

/*
* https://github.com/morethanwords/tweb
* Copyright (C) 2019-2021 Eduard Kuzmenko
* https://github.com/morethanwords/tweb/blob/master/LICENSE
*
* Originally from:
* https://github.com/evgeny-nadymov/telegram-react
* Copyright (C) 2018 Evgeny Nadymov
* https://github.com/evgeny-nadymov/telegram-react/blob/master/LICENSE
*/
export const MAX_SPEED = 8.2;
export const MIN_SPEED = 0.8;
// import { MIN_SPEED, MAX_SPEED } from './BlobDrawable';
type Radius = number[];
export default class LineBlobDrawable {
public maxRadius: number;
public minRadius: number;
private N: number;
private radius: Radius;
private radiusNext: Radius;
private progress: number[];
private speed: number[];
constructor(n: number) {
this.maxRadius = 10;
this.minRadius = 0;
this.N = n;
this.radius = new Array(n + 1);
this.radiusNext = new Array(n + 1);
this.progress = new Array(n + 1);
this.speed = new Array(n + 1);
for(let i = 0; i <= n; i++) {
this.generateBlob(this.radius, i);
this.generateBlob(this.radiusNext, i);
this.progress[i] = 0;
}
}
private generateBlob(radius: Radius, i: number) {
const {maxRadius, minRadius, speed} = this;
const radDif = maxRadius - minRadius;
radius[i] = minRadius + Math.random() * radDif;
speed[i] = 0.017 + 0.003 * Math.random();
}
private generateNextBlob() {
const {radius, radiusNext, progress, N} = this;
for(let i = 0; i < N; i++) {
this.generateBlob(radius, i);
this.generateBlob(radiusNext, i);
progress[i] = 0.0;
}
}
public update(amplitude: number, speedScale: number) {
const {N, progress, speed, radius, radiusNext} = this;
for(let i = 0; i <= N; i++) {
progress[i] += (speed[i] * MIN_SPEED) + amplitude * speed[i] * MAX_SPEED * speedScale;
if(progress[i] >= 1.0) {
progress[i] = 0.0;
radius[i] = radiusNext[i];
this.generateBlob(radiusNext, i);
}
}
}
public draw(left: number, top: number, right: number, bottom: number, canvas: HTMLCanvasElement, paint: (ctx: CanvasRenderingContext2D) => void, pinnedTop: number, progressToPinned: number) {
if(canvas.getContext) {
const ctx = canvas.getContext('2d');
// ctx.globalAlpha = 0.5;
// ctx.lineWidth = 1;
ctx.beginPath();
ctx.moveTo(right, bottom);
ctx.lineTo(left, bottom);
const {radius, radiusNext, N} = this;
for(let i = 0; i <= N; i++) {
if(i === 0) {
const progress = this.progress[i];
const r1 = radius[i] * (1.0 - progress) + radiusNext[i] * progress;
const y = (top - r1) * progressToPinned + pinnedTop * (1.0 - progressToPinned);
ctx.lineTo(left, y);
} else {
const progress = this.progress[i - 1];
const r1 = radius[i - 1] * (1.0 - progress) + radiusNext[i - 1] * progress;
const progressNext = this.progress[i];
const r2 = radius[i] * (1.0 - progressNext) + radiusNext[i] * progressNext;
const x1 = (right - left) / N * (i - 1);
const x2 = (right - left) / N * i;
const cx = x1 + (x2 - x1) / 2;
const y1 = (top - r1) * progressToPinned + pinnedTop * (1.0 - progressToPinned);
const y2 = (top - r2) * progressToPinned + pinnedTop * (1.0 - progressToPinned);
ctx.bezierCurveTo(cx, y1, cx, y2, x2, y2);
if(i === N) {
ctx.lineTo(right, bottom);
}
}
}
// ctx.scale(1.0, 1.0);
paint(ctx);
ctx.fill();
ctx.closePath();
}
}
}