Skip to content

Commit

Permalink
feat: responsive options
Browse files Browse the repository at this point in the history
feat: resize keeps particles in place
  • Loading branch information
matteobruni committed Mar 12, 2021
1 parent cd35308 commit f694555
Show file tree
Hide file tree
Showing 8 changed files with 5,430 additions and 16,724 deletions.
22,037 changes: 5,333 additions & 16,704 deletions core/main/schema/options.schema.json

Large diffs are not rendered by default.

40 changes: 22 additions & 18 deletions core/main/src/Core/Canvas.ts
Expand Up @@ -24,6 +24,8 @@ export class Canvas {
*/
public readonly size: IDimension;

public resizeFactor?: IDimension;

/**
* The particles canvas context
*/
Expand Down Expand Up @@ -128,18 +130,6 @@ export class Canvas {
}
}

/**
* Calculates the size of the canvas
*/
public resize(): void {
if (!this.element) {
return;
}

this.element.width = this.size.width;
this.element.height = this.size.height;
}

/**
* Paints the canvas background
*/
Expand Down Expand Up @@ -181,7 +171,8 @@ export class Canvas {

const container = this.container;

container.canvas.initSize();
container.canvas.resize();
container.actualOptions.setResponsive(this.size.width, container.retina.pixelRatio, container.options);

/* density particles enabled */
container.particles.setDensity();
Expand All @@ -193,19 +184,32 @@ export class Canvas {
}
}

public initSize(): void {
/**
* Calculates the size of the canvas
*/
public resize(): void {
if (!this.element) {
return;
}

const container = this.container;
const pxRatio = container.retina.pixelRatio;
const size = container.canvas.size;
const oldSize = {
width: size.width,
height: size.height,
};

container.canvas.size.width = this.element.offsetWidth * pxRatio;
container.canvas.size.height = this.element.offsetHeight * pxRatio;
size.width = this.element.offsetWidth * pxRatio;
size.height = this.element.offsetHeight * pxRatio;

this.element.width = container.canvas.size.width;
this.element.height = container.canvas.size.height;
this.element.width = size.width;
this.element.height = size.height;

this.resizeFactor = {
width: size.width / oldSize.width,
height: size.height / oldSize.height,
};
}

public drawConnectLine(p1: IParticle, p2: IParticle): void {
Expand Down
6 changes: 4 additions & 2 deletions core/main/src/Core/Container.ts
Expand Up @@ -408,12 +408,14 @@ export class Container {
this.actualOptions = new Options();

this.actualOptions.load(this.options);
this.actualOptions.setTheme(undefined);

/* init canvas + particles */
this.retina.init();
this.canvas.init();

this.actualOptions.setResponsive(this.canvas.size.width, this.retina.pixelRatio, this.options);
this.actualOptions.setTheme(undefined);

this.fpsLimit = this.actualOptions.fpsLimit > 0 ? this.actualOptions.fpsLimit : 60;

const availablePlugins = Plugins.getAvailablePlugins(this);
Expand All @@ -436,7 +438,7 @@ export class Container {
}
}

this.canvas.initSize();
this.canvas.resize();
this.particles.init();
this.particles.setDensity();
}
Expand Down
9 changes: 9 additions & 0 deletions core/main/src/Core/Particles.ts
Expand Up @@ -148,6 +148,13 @@ export class Particles {
// p.vy = f * Math.sin(t);
// }

const resizeFactor = this.container.canvas.resizeFactor;

if (resizeFactor) {
particle.position.x *= resizeFactor.width;
particle.position.y *= resizeFactor.height;
}

particle.move(delta);

if (particle.destroyed) {
Expand All @@ -172,6 +179,8 @@ export class Particles {
this.interactionManager.particlesInteract(particle, delta);
}
}

delete container.canvas.resizeFactor;
}

public draw(delta: IDelta): void {
Expand Down
20 changes: 20 additions & 0 deletions core/main/src/Options/Classes/Options.ts
Expand Up @@ -12,6 +12,7 @@ import { ThemeMode } from "../../Enums/Modes";
import { FullScreen } from "./FullScreen/FullScreen";
import { Motion } from "./Motion/Motion";
import { ManualParticle } from "./ManualParticle";
import { Responsive } from "./Responsive";

/**
* [[include:Options.md]]
Expand Down Expand Up @@ -78,6 +79,7 @@ export class Options implements IOptions, IOptionLoader<IOptions> {
public pauseOnBlur;
public pauseOnOutsideViewport;
public preset?: string | string[];
public responsive: Responsive[];
public themes: Theme[];

constructor() {
Expand All @@ -94,6 +96,7 @@ export class Options implements IOptions, IOptionLoader<IOptions> {
this.particles = new Particles();
this.pauseOnBlur = true;
this.pauseOnOutsideViewport = false;
this.responsive = [];
this.themes = [];
}

Expand Down Expand Up @@ -161,6 +164,18 @@ export class Options implements IOptions, IOptionLoader<IOptions> {

Plugins.loadOptions(this, data);

if (data.responsive !== undefined) {
for (const responsive of data.responsive) {
const optResponsive = new Responsive();

optResponsive.load(responsive);

this.responsive.push(optResponsive);
}
}

this.responsive.sort((a, b) => a.maxWidth - b.maxWidth);

if (data.themes !== undefined) {
for (const theme of data.themes) {
const optTheme = new Theme();
Expand Down Expand Up @@ -201,4 +216,9 @@ export class Options implements IOptions, IOptionLoader<IOptions> {
private importPreset(preset: string): void {
this.load(Plugins.getPreset(preset));
}

public setResponsive(width: number, pxRatio: number, defaultOptions: IOptions): void {
this.load(defaultOptions);
this.load(this.responsive.find((t) => t.maxWidth * pxRatio > width)?.options);
}
}
29 changes: 29 additions & 0 deletions core/main/src/Options/Classes/Responsive.ts
@@ -0,0 +1,29 @@
import type { IResponsive } from "../Interfaces/IResponsive";
import type { IOptionLoader } from "../Interfaces/IOptionLoader";
import type { RecursivePartial } from "../../Types";
import type { IOptions } from "../Interfaces/IOptions";
import { Utils } from "../../Utils";

export class Responsive implements IResponsive, IOptionLoader<IResponsive> {
public maxWidth: number;
public options: RecursivePartial<IOptions>;

constructor() {
this.maxWidth = Infinity;
this.options = {};
}

public load(data?: RecursivePartial<IResponsive>): void {
if (!data) {
return;
}

if (data.maxWidth !== undefined) {
this.maxWidth = data.maxWidth;
}

if (data.options !== undefined) {
this.options = Utils.deepExtend({}, data.options) as RecursivePartial<IOptions>;
}
}
}
6 changes: 6 additions & 0 deletions core/main/src/Options/Interfaces/IOptions.ts
Expand Up @@ -8,6 +8,7 @@ import type { ITheme } from "./Theme/ITheme";
import type { IFullScreen } from "./FullScreen/IFullScreen";
import type { IMotion } from "./Motion/IMotion";
import type { IManualParticle } from "./IManualParticle";
import type { IResponsive } from "./IResponsive";

/**
* The Options interface, defines all the options that can be used by `tsParticles`
Expand Down Expand Up @@ -97,6 +98,11 @@ export interface IOptions {
*/
preset?: SingleOrMultiple<string>;

/**
* This sets custom options based on canvas size
*/
responsive: IResponsive[];

/**
* Enables the retina detection, if disabled the ratio used by canvas will be always 1 and not the device setting.
* @deprecated use the new detectRetina instead
Expand Down
7 changes: 7 additions & 0 deletions core/main/src/Options/Interfaces/IResponsive.ts
@@ -0,0 +1,7 @@
import type { RecursivePartial } from "../../Types";
import type { IOptions } from "./IOptions";

export interface IResponsive {
maxWidth: number;
options: RecursivePartial<IOptions>;
}

0 comments on commit f694555

Please sign in to comment.