117 lines
3.6 KiB
TypeScript
117 lines
3.6 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();
|
|
}
|
|
}
|
|
}
|