|
1 | 1 | import React, { useLayoutEffect, useRef, useState } from "react";
|
2 |
| -import { Planet } from "src/astres/Planet"; |
3 |
| -import { Star } from "src/astres/Star"; |
4 |
| -import { Galaxy } from "src/astres/Galaxy"; |
5 |
| -import { parseColor } from "src/utils/parseColor"; |
6 |
| -import { Sun } from "src/astres/Sun"; |
7 |
| -import { Nebula } from "src/astres/Nebula"; |
8 |
| -import { AstreDescription } from "src/astres/types"; |
9 |
| -import { Astre } from "src/astres/Astre"; |
10 | 2 | import { generateStars } from "src/utils/starGenerator";
|
11 | 3 | import { generateNebulas } from "src/utils/generateNebulas";
|
12 | 4 | import { generateComet } from "src/utils/generateComet";
|
13 | 5 | import { SystemConfig } from "src/types";
|
14 |
| - |
15 |
| -const DEFAULT_CONFIG = { |
16 |
| - astres: [] as AstreDescription[], |
17 |
| - cometFrequence: 1, |
18 |
| - scale: 0.8, |
19 |
| - speed: 0.3, |
20 |
| - starsCount: 150, |
21 |
| - starsColor: "#FFFFFF", |
22 |
| - starsRotationSpeed: 5, |
23 |
| - nebulasIntensity: 6, |
24 |
| - nebulasColors: ["rgb(5,63,157)", "rgb(42,112,25)", "rgb(182,41,44)"], |
25 |
| -}; |
| 6 | +import { DEFAULT_CONFIG } from "src/DEFAULT_CONFIG"; |
| 7 | +import { drawAstres } from "src/draw"; |
26 | 8 |
|
27 | 9 | export const ReactNebula = ({ config = {} }: { config?: SystemConfig }) => {
|
28 | 10 | const filledConfig = Object.assign({}, DEFAULT_CONFIG, config);
|
29 | 11 | const canvasRef = useRef<HTMLCanvasElement>(null);
|
30 |
| - const [iter, setIter] = useState(0); |
| 12 | + const bgCanvasRef = useRef<HTMLCanvasElement>(null); |
| 13 | + const wrapperRef = useRef<HTMLDivElement>(null); |
| 14 | + const [size, setSize] = useState({ height: 0, width: 0 }); |
31 | 15 |
|
32 | 16 | useLayoutEffect(() => {
|
33 | 17 | const handler = () => {
|
34 |
| - setIter(iter + 1); |
| 18 | + setSize({ |
| 19 | + height: wrapperRef.current?.offsetHeight ?? 0, |
| 20 | + width: wrapperRef.current?.offsetWidth ?? 0, |
| 21 | + }); |
35 | 22 | };
|
36 |
| - if (!window) return; |
| 23 | + handler(); |
| 24 | + if (typeof window === "undefined") return; |
37 | 25 | window.addEventListener("resize", handler);
|
38 | 26 | return () => {
|
39 | 27 | window.removeEventListener("resize", handler);
|
40 | 28 | };
|
41 |
| - }, [iter]); |
| 29 | + }, [setSize]); |
42 | 30 |
|
43 | 31 | useLayoutEffect(() => {
|
44 |
| - if (!canvasRef.current) return; |
45 |
| - const canvas = canvasRef.current; |
46 |
| - |
47 |
| - const width = canvas.width; |
48 |
| - const height = canvas.height; |
49 |
| - |
50 |
| - const ctx = canvas.getContext("2d"); |
51 |
| - if (!ctx) return; |
52 |
| - |
53 |
| - const planets: Record<string, Astre> = {}; |
| 32 | + return drawAstres({ |
| 33 | + astresConfig: [ |
| 34 | + ...generateStars({ |
| 35 | + rotationSpeed: filledConfig.starsRotationSpeed, |
| 36 | + count: filledConfig.starsCount, |
| 37 | + color: filledConfig.starsColor, |
| 38 | + }), |
| 39 | + ...generateComet({ |
| 40 | + frequence: filledConfig.cometFrequence, |
| 41 | + }), |
| 42 | + ...filledConfig.astres, |
| 43 | + ], |
| 44 | + config: filledConfig, |
| 45 | + canvas: canvasRef.current as HTMLCanvasElement, |
| 46 | + play: true, |
| 47 | + }); |
| 48 | + }, [size]); |
54 | 49 |
|
55 |
| - const astres = [ |
56 |
| - ...generateStars({ |
57 |
| - rotationSpeed: filledConfig.starsRotationSpeed, |
58 |
| - count: filledConfig.starsCount, |
59 |
| - color: filledConfig.starsColor, |
60 |
| - }), |
61 |
| - ...generateNebulas({ |
| 50 | + useLayoutEffect(() => { |
| 51 | + return drawAstres({ |
| 52 | + astresConfig: generateNebulas({ |
62 | 53 | intensity: filledConfig.nebulasIntensity,
|
63 | 54 | colors: filledConfig.nebulasColors,
|
64 | 55 | }),
|
65 |
| - ...generateComet({ |
66 |
| - frequence: filledConfig.cometFrequence, |
67 |
| - }), |
68 |
| - ...filledConfig.astres, |
69 |
| - ]; |
70 |
| - |
71 |
| - astres.forEach((astreConfig) => { |
72 |
| - const Type = { |
73 |
| - star: Star, |
74 |
| - galaxy: Galaxy, |
75 |
| - planet: Planet, |
76 |
| - sun: Sun, |
77 |
| - nebula: Nebula, |
78 |
| - }[astreConfig.type]; |
79 |
| - planets[astreConfig.name] = new Type({ |
80 |
| - ctx, |
81 |
| - ...astreConfig, |
82 |
| - distance: astreConfig.distance * filledConfig.scale, |
83 |
| - rgb: parseColor(astreConfig.color), |
84 |
| - width: astreConfig.width * filledConfig.scale, |
85 |
| - origin: astreConfig.origin ? planets[astreConfig.origin] : undefined, |
86 |
| - rotateSpeed: astreConfig.rotateSpeed * filledConfig.speed, |
87 |
| - }); |
| 56 | + config: filledConfig, |
| 57 | + canvas: bgCanvasRef.current as HTMLCanvasElement, |
| 58 | + play: false, |
| 59 | + bgColor: "rgb(8, 8, 8)", |
88 | 60 | });
|
| 61 | + }, [size]); |
89 | 62 |
|
90 |
| - ctx.save(); |
91 |
| - |
92 |
| - let animation: number | undefined; |
93 |
| - const drawCtx = () => { |
94 |
| - ctx.clearRect(0, 0, width, height); |
95 |
| - ctx.fillStyle = "rgb(8, 8, 8)"; |
96 |
| - ctx.fillRect(0, 0, width, height); |
97 |
| - Object.values(planets).forEach((planet) => planet.draw()); |
98 |
| - animation = requestAnimationFrame(drawCtx); |
99 |
| - }; |
100 |
| - |
101 |
| - drawCtx(); |
102 |
| - |
103 |
| - return () => { |
104 |
| - ctx.restore(); |
105 |
| - if (animation) { |
106 |
| - cancelAnimationFrame(animation); |
107 |
| - } |
108 |
| - }; |
109 |
| - }, [iter]); |
110 |
| - |
111 |
| - if (!window) return <div></div>; |
112 | 63 | return (
|
113 | 64 | <div
|
| 65 | + ref={wrapperRef} |
114 | 66 | style={{
|
115 | 67 | overflow: "hidden",
|
116 | 68 | background: "#0a1929",
|
117 | 69 | height: "100%",
|
118 | 70 | width: "100%",
|
119 |
| - position: "relative", |
| 71 | + position: "absolute", |
120 | 72 | }}
|
121 | 73 | >
|
122 | 74 | <canvas
|
123 |
| - width={window.innerWidth} |
124 |
| - height={window.innerHeight} |
125 |
| - style={{ height: "100%", width: "100%" }} |
| 75 | + width={size.width * 2} |
| 76 | + height={size.height * 2} |
| 77 | + style={{ height: "100%", width: "100%", position: "absolute" }} |
| 78 | + ref={bgCanvasRef} |
| 79 | + /> |
| 80 | + <canvas |
| 81 | + width={size.width * 2} |
| 82 | + height={size.height * 2} |
| 83 | + style={{ height: "100%", width: "100%", position: "absolute" }} |
126 | 84 | ref={canvasRef}
|
127 | 85 | />
|
128 | 86 | </div>
|
|
0 commit comments