Skip to content

Commit a3a518b

Browse files
committed
refactor: changed type from standard canvas context, to both types (canvas and offscreen)
1 parent 289815f commit a3a518b

38 files changed

Lines changed: 185 additions & 133 deletions

File tree

engine/src/Core/Container.ts

Lines changed: 33 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,7 @@
11
import { animate, cancelAnimation, getRangeValue } from "../Utils/MathUtils.js";
2-
import {
3-
defaultFps,
4-
defaultFpsLimit,
5-
millisecondsToSeconds,
6-
minFpsLimit,
7-
removeDeleteCount,
8-
removeMinIndex,
9-
} from "./Utils/Constants.js";
2+
import { defaultFps, defaultFpsLimit, millisecondsToSeconds, minFpsLimit } from "./Utils/Constants.js";
103
import { CanvasManager } from "./CanvasManager.js";
11-
import type { Engine } from "./Engine.js";
4+
import type { CustomEventArgs } from "../Types/CustomEventArgs.js";
125
import { EventListeners } from "./Utils/EventListeners.js";
136
import { EventType } from "../Enums/Types/EventType.js";
147
import type { IContainerPlugin } from "./Interfaces/IContainerPlugin.js";
@@ -25,6 +18,14 @@ import { Retina } from "./Retina.js";
2518
import { getLogger } from "../Utils/LogUtils.js";
2619
import { loadOptions } from "../Utils/OptionsUtils.js";
2720

21+
interface ContainerParams {
22+
dispatchCallback: (eventType: string, args?: CustomEventArgs) => void;
23+
id: string;
24+
onDestroy: (remove: boolean) => void;
25+
pluginManager: PluginManager;
26+
sourceOptions?: ISourceOptions;
27+
}
28+
2829
/**
2930
* Checks if the container is still usable
3031
* @param container - the container to check
@@ -132,12 +133,12 @@ export class Container {
132133
private _delay: number;
133134
private _delayTimeout?: number | NodeJS.Timeout;
134135
private readonly _delta: IDelta = { value: 0, factor: 0 };
136+
private readonly _dispatchCallback;
135137
private _drawAnimationFrame?: number;
136138
/**
137139
* The container duration
138140
*/
139141
private _duration;
140-
private readonly _engine;
141142
private readonly _eventListeners;
142143
private _firstStart;
143144
private _initialSourceOptions;
@@ -149,19 +150,23 @@ export class Container {
149150
* The container lifetime
150151
*/
151152
private _lifeTime;
153+
private readonly _onDestroy;
152154
private _options;
153155
private _paused;
156+
private readonly _pluginManager;
154157
private _smooth;
155158
private _sourceOptions;
156159

157160
/**
158161
* This is the core class, create an instance to have a new working particles manager
159-
* @param engine - the engine used by container
160-
* @param id - the id to identify this instance
161-
* @param sourceOptions - the options to load
162+
* @param params -
162163
*/
163-
constructor(engine: Engine, id: string, sourceOptions?: ISourceOptions) {
164-
this._engine = engine;
164+
constructor(params: ContainerParams) {
165+
const { dispatchCallback, pluginManager, id, onDestroy, sourceOptions } = params;
166+
167+
this._pluginManager = pluginManager;
168+
this._dispatchCallback = dispatchCallback;
169+
this._onDestroy = onDestroy;
165170
this.id = Symbol(id);
166171
this.fpsLimit = 120;
167172
this.hdr = false;
@@ -182,15 +187,15 @@ export class Container {
182187
this.shapeDrawers = new Map();
183188
this.particleUpdaters = [];
184189
this.retina = new Retina(this);
185-
this.canvas = new CanvasManager(this._engine.pluginManager, this);
186-
this.particles = new ParticlesManager(this._engine.pluginManager, this);
190+
this.canvas = new CanvasManager(this._pluginManager, this);
191+
this.particles = new ParticlesManager(this._pluginManager, this);
187192
this.plugins = [];
188193
this.particleDestroyedPlugins = [];
189194
this.particleCreatedPlugins = [];
190195
this.particlePositionPlugins = [];
191196
/* tsParticles variables with default values */
192-
this._options = loadContainerOptions(this._engine.pluginManager, this);
193-
this.actualOptions = loadContainerOptions(this._engine.pluginManager, this);
197+
this._options = loadContainerOptions(this._pluginManager, this);
198+
this.actualOptions = loadContainerOptions(this._pluginManager, this);
194199

195200
/* ---------- tsParticles - start ------------ */
196201
this._eventListeners = new EventListeners(this);
@@ -260,24 +265,17 @@ export class Container {
260265
this.particleUpdaters = [];
261266
this.plugins.length = 0;
262267

263-
this._engine.pluginManager.clearPlugins(this);
268+
this._pluginManager.clearPlugins(this);
264269

265270
this.destroyed = true;
266271

267-
if (remove) {
268-
const mainArr = this._engine.items,
269-
idx = mainArr.indexOf(this);
270-
271-
if (idx >= removeMinIndex) {
272-
mainArr.splice(idx, removeDeleteCount);
273-
}
274-
}
272+
this._onDestroy(remove);
275273

276274
this.dispatchEvent(EventType.containerDestroyed);
277275
}
278276

279277
dispatchEvent(type: string, data?: unknown): void {
280-
this._engine.dispatchEvent(type, {
278+
this._dispatchCallback(type, {
281279
container: this,
282280
data,
283281
});
@@ -335,7 +333,7 @@ export class Container {
335333

336334
const allContainerPlugins = new Map<IPlugin, IContainerPlugin>();
337335

338-
for (const plugin of this._engine.pluginManager.plugins) {
336+
for (const plugin of this._pluginManager.plugins) {
339337
const containerPlugin = await plugin.getPlugin(this);
340338

341339
if (containerPlugin.preInit) {
@@ -348,13 +346,8 @@ export class Container {
348346
await this.initDrawersAndUpdaters();
349347

350348
/* options settings */
351-
this._options = loadContainerOptions(
352-
this._engine.pluginManager,
353-
this,
354-
this._initialSourceOptions,
355-
this.sourceOptions,
356-
);
357-
this.actualOptions = loadContainerOptions(this._engine.pluginManager, this, this._options);
349+
this._options = loadContainerOptions(this._pluginManager, this, this._initialSourceOptions, this.sourceOptions);
350+
this.actualOptions = loadContainerOptions(this._pluginManager, this, this._options);
358351

359352
this.plugins.length = 0;
360353
this.particleDestroyedPlugins.length = 0;
@@ -416,7 +409,7 @@ export class Container {
416409
}
417410

418411
async initDrawersAndUpdaters(): Promise<void> {
419-
const pluginManager = this._engine.pluginManager;
412+
const pluginManager = this._pluginManager;
420413

421414
this.effectDrawers = await pluginManager.getEffectDrawers(this, true);
422415
this.shapeDrawers = await pluginManager.getShapeDrawers(this, true);
@@ -508,13 +501,8 @@ export class Container {
508501

509502
this._initialSourceOptions = sourceOptions;
510503
this._sourceOptions = sourceOptions;
511-
this._options = loadContainerOptions(
512-
this._engine.pluginManager,
513-
this,
514-
this._initialSourceOptions,
515-
this.sourceOptions,
516-
);
517-
this.actualOptions = loadContainerOptions(this._engine.pluginManager, this, this._options);
504+
this._options = loadContainerOptions(this._pluginManager, this, this._initialSourceOptions, this.sourceOptions);
505+
this.actualOptions = loadContainerOptions(this._pluginManager, this, this._options);
518506

519507
return this.refresh();
520508
}

engine/src/Core/Engine.ts

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {
1313
none,
1414
one,
1515
removeDeleteCount,
16+
removeMinIndex,
1617
} from "./Utils/Constants.js";
1718
import { itemFromSingleOrMultiple, safeDocument } from "../Utils/Utils.js";
1819
import type { Container } from "./Container.js";
@@ -56,7 +57,7 @@ async function getDataFromUrl(
5657
const response = await fetch(url);
5758

5859
if (response.ok) {
59-
return (await response.json()) as SingleOrMultiple<ISourceOptions>;
60+
return (await response.json()) as SingleOrMultiple<Readonly<ISourceOptions>>;
6061
}
6162

6263
getLogger().error(`${response.status.toString()} while retrieving config file`);
@@ -107,7 +108,7 @@ const getCanvasFromContainer = (domContainer: HTMLElement): HTMLCanvasElement =>
107108
return domContainer;
108109
}
109110

110-
domContainer = documentSafe.createElement("div");
111+
domContainer = documentSafe.createElement("canvas");
111112

112113
domContainer.id = id;
113114
domContainer.dataset[generatedAttribute] = generatedTrue;
@@ -222,7 +223,26 @@ export class Engine {
222223
currentOptions = itemFromSingleOrMultiple(options, index),
223224
{ items } = this,
224225
oldIndex = items.findIndex(v => v.id.description === id),
225-
newItem = new Container(this, id, currentOptions);
226+
newItem = new Container({
227+
dispatchCallback: (eventType, args): void => {
228+
this.dispatchEvent(eventType, args);
229+
},
230+
id,
231+
onDestroy: (remove): void => {
232+
if (!remove) {
233+
return;
234+
}
235+
236+
const mainArr = this.items,
237+
idx = mainArr.indexOf(newItem);
238+
239+
if (idx >= removeMinIndex) {
240+
mainArr.splice(idx, removeDeleteCount);
241+
}
242+
},
243+
pluginManager: this.pluginManager,
244+
sourceOptions: currentOptions,
245+
});
226246

227247
if (oldIndex >= loadMinIndex) {
228248
const old = this.item(oldIndex),

engine/src/Core/Interfaces/IContainerPlugin.ts

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import type { CanvasContextType } from "../../Types/CanvasContextType.js";
12
import type { ExportResult } from "../../Types/ExportResult.js";
23
import type { ICoordinates } from "./ICoordinates.js";
34
import type { IDelta } from "./IDelta.js";
@@ -12,16 +13,16 @@ export interface IContainerPlugin {
1213
canvasClear?: () => boolean;
1314
canvasPaint?: () => boolean;
1415
checkParticlePosition?: (particle: Particle, position: ICoordinates, tryCount: number) => boolean;
15-
clearDraw?: (context: CanvasRenderingContext2D, delta: IDelta) => void;
16+
clearDraw?: (context: CanvasContextType, delta: IDelta) => void;
1617
clickPositionValid?: (position: ICoordinates) => boolean;
1718
destroy?: () => void;
18-
draw?: (context: CanvasRenderingContext2D, delta: IDelta) => void;
19-
drawParticle?: (context: CanvasRenderingContext2D, particle: Particle, delta: IDelta) => void;
20-
drawParticleCleanup?: (context: CanvasRenderingContext2D, particle: Particle, delta: IDelta) => void;
21-
drawParticleSetup?: (context: CanvasRenderingContext2D, particle: Particle, delta: IDelta) => void;
19+
draw?: (context: CanvasContextType, delta: IDelta) => void;
20+
drawParticle?: (context: CanvasContextType, particle: Particle, delta: IDelta) => void;
21+
drawParticleCleanup?: (context: CanvasContextType, particle: Particle, delta: IDelta) => void;
22+
drawParticleSetup?: (context: CanvasContextType, particle: Particle, delta: IDelta) => void;
2223
drawParticleTransform?: (data: IShapeDrawData) => void;
23-
drawSettingsCleanup?: (context: CanvasRenderingContext2D, delta: IDelta) => void;
24-
drawSettingsSetup?: (context: CanvasRenderingContext2D, delta: IDelta) => void;
24+
drawSettingsCleanup?: (context: CanvasContextType, delta: IDelta) => void;
25+
drawSettingsSetup?: (context: CanvasContextType, delta: IDelta) => void;
2526
export?: (type: string, data: Record<string, unknown>) => Promise<ExportResult>;
2627
init?: () => Promise<void>;
2728
particleBounce?: (particle: Particle, delta: IDelta, direction: OutModeDirection) => boolean;

engine/src/Core/Interfaces/IDrawParticleParams.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import type { CanvasContextType } from "../../Types/CanvasContextType.js";
12
import type { Container } from "../Container.js";
23
import type { IDelta } from "./IDelta.js";
34
import type { IParticleColorStyle } from "./IParticleColorStyle.js";
@@ -16,7 +17,7 @@ export interface IDrawParticleParams {
1617
/**
1718
* The canvas context to draw on
1819
*/
19-
context: CanvasRenderingContext2D;
20+
context: CanvasContextType;
2021
/**
2122
* This variable contains the delta between the current frame and the previous frame
2223
*/

engine/src/Core/Interfaces/IParticleUpdater.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import type { CanvasContextType } from "../../Types/CanvasContextType.js";
12
import type { IDelta } from "./IDelta.js";
23
import type { IParticleColorStyle } from "./IParticleColorStyle.js";
34
import type { IParticleTransformValues } from "./IParticleTransformValues.js";
@@ -13,7 +14,7 @@ export interface IParticleUpdater {
1314

1415
getColorStyles?: (
1516
particle: Particle,
16-
context: CanvasRenderingContext2D,
17+
context: CanvasContextType,
1718
radius: number,
1819
opacity: number,
1920
) => IParticleColorStyle;

engine/src/Core/Interfaces/IShapeDrawData.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import type { CanvasContextType } from "../../Types/CanvasContextType.js";
12
import type { ICoordinates } from "./ICoordinates.js";
23
import type { IDelta } from "./IDelta.js";
34
import type { Particle } from "../Particle.js";
@@ -6,7 +7,7 @@ export interface IShapeDrawData<TParticle extends Particle = Particle> {
67
/**
78
* the canvas context for drawing
89
*/
9-
context: CanvasRenderingContext2D;
10+
context: CanvasContextType;
1011

1112
/**
1213
* this variable contains the delta between the current frame and the previous frame

engine/src/Core/RenderManager.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { clear, drawParticle, drawParticlePlugin, paintBase, paintImage } from "../Utils/CanvasUtils.js";
22
import { defaultCompositeValue, defaultTransformValue, minimumSize, zIndexFactorOffset } from "./Utils/Constants.js";
33
import { getStyleFromHsl, rangeColorToHsl } from "../Utils/ColorUtils.js";
4+
import type { CanvasContextType } from "../Types/CanvasContextType.js";
45
import type { CanvasManager } from "./CanvasManager.js";
56
import type { Container } from "./Container.js";
67
import type { IContainerPlugin } from "./Interfaces/IContainerPlugin.js";
@@ -45,7 +46,7 @@ export class RenderManager {
4546
/**
4647
* The particles canvas context
4748
*/
48-
private _context: CanvasRenderingContext2D | null;
49+
private _context: CanvasContextType | null;
4950
private _contextSettings?: CanvasRenderingContext2DSettings;
5051
private _drawParticlePlugins: IContainerPlugin[];
5152
private _drawParticlesCleanupPlugins: IContainerPlugin[];
@@ -145,7 +146,7 @@ export class RenderManager {
145146
* @param cb -
146147
* @returns the result of the callback
147148
*/
148-
draw<T>(cb: (context: CanvasRenderingContext2D) => T): T | undefined {
149+
draw<T>(cb: (context: CanvasContextType) => T): T | undefined {
149150
const ctx = this._context;
150151

151152
if (!ctx) {
@@ -383,7 +384,7 @@ export class RenderManager {
383384
});
384385
}
385386

386-
setContext(context: CanvasRenderingContext2D | null): void {
387+
setContext(context: CanvasContextType | null): void {
387388
this._context = context;
388389

389390
if (this._context) {
@@ -408,7 +409,7 @@ export class RenderManager {
408409
};
409410

410411
private readonly _applyPreDrawUpdaters: (
411-
ctx: CanvasRenderingContext2D,
412+
ctx: CanvasContextType,
412413
particle: Particle,
413414
radius: number,
414415
zOpacity: number,
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export type CanvasContextType = CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D;

engine/src/Utils/CanvasUtils.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
1-
import type { IEffectDrawer, IShapeDrawData, IShapeDrawer } from "../export-types.js";
21
import { defaultZoom, minStrokeWidth, originPoint } from "../Core/Utils/Constants.js";
2+
import type { CanvasContextType } from "../Types/CanvasContextType.js";
33
import type { IContainerPlugin } from "../Core/Interfaces/IContainerPlugin.js";
44
import type { IDelta } from "../Core/Interfaces/IDelta.js";
55
import type { IDimension } from "../Core/Interfaces/IDimension.js";
66
import type { IDrawParticleParams } from "../Core/Interfaces/IDrawParticleParams.js";
7+
import type { IEffectDrawer } from "../Core/Interfaces/IEffectDrawer.js";
8+
import type { IShapeDrawData } from "../Core/Interfaces/IShapeDrawData.js";
9+
import type { IShapeDrawer } from "../Core/Interfaces/IShapeDrawer.js";
710
import type { Particle } from "../Core/Particle.js";
811

912
/**
@@ -12,7 +15,7 @@ import type { Particle } from "../Core/Particle.js";
1215
* @param dimension - The dimension of the rectangle.
1316
* @param baseColor - The base color of the rectangle, if not specified a transparent color will be used.
1417
*/
15-
export function paintBase(context: CanvasRenderingContext2D, dimension: IDimension, baseColor?: string): void {
18+
export function paintBase(context: CanvasContextType, dimension: IDimension, baseColor?: string): void {
1619
context.fillStyle = baseColor ?? "rgba(0,0,0,0)";
1720

1821
context.fillRect(originPoint.x, originPoint.y, dimension.width, dimension.height);
@@ -26,7 +29,7 @@ export function paintBase(context: CanvasRenderingContext2D, dimension: IDimensi
2629
* @param opacity - The opacity of the image.
2730
*/
2831
export function paintImage(
29-
context: CanvasRenderingContext2D,
32+
context: CanvasContextType,
3033
dimension: IDimension,
3134
image: HTMLImageElement | undefined,
3235
opacity: number,
@@ -49,7 +52,7 @@ export function paintImage(
4952
* @param context - The canvas context to clear.
5053
* @param dimension - The dimension of the canvas.
5154
*/
52-
export function clear(context: CanvasRenderingContext2D, dimension: IDimension): void {
55+
export function clear(context: CanvasContextType, dimension: IDimension): void {
5356
context.clearRect(originPoint.x, originPoint.y, dimension.width, dimension.height);
5457
}
5558

@@ -232,7 +235,7 @@ export function drawShapeBeforeDraw(drawer: IShapeDrawer | undefined, data: ISha
232235
* @param delta - this variable contains the delta between the current frame and the previous frame
233236
*/
234237
export function drawParticlePlugin(
235-
context: CanvasRenderingContext2D,
238+
context: CanvasContextType,
236239
plugin: IContainerPlugin,
237240
particle: Particle,
238241
delta: IDelta,

0 commit comments

Comments
 (0)