UNPKG

8.22 kBJavaScriptView Raw
1import { Container } from "./Container";
2import { Constants, itemFromArray } from "../Utils";
3const tsParticlesDom = [];
4function fetchError(statusCode) {
5 console.error(`Error tsParticles - fetch status: ${statusCode}`);
6 console.error("Error tsParticles - File config not found");
7}
8/**
9 * Main class for creating the [[Container]] objects
10 * @category Core
11 */
12export class Loader {
13 /**
14 * All the [[Container]] objects loaded
15 */
16 static dom() {
17 return tsParticlesDom;
18 }
19 /**
20 * Retrieves a [[Container]] from all the objects loaded
21 * @param index the object index
22 */
23 static domItem(index) {
24 const dom = Loader.dom();
25 const item = dom[index];
26 if (item && !item.destroyed) {
27 return item;
28 }
29 dom.splice(index, 1);
30 }
31 static async loadOptions(params) {
32 var _a, _b, _c;
33 const tagId = (_a = params.tagId) !== null && _a !== void 0 ? _a : `tsparticles${Math.floor(Math.random() * 10000)}`;
34 const { options, index } = params;
35 /* elements */
36 let domContainer = (_b = params.element) !== null && _b !== void 0 ? _b : document.getElementById(tagId);
37 if (!domContainer) {
38 domContainer = document.createElement("div");
39 domContainer.id = tagId;
40 (_c = document.querySelector("body")) === null || _c === void 0 ? void 0 : _c.append(domContainer);
41 }
42 const currentOptions = options instanceof Array ? itemFromArray(options, index) : options;
43 const dom = Loader.dom();
44 const oldIndex = dom.findIndex((v) => v.id === tagId);
45 if (oldIndex >= 0) {
46 const old = Loader.domItem(oldIndex);
47 if (old && !old.destroyed) {
48 old.destroy();
49 dom.splice(oldIndex, 1);
50 }
51 }
52 let canvasEl;
53 let generatedCanvas;
54 if (domContainer.tagName.toLowerCase() === "canvas") {
55 canvasEl = domContainer;
56 generatedCanvas = false;
57 }
58 else {
59 const existingCanvases = domContainer.getElementsByTagName("canvas");
60 /* get existing canvas if present, otherwise a new one will be created */
61 if (existingCanvases.length) {
62 canvasEl = existingCanvases[0];
63 if (!canvasEl.className) {
64 canvasEl.className = Constants.canvasClass;
65 }
66 generatedCanvas = false;
67 }
68 else {
69 generatedCanvas = true;
70 /* create canvas element */
71 canvasEl = document.createElement("canvas");
72 canvasEl.className = Constants.canvasClass;
73 /* set size canvas */
74 canvasEl.style.width = "100%";
75 canvasEl.style.height = "100%";
76 /* append canvas */
77 domContainer.appendChild(canvasEl);
78 }
79 }
80 /* launch tsParticles */
81 const newItem = new Container(tagId, currentOptions);
82 if (oldIndex >= 0) {
83 dom.splice(oldIndex, 0, newItem);
84 }
85 else {
86 dom.push(newItem);
87 }
88 newItem.canvas.loadCanvas(canvasEl, generatedCanvas);
89 await newItem.start();
90 return newItem;
91 }
92 static async loadRemoteOptions(params) {
93 const { url: jsonUrl, index } = params;
94 const url = jsonUrl instanceof Array ? itemFromArray(jsonUrl, index) : jsonUrl;
95 if (!url) {
96 return;
97 }
98 const response = await fetch(url);
99 if (!response.ok) {
100 fetchError(response.status);
101 return;
102 }
103 const data = await response.json();
104 return await Loader.loadOptions({
105 tagId: params.tagId,
106 element: params.element,
107 index,
108 options: data,
109 });
110 }
111 /**
112 * Loads the provided options to create a [[Container]] object.
113 * @param tagId the particles container element id
114 * @param options the options object to initialize the [[Container]]
115 * @param index if an options array is provided, this will retrieve the exact index of that array
116 */
117 static load(tagId, options, index) {
118 const params = { index };
119 if (typeof tagId === "string") {
120 params.tagId = tagId;
121 }
122 else {
123 params.options = tagId;
124 }
125 if (typeof options === "number") {
126 params.index = options !== null && options !== void 0 ? options : params.index;
127 }
128 else {
129 params.options = options !== null && options !== void 0 ? options : params.options;
130 }
131 return this.loadOptions(params);
132 }
133 /**
134 * Loads the provided options to create a [[Container]] object.
135 * @param id the particles container element id
136 * @param domContainer the dom container
137 * @param options the options object to initialize the [[Container]]
138 * @param index if an options array is provided, this will retrieve the exact index of that array
139 */
140 static async set(id, domContainer, options, index) {
141 const params = { index };
142 if (typeof id === "string") {
143 params.tagId = id;
144 }
145 else {
146 params.element = id;
147 }
148 if (domContainer instanceof HTMLElement) {
149 params.element = domContainer;
150 }
151 else {
152 params.options = domContainer;
153 }
154 if (typeof options === "number") {
155 params.index = options;
156 }
157 else {
158 params.options = options !== null && options !== void 0 ? options : params.options;
159 }
160 return this.loadOptions(params);
161 }
162 /**
163 * Loads the provided json with a GET request. The content will be used to create a [[Container]] object.
164 * This method is async, so if you need a callback refer to JavaScript function `fetch`
165 * @param tagId the particles container element id
166 * @param jsonUrl the json path (or paths array) to use in the GET request
167 * @param index the index of the paths array, if a single path is passed this value is ignored
168 * @returns A Promise with the [[Container]] object created
169 */
170 static async loadJSON(tagId, jsonUrl, index) {
171 let url, id;
172 if (typeof jsonUrl === "number" || jsonUrl === undefined) {
173 url = tagId;
174 }
175 else {
176 id = tagId;
177 url = jsonUrl;
178 }
179 return await Loader.loadRemoteOptions({ tagId: id, url, index });
180 }
181 /**
182 * Loads the provided json with a GET request. The content will be used to create a [[Container]] object.
183 * This method is async, so if you need a callback refer to JavaScript function `fetch`
184 * @param id the particles container element id
185 * @param domContainer the container used to contains the particles
186 * @param jsonUrl the json path (or paths array) to use in the GET request
187 * @param index the index of the paths array, if a single path is passed this value is ignored
188 * @returns A Promise with the [[Container]] object created
189 */
190 static async setJSON(id, domContainer, jsonUrl, index) {
191 let url, newId, newIndex, element;
192 if (id instanceof HTMLElement) {
193 element = id;
194 url = domContainer;
195 newIndex = jsonUrl;
196 }
197 else {
198 newId = id;
199 element = domContainer;
200 url = jsonUrl;
201 newIndex = index;
202 }
203 return await Loader.loadRemoteOptions({ tagId: newId, url, index: newIndex, element });
204 }
205 /**
206 * Adds an additional click handler to all the loaded [[Container]] objects.
207 * @param callback the function called after the click event is fired
208 */
209 static setOnClickHandler(callback) {
210 const dom = Loader.dom();
211 if (dom.length === 0) {
212 throw new Error("Can only set click handlers after calling tsParticles.load() or tsParticles.loadJSON()");
213 }
214 for (const domItem of dom) {
215 domItem.addClickHandler(callback);
216 }
217 }
218}