Skip to content

Commit

Permalink
feat: add useMemo
Browse files Browse the repository at this point in the history
  • Loading branch information
halilatilla committed Jul 22, 2023
1 parent c8b2fe9 commit 2dddf6a
Show file tree
Hide file tree
Showing 9 changed files with 13,682 additions and 14,023 deletions.
2 changes: 1 addition & 1 deletion package.json
Expand Up @@ -73,7 +73,7 @@
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-is": "^17.0.2",
"semantic-release": "^18.0.1",
"semantic-release": "^21.0.7",
"size-limit": "^4.12.0",
"tsdx": "^0.14.1",
"tslib": "^2.3.0",
Expand Down
32 changes: 32 additions & 0 deletions src/hooks/useParticleConfig.tsx
@@ -0,0 +1,32 @@
import { useState } from 'react';
import sketch from '../sketch/index';
import { ParticleState } from '../types';

export default function useParticleConfig({
text = 'Halil Atilla',
textSize = 160,
flow = 0.3,
topSpeed = 100,
lifeSpan = 2000,
flowOffset = 0,
gravity = { direction: 90, force: 0 },
canvas = { width: 880, height: 300, bg: '#161c1e' },
colorSet = ['#fbbf24', '#e91e63', '#60a5fa', '#673ab7', '#65a30d'],
}): ParticleState {
const [state] = useState<ParticleState>({
colorSet,
config: {
text,
textSize,
flow,
topSpeed,
lifeSpan,
flowOffset,
gravity,
canvas,
},
sketch,
});

return state;
}
26 changes: 26 additions & 0 deletions src/hooks/withClientSideRendering.tsx
@@ -0,0 +1,26 @@
import React, {
useEffect,
useState,
ComponentType,
PropsWithChildren,
} from 'react';

function withClientSideRendering<P extends object>(
WrappedComponent: ComponentType<P>
) {
return (props: PropsWithChildren<P>) => {
const [isClient, setIsClient] = useState(false);

useEffect(() => {
setIsClient(typeof window !== 'undefined');
}, []);

if (!isClient) {
return null;
}

return <WrappedComponent {...props} />;
};
}

export default withClientSideRendering;
35 changes: 7 additions & 28 deletions src/index.tsx
@@ -1,34 +1,11 @@
import React, { FC, useState } from 'react';
import React, { FC, useMemo } from 'react';
import { ReactP5Wrapper } from 'react-p5-wrapper';

import sketch from './sketch/index.js';
import { TextParticlesProps } from './types';
import { ParticleState } from './types';
import useParticleConfig from './hooks/useParticleConfig';

export const TextParticles: FC<TextParticlesProps> = ({
text = 'Halil Atilla',
textSize = 160,
flow = 0.3,
topSpeed = 100,
lifeSpan = 2000,
flowOffset = 0,
gravity = { direction: 90, force: 0 },
canvas = { width: 880, height: 300, bg: '#161c1e' },
colorSet = ['#fbbf24', '#e91e63', '#60a5fa', '#673ab7', '#65a30d'],
}) => {
const [state] = useState({
colorSet,
config: {
text,
textSize,
flow,
topSpeed,
lifeSpan,
flowOffset,
gravity,
canvas,
},
sketch,
});
export const TextParticles: FC<ParticleState> = (props) => {
const state = useMemo(() => useParticleConfig(props), [props]);

return (
<ReactP5Wrapper
Expand All @@ -38,3 +15,5 @@ export const TextParticles: FC<TextParticlesProps> = ({
/>
);
};

export default React.memo(TextParticles);
114 changes: 63 additions & 51 deletions src/sketch/index.js
@@ -1,11 +1,6 @@
/* eslint-disable no-multi-assign */
/* eslint-disable no-plusplus */
/* eslint-disable no-underscore-dangle */
/* eslint-disable no-param-reassign */

import Particle from './particle';

export default function sketch(p5) {
const sketch = (p5) => {
let particles = [];
let field = [];
let fieldStep;
Expand All @@ -14,15 +9,17 @@ export default function sketch(p5) {
let colorSet = [];

p5.setup = () => {
p5.createCanvas(config?.canvas?.width, config?.canvas?.height);
setGravity();
init();
p5.frameRate(60);
p5.noStroke();
p5.colorMode(p5.HSL, 100);
if (config) {
p5.createCanvas(config?.canvas?.width, config?.canvas?.height);
p5.colorMode(p5.HSL, 100);
p5.frameRate(60);
p5.noStroke();
setGravity();
init();
}
};

p5.updateWithProps = props => {
p5.updateWithProps = (props) => {
if (props.config) config = props.config;
if (props.colorSet) colorSet = props.colorSet;
p5.setup();
Expand All @@ -32,72 +29,87 @@ export default function sketch(p5) {
p5.clear();
p5.fill(0);
p5.textSize(config?.textSize);
p5.text(config?.text, p5.width / 2, p5.height / 2);
p5.textAlign(p5.CENTER, p5.CENTER);
p5.textStyle(p5.BOLD);
p5.noFill();
particles = [];
let step = p5.floor(
p5.max(p5.width, p5.height) / p5.min(160, p5.min(p5.width, p5.height))
);
p5.text(config?.text, p5.width / 2, p5.height / 2);
particles = createParticles();
field = createField();
p5.clear();
}

function createParticles() {
let tempParticles = [];
let step = calculateStep(160);
let i = 0;
for (let x = 0; x < p5.width; x += step) {
for (let y = 0; y < p5.height; y += step) {
const targetX = x + step / 2;
const targetY = y + step / 2;
const alpha = p5.get(targetX, targetY)[3];
const alpha = p5.get(x + step / 2, y + step / 2)[3];
if (alpha > 0.5) {
particles.push(
new Particle(p5, config, colorSet, targetX, targetY, step * 3, i)
tempParticles.push(
new Particle(
p5,
config,
colorSet,
x + step / 2,
y + step / 2,
step * 3,
i
)
);
i++;
}
}
}
field = [];
p5.clear();
step = fieldStep = p5.floor(
p5.max(p5.width, p5.height) / p5.min(20, p5.min(p5.width, p5.height))
);
i = 0;
return tempParticles;
}

function createField() {
let tempField = [];
let step = (fieldStep = calculateStep(20));
let i = 0;
for (let x = 0; x < p5.width; x += step) {
for (let y = 0; y < p5.height; y += step) {
i++;
const a = p5.noise(i) * p5.TWO_PI;
field[`${x}-${y}`] = a;
p5.translate(x, y);
p5.rotate(a);
p5.rect(-step / 4, -step / 2, step / 2, step);
p5.resetMatrix();
tempField[`${x}-${y}`] = a;
}
}
return tempField;
}

p5.clear();
function calculateStep(min) {
return p5.floor(
p5.max(p5.width, p5.height) / p5.min(min, p5.min(p5.width, p5.height))
);
}

function setGravity() {
gravity = p5.createVector(
p5.radians(config?.gravity?.direction),
config?.gravity?.force
);
}

p5.draw = () => {
p5.draw = () => {
if (config) {
p5.background(config?.canvas?.bg || 'white');
particles.forEach(particle => {
particles.forEach((particle) => {
particle.addForce(gravity);
particle.addForce(
p5.constructor.Vector.fromAngle(
p5.createVector(
field[
`${particle.position.x -
(particle.position.x % fieldStep)}-${particle.position.y -
(particle.position.y % fieldStep)}`
`${Math.floor(particle.position.x / fieldStep) * fieldStep}-${
Math.floor(particle.position.y / fieldStep) * fieldStep
}`
] + config?.flowOffset,
config?.flow
)
);
particle.update();
particle.display();
});
};
}
}
};
};

function setGravity() {
gravity = p5.constructor.Vector.fromAngle(
p5.radians(config?.gravity?.direction),
config?.gravity.force
);
}
}
export default sketch;
33 changes: 14 additions & 19 deletions src/sketch/particle.js
@@ -1,10 +1,10 @@
export default class Particle {
constructor(p5, config, colorSet, x, y, size, index) {
constructor(p5, config, colorSet, x, y, size, index = 0) {
this.p5 = p5;
this.config = config;
this.colorSet = colorSet;
this.baseSize = size;
this.index = index || 0;
this.index = index;
this.spawn = this.p5.createVector(x, y);
this.init();
}
Expand All @@ -18,39 +18,33 @@ export default class Particle {
this.duration = this.config?.lifeSpan * this.p5.random(0.2, 1.2);
this.drag = this.p5.random(0.9, 1);
this.addForce(
this.p5.constructor.Vector.fromAngle(
this.p5.random(this.p5.TWO_PI),
this.p5.random(10)
)
this.p5.createVector(this.p5.random(this.p5.TWO_PI), this.p5.random(10))
);
this.color = this.p5.random(this.colorSet);
}

display() {
let s = 1;
if (this.p5.millis() - this.start < this.duration * 0.1) {
s = this.p5.map(
this.p5.millis() - this.start,
0,
this.duration * 0.1,
0,
1
);
} else if (this.p5.millis() - this.start > this.duration * 0.5) {
s = this.p5.map(
this.p5.millis() - this.start,
const elapsed = this.p5.millis() - this.start;
let sizeMultiplier = 1;

if (elapsed < this.duration * 0.1) {
sizeMultiplier = this.p5.map(elapsed, 0, this.duration * 0.1, 0, 1);
} else if (elapsed > this.duration * 0.5) {
sizeMultiplier = this.p5.map(
elapsed,
this.duration * 0.5,
this.duration,
1,
0
);
}

this.p5.fill(this.color);
this.p5.circle(
this.position.x,
this.position.y,
this.size *
s *
sizeMultiplier *
this.p5.map(this.velocity.mag(), 0, this.config?.topSpeed, 0.5, 1.2)
);
}
Expand All @@ -61,6 +55,7 @@ export default class Particle {
this.velocity.mult(this.drag);
this.position.add(this.velocity.copy().mult(1 / this.p5._targetFrameRate));
this.acceleration.mult(0);

if (
this.position.y > this.p5.height ||
this.p5.millis() - this.start > this.duration
Expand Down
25 changes: 14 additions & 11 deletions src/types.ts
@@ -1,18 +1,21 @@
export interface TextParticlesProps {
export interface ParticleState {
colorSet: string[];
config: {
text: string;
textSize: number;
flow?: number;
topSpeed?: number;
lifeSpan?: number;
flowOffset?: number;
gravity?: {
direction?: number;
force?: number;
flow: number;
topSpeed: number;
lifeSpan: number;
flowOffset: number;
gravity: {
direction: number;
force: number;
};
canvas: {
width: number;
height: number;
bg?: string;
bg: string;
};
colorSet?: string[];
}
};
sketch: (p5: any) => void;
}

0 comments on commit 2dddf6a

Please sign in to comment.