├── .gitignore
├── LICENSE
├── README.md
├── package-lock.json
├── package.json
├── public
├── favicon.ico
├── index.html
├── logo192.png
├── logo512.png
├── manifest.json
├── particles.js
├── robots.txt
└── web-programming.svg
├── screenshots
├── convex_instruct.gif
├── frontpage.png
├── pathfinder.gif
└── sorting.gif
└── src
├── App.css
├── App.js
├── App.test.js
├── assets
├── Anurati-Regular.otf
├── analytics.svg
├── asteroid.svg
├── bar-chart.svg
├── convex.svg
├── convex_hull.png
├── convex_instruct.gif
├── github.svg
├── graph.svg
├── heading_logo.png
├── linkedin.svg
├── particles.json
├── pathfinder.gif
├── pathfinding_front.svg
├── planet.svg
├── sorting.png
└── space-ship.svg
├── components
├── ConvexHull
│ └── ConvexHull.js
├── Home.js
├── Instructions
│ ├── Instruct.js
│ └── modal.css
├── Pathfinding
│ ├── Node.js
│ ├── Pathfinding.js
│ └── algorithms
│ │ ├── Dijkstra.js
│ │ └── astar.js
└── Sorting
│ ├── Sorting.js
│ └── algorithms
│ ├── MergeSort.js
│ ├── QuickSort.js
│ └── SelectionSort.js
├── index.css
├── index.js
├── logo.svg
├── serviceWorker.js
├── setupTests.js
└── styles
├── ConvexHull.css
├── Home.css
├── Pathfinding.css
└── Sorting.css
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 |
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Arnab Ray
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | ##
7 |
8 | Fascinated with DS and Algorithm?!!
9 | This website can be used to visualize multiple algorithms which includes Sorting, Pathfinding and ConvexHull. You can access it here:
10 | https://algorithm-visualizer.vercel.app/
11 |
12 |  [](https://github.com/arnabuchiha/Algorithm-Visualizer/blob/master/LICENSE)
13 |
14 |
15 | ## Algorithms
16 |
17 | - ### Sorting
18 |
19 | - Selection Sort
20 | - Merge Sort
21 | - Quick Sort
22 |
23 |
24 |
25 | - ### Pathfinding
26 | - Dijkstra's algorithm
27 |
28 |
29 |
30 | - ### ConvexHull
31 | - Graham's Scan
32 |
33 |
34 |
35 |
36 | ## Installation
37 |
38 | - Install Node on your computer
39 | - Clone this repository and the backend repository from here .
40 | - Open CMD on your computer and change the directory to the place where you cloned the front-end repository.
41 | - Run the command **npm install** to install all the necessary packages from node server.
42 | - Now run the command **npm start** to run the app on your localhost.
43 | - Run the app live on **localhost:3000**
44 |
45 |
46 | Show some love ❤️ and Star ⭐️ the Repository to support the project.
47 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "algo-visualizer",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@material-ui/core": "^4.11.0",
7 | "@testing-library/jest-dom": "^4.2.4",
8 | "@testing-library/react": "^9.5.0",
9 | "@testing-library/user-event": "^7.2.1",
10 | "collections": "^5.1.11",
11 | "framer-motion": "^2.6.15",
12 | "js-priority-queue": "^0.1.5",
13 | "particles.js": "^2.0.0",
14 | "react": "^16.13.1",
15 | "react-dom": "^16.13.1",
16 | "react-router-dom": "^5.2.0",
17 | "react-scripts": "3.4.3"
18 | },
19 | "scripts": {
20 | "start": "react-scripts start",
21 | "build": "react-scripts build",
22 | "test": "react-scripts test",
23 | "eject": "react-scripts eject"
24 | },
25 | "eslintConfig": {
26 | "extends": "react-app"
27 | },
28 | "browserslist": {
29 | "production": [
30 | ">0.2%",
31 | "not dead",
32 | "not op_mini all"
33 | ],
34 | "development": [
35 | "last 1 chrome version",
36 | "last 1 firefox version",
37 | "last 1 safari version"
38 | ]
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arnabuchiha/Algorithm-Visualizer/a19a588b18af38bff2a07341f9ed0cd09e131d2f/public/favicon.ico
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
14 |
15 |
19 |
20 |
29 | Algorithm Visualizer
30 |
31 |
32 | You need to enable JavaScript to run this app.
33 |
34 |
35 |
36 |
37 |
38 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/public/logo192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arnabuchiha/Algorithm-Visualizer/a19a588b18af38bff2a07341f9ed0cd09e131d2f/public/logo192.png
--------------------------------------------------------------------------------
/public/logo512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arnabuchiha/Algorithm-Visualizer/a19a588b18af38bff2a07341f9ed0cd09e131d2f/public/logo512.png
--------------------------------------------------------------------------------
/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "Algorithm Visualizer",
3 | "name": "Algorithm Visualizer",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | },
10 | {
11 | "src": "logo192.png",
12 | "type": "image/png",
13 | "sizes": "192x192"
14 | },
15 | {
16 | "src": "logo512.png",
17 | "type": "image/png",
18 | "sizes": "512x512"
19 | }
20 | ],
21 | "start_url": ".",
22 | "display": "standalone",
23 | "theme_color": "#000000",
24 | "background_color": "#ffffff"
25 | }
26 |
--------------------------------------------------------------------------------
/public/particles.js:
--------------------------------------------------------------------------------
1 | /* -----------------------------------------------
2 | /* Author : Vincent Garreau - vincentgarreau.com
3 | /* MIT license: http://opensource.org/licenses/MIT
4 | /* Demo / Generator : vincentgarreau.com/particles.js
5 | /* GitHub : github.com/VincentGarreau/particles.js
6 | /* How to use? : Check the GitHub README
7 | /* v2.0.0
8 | /* ----------------------------------------------- */
9 |
10 | var pJS = function(tag_id, params){
11 |
12 | var canvas_el = document.querySelector('#'+tag_id+' > .particles-js-canvas-el');
13 |
14 | /* particles.js variables with default values */
15 | this.pJS = {
16 | canvas: {
17 | el: canvas_el,
18 | w: canvas_el.offsetWidth,
19 | h: canvas_el.offsetHeight
20 | },
21 | particles: {
22 | number: {
23 | value: 400,
24 | density: {
25 | enable: true,
26 | value_area: 800
27 | }
28 | },
29 | color: {
30 | value: '#fff'
31 | },
32 | shape: {
33 | type: 'circle',
34 | stroke: {
35 | width: 0,
36 | color: '#ff0000'
37 | },
38 | polygon: {
39 | nb_sides: 5
40 | },
41 | image: {
42 | src: '',
43 | width: 100,
44 | height: 100
45 | }
46 | },
47 | opacity: {
48 | value: 1,
49 | random: false,
50 | anim: {
51 | enable: false,
52 | speed: 2,
53 | opacity_min: 0,
54 | sync: false
55 | }
56 | },
57 | size: {
58 | value: 20,
59 | random: false,
60 | anim: {
61 | enable: false,
62 | speed: 20,
63 | size_min: 0,
64 | sync: false
65 | }
66 | },
67 | line_linked: {
68 | enable: true,
69 | distance: 100,
70 | color: '#fff',
71 | opacity: 1,
72 | width: 1
73 | },
74 | move: {
75 | enable: true,
76 | speed: 2,
77 | direction: 'none',
78 | random: false,
79 | straight: false,
80 | out_mode: 'out',
81 | bounce: false,
82 | attract: {
83 | enable: false,
84 | rotateX: 3000,
85 | rotateY: 3000
86 | }
87 | },
88 | array: []
89 | },
90 | interactivity: {
91 | detect_on: 'canvas',
92 | events: {
93 | onhover: {
94 | enable: true,
95 | mode: 'grab'
96 | },
97 | onclick: {
98 | enable: true,
99 | mode: 'push'
100 | },
101 | resize: true
102 | },
103 | modes: {
104 | grab:{
105 | distance: 100,
106 | line_linked:{
107 | opacity: 1
108 | }
109 | },
110 | bubble:{
111 | distance: 200,
112 | size: 80,
113 | duration: 0.4
114 | },
115 | repulse:{
116 | distance: 200,
117 | duration: 0.4
118 | },
119 | push:{
120 | particles_nb: 4
121 | },
122 | remove:{
123 | particles_nb: 2
124 | }
125 | },
126 | mouse:{}
127 | },
128 | retina_detect: false,
129 | fn: {
130 | interact: {},
131 | modes: {},
132 | vendors:{}
133 | },
134 | tmp: {}
135 | };
136 |
137 | var pJS = this.pJS;
138 |
139 | /* params settings */
140 | if(params){
141 | Object.deepExtend(pJS, params);
142 | }
143 |
144 | pJS.tmp.obj = {
145 | size_value: pJS.particles.size.value,
146 | size_anim_speed: pJS.particles.size.anim.speed,
147 | move_speed: pJS.particles.move.speed,
148 | line_linked_distance: pJS.particles.line_linked.distance,
149 | line_linked_width: pJS.particles.line_linked.width,
150 | mode_grab_distance: pJS.interactivity.modes.grab.distance,
151 | mode_bubble_distance: pJS.interactivity.modes.bubble.distance,
152 | mode_bubble_size: pJS.interactivity.modes.bubble.size,
153 | mode_repulse_distance: pJS.interactivity.modes.repulse.distance
154 | };
155 |
156 |
157 | pJS.fn.retinaInit = function(){
158 |
159 | if(pJS.retina_detect && window.devicePixelRatio > 1){
160 | pJS.canvas.pxratio = window.devicePixelRatio;
161 | pJS.tmp.retina = true;
162 | }
163 | else{
164 | pJS.canvas.pxratio = 1;
165 | pJS.tmp.retina = false;
166 | }
167 |
168 | pJS.canvas.w = pJS.canvas.el.offsetWidth * pJS.canvas.pxratio;
169 | pJS.canvas.h = pJS.canvas.el.offsetHeight * pJS.canvas.pxratio;
170 |
171 | pJS.particles.size.value = pJS.tmp.obj.size_value * pJS.canvas.pxratio;
172 | pJS.particles.size.anim.speed = pJS.tmp.obj.size_anim_speed * pJS.canvas.pxratio;
173 | pJS.particles.move.speed = pJS.tmp.obj.move_speed * pJS.canvas.pxratio;
174 | pJS.particles.line_linked.distance = pJS.tmp.obj.line_linked_distance * pJS.canvas.pxratio;
175 | pJS.interactivity.modes.grab.distance = pJS.tmp.obj.mode_grab_distance * pJS.canvas.pxratio;
176 | pJS.interactivity.modes.bubble.distance = pJS.tmp.obj.mode_bubble_distance * pJS.canvas.pxratio;
177 | pJS.particles.line_linked.width = pJS.tmp.obj.line_linked_width * pJS.canvas.pxratio;
178 | pJS.interactivity.modes.bubble.size = pJS.tmp.obj.mode_bubble_size * pJS.canvas.pxratio;
179 | pJS.interactivity.modes.repulse.distance = pJS.tmp.obj.mode_repulse_distance * pJS.canvas.pxratio;
180 |
181 | };
182 |
183 |
184 |
185 | /* ---------- pJS functions - canvas ------------ */
186 |
187 | pJS.fn.canvasInit = function(){
188 | pJS.canvas.ctx = pJS.canvas.el.getContext('2d');
189 | };
190 |
191 | pJS.fn.canvasSize = function(){
192 |
193 | pJS.canvas.el.width = pJS.canvas.w;
194 | pJS.canvas.el.height = pJS.canvas.h;
195 |
196 | if(pJS && pJS.interactivity.events.resize){
197 |
198 | window.addEventListener('resize', function(){
199 |
200 | pJS.canvas.w = pJS.canvas.el.offsetWidth;
201 | pJS.canvas.h = pJS.canvas.el.offsetHeight;
202 |
203 | /* resize canvas */
204 | if(pJS.tmp.retina){
205 | pJS.canvas.w *= pJS.canvas.pxratio;
206 | pJS.canvas.h *= pJS.canvas.pxratio;
207 | }
208 |
209 | pJS.canvas.el.width = pJS.canvas.w;
210 | pJS.canvas.el.height = pJS.canvas.h;
211 |
212 | /* repaint canvas on anim disabled */
213 | if(!pJS.particles.move.enable){
214 | pJS.fn.particlesEmpty();
215 | pJS.fn.particlesCreate();
216 | pJS.fn.particlesDraw();
217 | pJS.fn.vendors.densityAutoParticles();
218 | }
219 |
220 | /* density particles enabled */
221 | pJS.fn.vendors.densityAutoParticles();
222 |
223 | });
224 |
225 | }
226 |
227 | };
228 |
229 |
230 | pJS.fn.canvasPaint = function(){
231 | pJS.canvas.ctx.fillRect(0, 0, pJS.canvas.w, pJS.canvas.h);
232 | };
233 |
234 | pJS.fn.canvasClear = function(){
235 | pJS.canvas.ctx.clearRect(0, 0, pJS.canvas.w, pJS.canvas.h);
236 | };
237 |
238 |
239 | /* --------- pJS functions - particles ----------- */
240 |
241 | pJS.fn.particle = function(color, opacity, position){
242 |
243 | /* size */
244 | this.radius = (pJS.particles.size.random ? Math.random() : 1) * pJS.particles.size.value;
245 | if(pJS.particles.size.anim.enable){
246 | this.size_status = false;
247 | this.vs = pJS.particles.size.anim.speed / 100;
248 | if(!pJS.particles.size.anim.sync){
249 | this.vs = this.vs * Math.random();
250 | }
251 | }
252 |
253 | /* position */
254 | this.x = position ? position.x : Math.random() * pJS.canvas.w;
255 | this.y = position ? position.y : Math.random() * pJS.canvas.h;
256 |
257 | /* check position - into the canvas */
258 | if(this.x > pJS.canvas.w - this.radius*2) this.x = this.x - this.radius;
259 | else if(this.x < this.radius*2) this.x = this.x + this.radius;
260 | if(this.y > pJS.canvas.h - this.radius*2) this.y = this.y - this.radius;
261 | else if(this.y < this.radius*2) this.y = this.y + this.radius;
262 |
263 | /* check position - avoid overlap */
264 | if(pJS.particles.move.bounce){
265 | pJS.fn.vendors.checkOverlap(this, position);
266 | }
267 |
268 | /* color */
269 | this.color = {};
270 | if(typeof(color.value) == 'object'){
271 |
272 | if(color.value instanceof Array){
273 | var color_selected = color.value[Math.floor(Math.random() * pJS.particles.color.value.length)];
274 | this.color.rgb = hexToRgb(color_selected);
275 | }else{
276 | if(color.value.r != undefined && color.value.g != undefined && color.value.b != undefined){
277 | this.color.rgb = {
278 | r: color.value.r,
279 | g: color.value.g,
280 | b: color.value.b
281 | }
282 | }
283 | if(color.value.h != undefined && color.value.s != undefined && color.value.l != undefined){
284 | this.color.hsl = {
285 | h: color.value.h,
286 | s: color.value.s,
287 | l: color.value.l
288 | }
289 | }
290 | }
291 |
292 | }
293 | else if(color.value == 'random'){
294 | this.color.rgb = {
295 | r: (Math.floor(Math.random() * (255 - 0 + 1)) + 0),
296 | g: (Math.floor(Math.random() * (255 - 0 + 1)) + 0),
297 | b: (Math.floor(Math.random() * (255 - 0 + 1)) + 0)
298 | }
299 | }
300 | else if(typeof(color.value) == 'string'){
301 | this.color = color;
302 | this.color.rgb = hexToRgb(this.color.value);
303 | }
304 |
305 | /* opacity */
306 | this.opacity = (pJS.particles.opacity.random ? Math.random() : 1) * pJS.particles.opacity.value;
307 | if(pJS.particles.opacity.anim.enable){
308 | this.opacity_status = false;
309 | this.vo = pJS.particles.opacity.anim.speed / 100;
310 | if(!pJS.particles.opacity.anim.sync){
311 | this.vo = this.vo * Math.random();
312 | }
313 | }
314 |
315 | /* animation - velocity for speed */
316 | var velbase = {}
317 | switch(pJS.particles.move.direction){
318 | case 'top':
319 | velbase = { x:0, y:-1 };
320 | break;
321 | case 'top-right':
322 | velbase = { x:0.5, y:-0.5 };
323 | break;
324 | case 'right':
325 | velbase = { x:1, y:-0 };
326 | break;
327 | case 'bottom-right':
328 | velbase = { x:0.5, y:0.5 };
329 | break;
330 | case 'bottom':
331 | velbase = { x:0, y:1 };
332 | break;
333 | case 'bottom-left':
334 | velbase = { x:-0.5, y:1 };
335 | break;
336 | case 'left':
337 | velbase = { x:-1, y:0 };
338 | break;
339 | case 'top-left':
340 | velbase = { x:-0.5, y:-0.5 };
341 | break;
342 | default:
343 | velbase = { x:0, y:0 };
344 | break;
345 | }
346 |
347 | if(pJS.particles.move.straight){
348 | this.vx = velbase.x;
349 | this.vy = velbase.y;
350 | if(pJS.particles.move.random){
351 | this.vx = this.vx * (Math.random());
352 | this.vy = this.vy * (Math.random());
353 | }
354 | }else{
355 | this.vx = velbase.x + Math.random()-0.5;
356 | this.vy = velbase.y + Math.random()-0.5;
357 | }
358 |
359 | // var theta = 2.0 * Math.PI * Math.random();
360 | // this.vx = Math.cos(theta);
361 | // this.vy = Math.sin(theta);
362 |
363 | this.vx_i = this.vx;
364 | this.vy_i = this.vy;
365 |
366 |
367 |
368 | /* if shape is image */
369 |
370 | var shape_type = pJS.particles.shape.type;
371 | if(typeof(shape_type) == 'object'){
372 | if(shape_type instanceof Array){
373 | var shape_selected = shape_type[Math.floor(Math.random() * shape_type.length)];
374 | this.shape = shape_selected;
375 | }
376 | }else{
377 | this.shape = shape_type;
378 | }
379 |
380 | if(this.shape == 'image'){
381 | var sh = pJS.particles.shape;
382 | this.img = {
383 | src: sh.image.src,
384 | ratio: sh.image.width / sh.image.height
385 | }
386 | if(!this.img.ratio) this.img.ratio = 1;
387 | if(pJS.tmp.img_type == 'svg' && pJS.tmp.source_svg != undefined){
388 | pJS.fn.vendors.createSvgImg(this);
389 | if(pJS.tmp.pushing){
390 | this.img.loaded = false;
391 | }
392 | }
393 | }
394 |
395 |
396 |
397 | };
398 |
399 |
400 | pJS.fn.particle.prototype.draw = function() {
401 |
402 | var p = this;
403 |
404 | if(p.radius_bubble != undefined){
405 | var radius = p.radius_bubble;
406 | }else{
407 | var radius = p.radius;
408 | }
409 |
410 | if(p.opacity_bubble != undefined){
411 | var opacity = p.opacity_bubble;
412 | }else{
413 | var opacity = p.opacity;
414 | }
415 |
416 | if(p.color.rgb){
417 | var color_value = 'rgba('+p.color.rgb.r+','+p.color.rgb.g+','+p.color.rgb.b+','+opacity+')';
418 | }else{
419 | var color_value = 'hsla('+p.color.hsl.h+','+p.color.hsl.s+'%,'+p.color.hsl.l+'%,'+opacity+')';
420 | }
421 |
422 | pJS.canvas.ctx.fillStyle = color_value;
423 | pJS.canvas.ctx.beginPath();
424 |
425 | switch(p.shape){
426 |
427 | case 'circle':
428 | pJS.canvas.ctx.arc(p.x, p.y, radius, 0, Math.PI * 2, false);
429 | break;
430 |
431 | case 'edge':
432 | pJS.canvas.ctx.rect(p.x-radius, p.y-radius, radius*2, radius*2);
433 | break;
434 |
435 | case 'triangle':
436 | pJS.fn.vendors.drawShape(pJS.canvas.ctx, p.x-radius, p.y+radius / 1.66, radius*2, 3, 2);
437 | break;
438 |
439 | case 'polygon':
440 | pJS.fn.vendors.drawShape(
441 | pJS.canvas.ctx,
442 | p.x - radius / (pJS.particles.shape.polygon.nb_sides/3.5), // startX
443 | p.y - radius / (2.66/3.5), // startY
444 | radius*2.66 / (pJS.particles.shape.polygon.nb_sides/3), // sideLength
445 | pJS.particles.shape.polygon.nb_sides, // sideCountNumerator
446 | 1 // sideCountDenominator
447 | );
448 | break;
449 |
450 | case 'star':
451 | pJS.fn.vendors.drawShape(
452 | pJS.canvas.ctx,
453 | p.x - radius*2 / (pJS.particles.shape.polygon.nb_sides/4), // startX
454 | p.y - radius / (2*2.66/3.5), // startY
455 | radius*2*2.66 / (pJS.particles.shape.polygon.nb_sides/3), // sideLength
456 | pJS.particles.shape.polygon.nb_sides, // sideCountNumerator
457 | 2 // sideCountDenominator
458 | );
459 | break;
460 |
461 | case 'image':
462 |
463 | function draw(){
464 | pJS.canvas.ctx.drawImage(
465 | img_obj,
466 | p.x-radius,
467 | p.y-radius,
468 | radius*2,
469 | radius*2 / p.img.ratio
470 | );
471 | }
472 |
473 | if(pJS.tmp.img_type == 'svg'){
474 | var img_obj = p.img.obj;
475 | }else{
476 | var img_obj = pJS.tmp.img_obj;
477 | }
478 |
479 | if(img_obj){
480 | draw();
481 | }
482 |
483 | break;
484 |
485 | }
486 |
487 | pJS.canvas.ctx.closePath();
488 |
489 | if(pJS.particles.shape.stroke.width > 0){
490 | pJS.canvas.ctx.strokeStyle = pJS.particles.shape.stroke.color;
491 | pJS.canvas.ctx.lineWidth = pJS.particles.shape.stroke.width;
492 | pJS.canvas.ctx.stroke();
493 | }
494 |
495 | pJS.canvas.ctx.fill();
496 |
497 | };
498 |
499 |
500 | pJS.fn.particlesCreate = function(){
501 | for(var i = 0; i < pJS.particles.number.value; i++) {
502 | pJS.particles.array.push(new pJS.fn.particle(pJS.particles.color, pJS.particles.opacity.value));
503 | }
504 | };
505 |
506 | pJS.fn.particlesUpdate = function(){
507 |
508 | for(var i = 0; i < pJS.particles.array.length; i++){
509 |
510 | /* the particle */
511 | var p = pJS.particles.array[i];
512 |
513 | // var d = ( dx = pJS.interactivity.mouse.click_pos_x - p.x ) * dx + ( dy = pJS.interactivity.mouse.click_pos_y - p.y ) * dy;
514 | // var f = -BANG_SIZE / d;
515 | // if ( d < BANG_SIZE ) {
516 | // var t = Math.atan2( dy, dx );
517 | // p.vx = f * Math.cos(t);
518 | // p.vy = f * Math.sin(t);
519 | // }
520 |
521 | /* move the particle */
522 | if(pJS.particles.move.enable){
523 | var ms = pJS.particles.move.speed/2;
524 | p.x += p.vx * ms;
525 | p.y += p.vy * ms;
526 | }
527 |
528 | /* change opacity status */
529 | if(pJS.particles.opacity.anim.enable) {
530 | if(p.opacity_status == true) {
531 | if(p.opacity >= pJS.particles.opacity.value) p.opacity_status = false;
532 | p.opacity += p.vo;
533 | }else {
534 | if(p.opacity <= pJS.particles.opacity.anim.opacity_min) p.opacity_status = true;
535 | p.opacity -= p.vo;
536 | }
537 | if(p.opacity < 0) p.opacity = 0;
538 | }
539 |
540 | /* change size */
541 | if(pJS.particles.size.anim.enable){
542 | if(p.size_status == true){
543 | if(p.radius >= pJS.particles.size.value) p.size_status = false;
544 | p.radius += p.vs;
545 | }else{
546 | if(p.radius <= pJS.particles.size.anim.size_min) p.size_status = true;
547 | p.radius -= p.vs;
548 | }
549 | if(p.radius < 0) p.radius = 0;
550 | }
551 |
552 | /* change particle position if it is out of canvas */
553 | if(pJS.particles.move.out_mode == 'bounce'){
554 | var new_pos = {
555 | x_left: p.radius,
556 | x_right: pJS.canvas.w,
557 | y_top: p.radius,
558 | y_bottom: pJS.canvas.h
559 | }
560 | }else{
561 | var new_pos = {
562 | x_left: -p.radius,
563 | x_right: pJS.canvas.w + p.radius,
564 | y_top: -p.radius,
565 | y_bottom: pJS.canvas.h + p.radius
566 | }
567 | }
568 |
569 | if(p.x - p.radius > pJS.canvas.w){
570 | p.x = new_pos.x_left;
571 | p.y = Math.random() * pJS.canvas.h;
572 | }
573 | else if(p.x + p.radius < 0){
574 | p.x = new_pos.x_right;
575 | p.y = Math.random() * pJS.canvas.h;
576 | }
577 | if(p.y - p.radius > pJS.canvas.h){
578 | p.y = new_pos.y_top;
579 | p.x = Math.random() * pJS.canvas.w;
580 | }
581 | else if(p.y + p.radius < 0){
582 | p.y = new_pos.y_bottom;
583 | p.x = Math.random() * pJS.canvas.w;
584 | }
585 |
586 | /* out of canvas modes */
587 | switch(pJS.particles.move.out_mode){
588 | case 'bounce':
589 | if (p.x + p.radius > pJS.canvas.w) p.vx = -p.vx;
590 | else if (p.x - p.radius < 0) p.vx = -p.vx;
591 | if (p.y + p.radius > pJS.canvas.h) p.vy = -p.vy;
592 | else if (p.y - p.radius < 0) p.vy = -p.vy;
593 | break;
594 | }
595 |
596 | /* events */
597 | if(isInArray('grab', pJS.interactivity.events.onhover.mode)){
598 | pJS.fn.modes.grabParticle(p);
599 | }
600 |
601 | if(isInArray('bubble', pJS.interactivity.events.onhover.mode) || isInArray('bubble', pJS.interactivity.events.onclick.mode)){
602 | pJS.fn.modes.bubbleParticle(p);
603 | }
604 |
605 | if(isInArray('repulse', pJS.interactivity.events.onhover.mode) || isInArray('repulse', pJS.interactivity.events.onclick.mode)){
606 | pJS.fn.modes.repulseParticle(p);
607 | }
608 |
609 | /* interaction auto between particles */
610 | if(pJS.particles.line_linked.enable || pJS.particles.move.attract.enable){
611 | for(var j = i + 1; j < pJS.particles.array.length; j++){
612 | var p2 = pJS.particles.array[j];
613 |
614 | /* link particles */
615 | if(pJS.particles.line_linked.enable){
616 | pJS.fn.interact.linkParticles(p,p2);
617 | }
618 |
619 | /* attract particles */
620 | if(pJS.particles.move.attract.enable){
621 | pJS.fn.interact.attractParticles(p,p2);
622 | }
623 |
624 | /* bounce particles */
625 | if(pJS.particles.move.bounce){
626 | pJS.fn.interact.bounceParticles(p,p2);
627 | }
628 |
629 | }
630 | }
631 |
632 |
633 | }
634 |
635 | };
636 |
637 | pJS.fn.particlesDraw = function(){
638 |
639 | /* clear canvas */
640 | pJS.canvas.ctx.clearRect(0, 0, pJS.canvas.w, pJS.canvas.h);
641 |
642 | /* update each particles param */
643 | pJS.fn.particlesUpdate();
644 |
645 | /* draw each particle */
646 | for(var i = 0; i < pJS.particles.array.length; i++){
647 | var p = pJS.particles.array[i];
648 | p.draw();
649 | }
650 |
651 | };
652 |
653 | pJS.fn.particlesEmpty = function(){
654 | pJS.particles.array = [];
655 | };
656 |
657 | pJS.fn.particlesRefresh = function(){
658 |
659 | /* init all */
660 | cancelRequestAnimFrame(pJS.fn.checkAnimFrame);
661 | cancelRequestAnimFrame(pJS.fn.drawAnimFrame);
662 | pJS.tmp.source_svg = undefined;
663 | pJS.tmp.img_obj = undefined;
664 | pJS.tmp.count_svg = 0;
665 | pJS.fn.particlesEmpty();
666 | pJS.fn.canvasClear();
667 |
668 | /* restart */
669 | pJS.fn.vendors.start();
670 |
671 | };
672 |
673 |
674 | /* ---------- pJS functions - particles interaction ------------ */
675 |
676 | pJS.fn.interact.linkParticles = function(p1, p2){
677 |
678 | var dx = p1.x - p2.x,
679 | dy = p1.y - p2.y,
680 | dist = Math.sqrt(dx*dx + dy*dy);
681 |
682 | /* draw a line between p1 and p2 if the distance between them is under the config distance */
683 | if(dist <= pJS.particles.line_linked.distance){
684 |
685 | var opacity_line = pJS.particles.line_linked.opacity - (dist / (1/pJS.particles.line_linked.opacity)) / pJS.particles.line_linked.distance;
686 |
687 | if(opacity_line > 0){
688 |
689 | /* style */
690 | var color_line = pJS.particles.line_linked.color_rgb_line;
691 | pJS.canvas.ctx.strokeStyle = 'rgba('+color_line.r+','+color_line.g+','+color_line.b+','+opacity_line+')';
692 | pJS.canvas.ctx.lineWidth = pJS.particles.line_linked.width;
693 | //pJS.canvas.ctx.lineCap = 'round'; /* performance issue */
694 |
695 | /* path */
696 | pJS.canvas.ctx.beginPath();
697 | pJS.canvas.ctx.moveTo(p1.x, p1.y);
698 | pJS.canvas.ctx.lineTo(p2.x, p2.y);
699 | pJS.canvas.ctx.stroke();
700 | pJS.canvas.ctx.closePath();
701 |
702 | }
703 |
704 | }
705 |
706 | };
707 |
708 |
709 | pJS.fn.interact.attractParticles = function(p1, p2){
710 |
711 | /* condensed particles */
712 | var dx = p1.x - p2.x,
713 | dy = p1.y - p2.y,
714 | dist = Math.sqrt(dx*dx + dy*dy);
715 |
716 | if(dist <= pJS.particles.line_linked.distance){
717 |
718 | var ax = dx/(pJS.particles.move.attract.rotateX*1000),
719 | ay = dy/(pJS.particles.move.attract.rotateY*1000);
720 |
721 | p1.vx -= ax;
722 | p1.vy -= ay;
723 |
724 | p2.vx += ax;
725 | p2.vy += ay;
726 |
727 | }
728 |
729 |
730 | }
731 |
732 |
733 | pJS.fn.interact.bounceParticles = function(p1, p2){
734 |
735 | var dx = p1.x - p2.x,
736 | dy = p1.y - p2.y,
737 | dist = Math.sqrt(dx*dx + dy*dy),
738 | dist_p = p1.radius+p2.radius;
739 |
740 | if(dist <= dist_p){
741 | p1.vx = -p1.vx;
742 | p1.vy = -p1.vy;
743 |
744 | p2.vx = -p2.vx;
745 | p2.vy = -p2.vy;
746 | }
747 |
748 | }
749 |
750 |
751 | /* ---------- pJS functions - modes events ------------ */
752 |
753 | pJS.fn.modes.pushParticles = function(nb, pos){
754 |
755 | pJS.tmp.pushing = true;
756 |
757 | for(var i = 0; i < nb; i++){
758 | pJS.particles.array.push(
759 | new pJS.fn.particle(
760 | pJS.particles.color,
761 | pJS.particles.opacity.value,
762 | {
763 | 'x': pos ? pos.pos_x : Math.random() * pJS.canvas.w,
764 | 'y': pos ? pos.pos_y : Math.random() * pJS.canvas.h
765 | }
766 | )
767 | )
768 | if(i == nb-1){
769 | if(!pJS.particles.move.enable){
770 | pJS.fn.particlesDraw();
771 | }
772 | pJS.tmp.pushing = false;
773 | }
774 | }
775 |
776 | };
777 |
778 |
779 | pJS.fn.modes.removeParticles = function(nb){
780 |
781 | pJS.particles.array.splice(0, nb);
782 | if(!pJS.particles.move.enable){
783 | pJS.fn.particlesDraw();
784 | }
785 |
786 | };
787 |
788 |
789 | pJS.fn.modes.bubbleParticle = function(p){
790 |
791 | /* on hover event */
792 | if(pJS.interactivity.events.onhover.enable && isInArray('bubble', pJS.interactivity.events.onhover.mode)){
793 |
794 | var dx_mouse = p.x - pJS.interactivity.mouse.pos_x,
795 | dy_mouse = p.y - pJS.interactivity.mouse.pos_y,
796 | dist_mouse = Math.sqrt(dx_mouse*dx_mouse + dy_mouse*dy_mouse),
797 | ratio = 1 - dist_mouse / pJS.interactivity.modes.bubble.distance;
798 |
799 | function init(){
800 | p.opacity_bubble = p.opacity;
801 | p.radius_bubble = p.radius;
802 | }
803 |
804 | /* mousemove - check ratio */
805 | if(dist_mouse <= pJS.interactivity.modes.bubble.distance){
806 |
807 | if(ratio >= 0 && pJS.interactivity.status == 'mousemove'){
808 |
809 | /* size */
810 | if(pJS.interactivity.modes.bubble.size != pJS.particles.size.value){
811 |
812 | if(pJS.interactivity.modes.bubble.size > pJS.particles.size.value){
813 | var size = p.radius + (pJS.interactivity.modes.bubble.size*ratio);
814 | if(size >= 0){
815 | p.radius_bubble = size;
816 | }
817 | }else{
818 | var dif = p.radius - pJS.interactivity.modes.bubble.size,
819 | size = p.radius - (dif*ratio);
820 | if(size > 0){
821 | p.radius_bubble = size;
822 | }else{
823 | p.radius_bubble = 0;
824 | }
825 | }
826 |
827 | }
828 |
829 | /* opacity */
830 | if(pJS.interactivity.modes.bubble.opacity != pJS.particles.opacity.value){
831 |
832 | if(pJS.interactivity.modes.bubble.opacity > pJS.particles.opacity.value){
833 | var opacity = pJS.interactivity.modes.bubble.opacity*ratio;
834 | if(opacity > p.opacity && opacity <= pJS.interactivity.modes.bubble.opacity){
835 | p.opacity_bubble = opacity;
836 | }
837 | }else{
838 | var opacity = p.opacity - (pJS.particles.opacity.value-pJS.interactivity.modes.bubble.opacity)*ratio;
839 | if(opacity < p.opacity && opacity >= pJS.interactivity.modes.bubble.opacity){
840 | p.opacity_bubble = opacity;
841 | }
842 | }
843 |
844 | }
845 |
846 | }
847 |
848 | }else{
849 | init();
850 | }
851 |
852 |
853 | /* mouseleave */
854 | if(pJS.interactivity.status == 'mouseleave'){
855 | init();
856 | }
857 |
858 | }
859 |
860 | /* on click event */
861 | else if(pJS.interactivity.events.onclick.enable && isInArray('bubble', pJS.interactivity.events.onclick.mode)){
862 |
863 |
864 | if(pJS.tmp.bubble_clicking){
865 | var dx_mouse = p.x - pJS.interactivity.mouse.click_pos_x,
866 | dy_mouse = p.y - pJS.interactivity.mouse.click_pos_y,
867 | dist_mouse = Math.sqrt(dx_mouse*dx_mouse + dy_mouse*dy_mouse),
868 | time_spent = (new Date().getTime() - pJS.interactivity.mouse.click_time)/1000;
869 |
870 | if(time_spent > pJS.interactivity.modes.bubble.duration){
871 | pJS.tmp.bubble_duration_end = true;
872 | }
873 |
874 | if(time_spent > pJS.interactivity.modes.bubble.duration*2){
875 | pJS.tmp.bubble_clicking = false;
876 | pJS.tmp.bubble_duration_end = false;
877 | }
878 | }
879 |
880 |
881 | function process(bubble_param, particles_param, p_obj_bubble, p_obj, id){
882 |
883 | if(bubble_param != particles_param){
884 |
885 | if(!pJS.tmp.bubble_duration_end){
886 | if(dist_mouse <= pJS.interactivity.modes.bubble.distance){
887 | if(p_obj_bubble != undefined) var obj = p_obj_bubble;
888 | else var obj = p_obj;
889 | if(obj != bubble_param){
890 | var value = p_obj - (time_spent * (p_obj - bubble_param) / pJS.interactivity.modes.bubble.duration);
891 | if(id == 'size') p.radius_bubble = value;
892 | if(id == 'opacity') p.opacity_bubble = value;
893 | }
894 | }else{
895 | if(id == 'size') p.radius_bubble = undefined;
896 | if(id == 'opacity') p.opacity_bubble = undefined;
897 | }
898 | }else{
899 | if(p_obj_bubble != undefined){
900 | var value_tmp = p_obj - (time_spent * (p_obj - bubble_param) / pJS.interactivity.modes.bubble.duration),
901 | dif = bubble_param - value_tmp;
902 | value = bubble_param + dif;
903 | if(id == 'size') p.radius_bubble = value;
904 | if(id == 'opacity') p.opacity_bubble = value;
905 | }
906 | }
907 |
908 | }
909 |
910 | }
911 |
912 | if(pJS.tmp.bubble_clicking){
913 | /* size */
914 | process(pJS.interactivity.modes.bubble.size, pJS.particles.size.value, p.radius_bubble, p.radius, 'size');
915 | /* opacity */
916 | process(pJS.interactivity.modes.bubble.opacity, pJS.particles.opacity.value, p.opacity_bubble, p.opacity, 'opacity');
917 | }
918 |
919 | }
920 |
921 | };
922 |
923 |
924 | pJS.fn.modes.repulseParticle = function(p){
925 |
926 | if(pJS.interactivity.events.onhover.enable && isInArray('repulse', pJS.interactivity.events.onhover.mode) && pJS.interactivity.status == 'mousemove') {
927 |
928 | var dx_mouse = p.x - pJS.interactivity.mouse.pos_x,
929 | dy_mouse = p.y - pJS.interactivity.mouse.pos_y,
930 | dist_mouse = Math.sqrt(dx_mouse*dx_mouse + dy_mouse*dy_mouse);
931 |
932 | var normVec = {x: dx_mouse/dist_mouse, y: dy_mouse/dist_mouse},
933 | repulseRadius = pJS.interactivity.modes.repulse.distance,
934 | velocity = 100,
935 | repulseFactor = clamp((1/repulseRadius)*(-1*Math.pow(dist_mouse/repulseRadius,2)+1)*repulseRadius*velocity, 0, 50);
936 |
937 | var pos = {
938 | x: p.x + normVec.x * repulseFactor,
939 | y: p.y + normVec.y * repulseFactor
940 | }
941 |
942 | if(pJS.particles.move.out_mode == 'bounce'){
943 | if(pos.x - p.radius > 0 && pos.x + p.radius < pJS.canvas.w) p.x = pos.x;
944 | if(pos.y - p.radius > 0 && pos.y + p.radius < pJS.canvas.h) p.y = pos.y;
945 | }else{
946 | p.x = pos.x;
947 | p.y = pos.y;
948 | }
949 |
950 | }
951 |
952 |
953 | else if(pJS.interactivity.events.onclick.enable && isInArray('repulse', pJS.interactivity.events.onclick.mode)) {
954 |
955 | if(!pJS.tmp.repulse_finish){
956 | pJS.tmp.repulse_count++;
957 | if(pJS.tmp.repulse_count == pJS.particles.array.length){
958 | pJS.tmp.repulse_finish = true;
959 | }
960 | }
961 |
962 | if(pJS.tmp.repulse_clicking){
963 |
964 | var repulseRadius = Math.pow(pJS.interactivity.modes.repulse.distance/6, 3);
965 |
966 | var dx = pJS.interactivity.mouse.click_pos_x - p.x,
967 | dy = pJS.interactivity.mouse.click_pos_y - p.y,
968 | d = dx*dx + dy*dy;
969 |
970 | var force = -repulseRadius / d * 1;
971 |
972 | function process(){
973 |
974 | var f = Math.atan2(dy,dx);
975 | p.vx = force * Math.cos(f);
976 | p.vy = force * Math.sin(f);
977 |
978 | if(pJS.particles.move.out_mode == 'bounce'){
979 | var pos = {
980 | x: p.x + p.vx,
981 | y: p.y + p.vy
982 | }
983 | if (pos.x + p.radius > pJS.canvas.w) p.vx = -p.vx;
984 | else if (pos.x - p.radius < 0) p.vx = -p.vx;
985 | if (pos.y + p.radius > pJS.canvas.h) p.vy = -p.vy;
986 | else if (pos.y - p.radius < 0) p.vy = -p.vy;
987 | }
988 |
989 | }
990 |
991 | // default
992 | if(d <= repulseRadius){
993 | process();
994 | }
995 |
996 | // bang - slow motion mode
997 | // if(!pJS.tmp.repulse_finish){
998 | // if(d <= repulseRadius){
999 | // process();
1000 | // }
1001 | // }else{
1002 | // process();
1003 | // }
1004 |
1005 |
1006 | }else{
1007 |
1008 | if(pJS.tmp.repulse_clicking == false){
1009 |
1010 | p.vx = p.vx_i;
1011 | p.vy = p.vy_i;
1012 |
1013 | }
1014 |
1015 | }
1016 |
1017 | }
1018 |
1019 | }
1020 |
1021 |
1022 | pJS.fn.modes.grabParticle = function(p){
1023 |
1024 | if(pJS.interactivity.events.onhover.enable && pJS.interactivity.status == 'mousemove'){
1025 |
1026 | var dx_mouse = p.x - pJS.interactivity.mouse.pos_x,
1027 | dy_mouse = p.y - pJS.interactivity.mouse.pos_y,
1028 | dist_mouse = Math.sqrt(dx_mouse*dx_mouse + dy_mouse*dy_mouse);
1029 |
1030 | /* draw a line between the cursor and the particle if the distance between them is under the config distance */
1031 | if(dist_mouse <= pJS.interactivity.modes.grab.distance){
1032 |
1033 | var opacity_line = pJS.interactivity.modes.grab.line_linked.opacity - (dist_mouse / (1/pJS.interactivity.modes.grab.line_linked.opacity)) / pJS.interactivity.modes.grab.distance;
1034 |
1035 | if(opacity_line > 0){
1036 |
1037 | /* style */
1038 | var color_line = pJS.particles.line_linked.color_rgb_line;
1039 | pJS.canvas.ctx.strokeStyle = 'rgba('+color_line.r+','+color_line.g+','+color_line.b+','+opacity_line+')';
1040 | pJS.canvas.ctx.lineWidth = pJS.particles.line_linked.width;
1041 | //pJS.canvas.ctx.lineCap = 'round'; /* performance issue */
1042 |
1043 | /* path */
1044 | pJS.canvas.ctx.beginPath();
1045 | pJS.canvas.ctx.moveTo(p.x, p.y);
1046 | pJS.canvas.ctx.lineTo(pJS.interactivity.mouse.pos_x, pJS.interactivity.mouse.pos_y);
1047 | pJS.canvas.ctx.stroke();
1048 | pJS.canvas.ctx.closePath();
1049 |
1050 | }
1051 |
1052 | }
1053 |
1054 | }
1055 |
1056 | };
1057 |
1058 |
1059 |
1060 | /* ---------- pJS functions - vendors ------------ */
1061 |
1062 | pJS.fn.vendors.eventsListeners = function(){
1063 |
1064 | /* events target element */
1065 | if(pJS.interactivity.detect_on == 'window'){
1066 | pJS.interactivity.el = window;
1067 | }else{
1068 | pJS.interactivity.el = pJS.canvas.el;
1069 | }
1070 |
1071 |
1072 | /* detect mouse pos - on hover / click event */
1073 | if(pJS.interactivity.events.onhover.enable || pJS.interactivity.events.onclick.enable){
1074 |
1075 | /* el on mousemove */
1076 | pJS.interactivity.el.addEventListener('mousemove', function(e){
1077 |
1078 | if(pJS.interactivity.el == window){
1079 | var pos_x = e.clientX,
1080 | pos_y = e.clientY;
1081 | }
1082 | else{
1083 | var pos_x = e.offsetX || e.clientX,
1084 | pos_y = e.offsetY || e.clientY;
1085 | }
1086 |
1087 | pJS.interactivity.mouse.pos_x = pos_x;
1088 | pJS.interactivity.mouse.pos_y = pos_y;
1089 |
1090 | if(pJS.tmp.retina){
1091 | pJS.interactivity.mouse.pos_x *= pJS.canvas.pxratio;
1092 | pJS.interactivity.mouse.pos_y *= pJS.canvas.pxratio;
1093 | }
1094 |
1095 | pJS.interactivity.status = 'mousemove';
1096 |
1097 | });
1098 |
1099 | /* el on onmouseleave */
1100 | pJS.interactivity.el.addEventListener('mouseleave', function(e){
1101 |
1102 | pJS.interactivity.mouse.pos_x = null;
1103 | pJS.interactivity.mouse.pos_y = null;
1104 | pJS.interactivity.status = 'mouseleave';
1105 |
1106 | });
1107 |
1108 | }
1109 |
1110 | /* on click event */
1111 | if(pJS.interactivity.events.onclick.enable){
1112 |
1113 | pJS.interactivity.el.addEventListener('click', function(){
1114 |
1115 | pJS.interactivity.mouse.click_pos_x = pJS.interactivity.mouse.pos_x;
1116 | pJS.interactivity.mouse.click_pos_y = pJS.interactivity.mouse.pos_y;
1117 | pJS.interactivity.mouse.click_time = new Date().getTime();
1118 |
1119 | if(pJS.interactivity.events.onclick.enable){
1120 |
1121 | switch(pJS.interactivity.events.onclick.mode){
1122 |
1123 | case 'push':
1124 | if(pJS.particles.move.enable){
1125 | pJS.fn.modes.pushParticles(pJS.interactivity.modes.push.particles_nb, pJS.interactivity.mouse);
1126 | }else{
1127 | if(pJS.interactivity.modes.push.particles_nb == 1){
1128 | pJS.fn.modes.pushParticles(pJS.interactivity.modes.push.particles_nb, pJS.interactivity.mouse);
1129 | }
1130 | else if(pJS.interactivity.modes.push.particles_nb > 1){
1131 | pJS.fn.modes.pushParticles(pJS.interactivity.modes.push.particles_nb);
1132 | }
1133 | }
1134 | break;
1135 |
1136 | case 'remove':
1137 | pJS.fn.modes.removeParticles(pJS.interactivity.modes.remove.particles_nb);
1138 | break;
1139 |
1140 | case 'bubble':
1141 | pJS.tmp.bubble_clicking = true;
1142 | break;
1143 |
1144 | case 'repulse':
1145 | pJS.tmp.repulse_clicking = true;
1146 | pJS.tmp.repulse_count = 0;
1147 | pJS.tmp.repulse_finish = false;
1148 | setTimeout(function(){
1149 | pJS.tmp.repulse_clicking = false;
1150 | }, pJS.interactivity.modes.repulse.duration*1000)
1151 | break;
1152 |
1153 | }
1154 |
1155 | }
1156 |
1157 | });
1158 |
1159 | }
1160 |
1161 |
1162 | };
1163 |
1164 | pJS.fn.vendors.densityAutoParticles = function(){
1165 |
1166 | if(pJS.particles.number.density.enable){
1167 |
1168 | /* calc area */
1169 | var area = pJS.canvas.el.width * pJS.canvas.el.height / 1000;
1170 | if(pJS.tmp.retina){
1171 | area = area/(pJS.canvas.pxratio*2);
1172 | }
1173 |
1174 | /* calc number of particles based on density area */
1175 | var nb_particles = area * pJS.particles.number.value / pJS.particles.number.density.value_area;
1176 |
1177 | /* add or remove X particles */
1178 | var missing_particles = pJS.particles.array.length - nb_particles;
1179 | if(missing_particles < 0) pJS.fn.modes.pushParticles(Math.abs(missing_particles));
1180 | else pJS.fn.modes.removeParticles(missing_particles);
1181 |
1182 | }
1183 |
1184 | };
1185 |
1186 |
1187 | pJS.fn.vendors.checkOverlap = function(p1, position){
1188 | for(var i = 0; i < pJS.particles.array.length; i++){
1189 | var p2 = pJS.particles.array[i];
1190 |
1191 | var dx = p1.x - p2.x,
1192 | dy = p1.y - p2.y,
1193 | dist = Math.sqrt(dx*dx + dy*dy);
1194 |
1195 | if(dist <= p1.radius + p2.radius){
1196 | p1.x = position ? position.x : Math.random() * pJS.canvas.w;
1197 | p1.y = position ? position.y : Math.random() * pJS.canvas.h;
1198 | pJS.fn.vendors.checkOverlap(p1);
1199 | }
1200 | }
1201 | };
1202 |
1203 |
1204 | pJS.fn.vendors.createSvgImg = function(p){
1205 |
1206 | /* set color to svg element */
1207 | var svgXml = pJS.tmp.source_svg,
1208 | rgbHex = /#([0-9A-F]{3,6})/gi,
1209 | coloredSvgXml = svgXml.replace(rgbHex, function (m, r, g, b) {
1210 | if(p.color.rgb){
1211 | var color_value = 'rgba('+p.color.rgb.r+','+p.color.rgb.g+','+p.color.rgb.b+','+p.opacity+')';
1212 | }else{
1213 | var color_value = 'hsla('+p.color.hsl.h+','+p.color.hsl.s+'%,'+p.color.hsl.l+'%,'+p.opacity+')';
1214 | }
1215 | return color_value;
1216 | });
1217 |
1218 | /* prepare to create img with colored svg */
1219 | var svg = new Blob([coloredSvgXml], {type: 'image/svg+xml;charset=utf-8'}),
1220 | DOMURL = window.URL || window.webkitURL || window,
1221 | url = DOMURL.createObjectURL(svg);
1222 |
1223 | /* create particle img obj */
1224 | var img = new Image();
1225 | img.addEventListener('load', function(){
1226 | p.img.obj = img;
1227 | p.img.loaded = true;
1228 | DOMURL.revokeObjectURL(url);
1229 | pJS.tmp.count_svg++;
1230 | });
1231 | img.src = url;
1232 |
1233 | };
1234 |
1235 |
1236 | pJS.fn.vendors.destroypJS = function(){
1237 | cancelAnimationFrame(pJS.fn.drawAnimFrame);
1238 | canvas_el.remove();
1239 | pJSDom = null;
1240 | };
1241 |
1242 |
1243 | pJS.fn.vendors.drawShape = function(c, startX, startY, sideLength, sideCountNumerator, sideCountDenominator){
1244 |
1245 | // By Programming Thomas - https://programmingthomas.wordpress.com/2013/04/03/n-sided-shapes/
1246 | var sideCount = sideCountNumerator * sideCountDenominator;
1247 | var decimalSides = sideCountNumerator / sideCountDenominator;
1248 | var interiorAngleDegrees = (180 * (decimalSides - 2)) / decimalSides;
1249 | var interiorAngle = Math.PI - Math.PI * interiorAngleDegrees / 180; // convert to radians
1250 | c.save();
1251 | c.beginPath();
1252 | c.translate(startX, startY);
1253 | c.moveTo(0,0);
1254 | for (var i = 0; i < sideCount; i++) {
1255 | c.lineTo(sideLength,0);
1256 | c.translate(sideLength,0);
1257 | c.rotate(interiorAngle);
1258 | }
1259 | //c.stroke();
1260 | c.fill();
1261 | c.restore();
1262 |
1263 | };
1264 |
1265 | pJS.fn.vendors.exportImg = function(){
1266 | window.open(pJS.canvas.el.toDataURL('image/png'), '_blank');
1267 | };
1268 |
1269 |
1270 | pJS.fn.vendors.loadImg = function(type){
1271 |
1272 | pJS.tmp.img_error = undefined;
1273 |
1274 | if(pJS.particles.shape.image.src != ''){
1275 |
1276 | if(type == 'svg'){
1277 |
1278 | var xhr = new XMLHttpRequest();
1279 | xhr.open('GET', pJS.particles.shape.image.src);
1280 | xhr.onreadystatechange = function (data) {
1281 | if(xhr.readyState == 4){
1282 | if(xhr.status == 200){
1283 | pJS.tmp.source_svg = data.currentTarget.response;
1284 | pJS.fn.vendors.checkBeforeDraw();
1285 | }else{
1286 | console.log('Error pJS - Image not found');
1287 | pJS.tmp.img_error = true;
1288 | }
1289 | }
1290 | }
1291 | xhr.send();
1292 |
1293 | }else{
1294 |
1295 | var img = new Image();
1296 | img.addEventListener('load', function(){
1297 | pJS.tmp.img_obj = img;
1298 | pJS.fn.vendors.checkBeforeDraw();
1299 | });
1300 | img.src = pJS.particles.shape.image.src;
1301 |
1302 | }
1303 |
1304 | }else{
1305 | console.log('Error pJS - No image.src');
1306 | pJS.tmp.img_error = true;
1307 | }
1308 |
1309 | };
1310 |
1311 |
1312 | pJS.fn.vendors.draw = function(){
1313 |
1314 | if(pJS.particles.shape.type == 'image'){
1315 |
1316 | if(pJS.tmp.img_type == 'svg'){
1317 |
1318 | if(pJS.tmp.count_svg >= pJS.particles.number.value){
1319 | pJS.fn.particlesDraw();
1320 | if(!pJS.particles.move.enable) cancelRequestAnimFrame(pJS.fn.drawAnimFrame);
1321 | else pJS.fn.drawAnimFrame = requestAnimFrame(pJS.fn.vendors.draw);
1322 | }else{
1323 | //console.log('still loading...');
1324 | if(!pJS.tmp.img_error) pJS.fn.drawAnimFrame = requestAnimFrame(pJS.fn.vendors.draw);
1325 | }
1326 |
1327 | }else{
1328 |
1329 | if(pJS.tmp.img_obj != undefined){
1330 | pJS.fn.particlesDraw();
1331 | if(!pJS.particles.move.enable) cancelRequestAnimFrame(pJS.fn.drawAnimFrame);
1332 | else pJS.fn.drawAnimFrame = requestAnimFrame(pJS.fn.vendors.draw);
1333 | }else{
1334 | if(!pJS.tmp.img_error) pJS.fn.drawAnimFrame = requestAnimFrame(pJS.fn.vendors.draw);
1335 | }
1336 |
1337 | }
1338 |
1339 | }else{
1340 | pJS.fn.particlesDraw();
1341 | if(!pJS.particles.move.enable) cancelRequestAnimFrame(pJS.fn.drawAnimFrame);
1342 | else pJS.fn.drawAnimFrame = requestAnimFrame(pJS.fn.vendors.draw);
1343 | }
1344 |
1345 | };
1346 |
1347 |
1348 | pJS.fn.vendors.checkBeforeDraw = function(){
1349 |
1350 | // if shape is image
1351 | if(pJS.particles.shape.type == 'image'){
1352 |
1353 | if(pJS.tmp.img_type == 'svg' && pJS.tmp.source_svg == undefined){
1354 | pJS.tmp.checkAnimFrame = requestAnimFrame(check);
1355 | }else{
1356 | //console.log('images loaded! cancel check');
1357 | cancelRequestAnimFrame(pJS.tmp.checkAnimFrame);
1358 | if(!pJS.tmp.img_error){
1359 | pJS.fn.vendors.init();
1360 | pJS.fn.vendors.draw();
1361 | }
1362 |
1363 | }
1364 |
1365 | }else{
1366 | pJS.fn.vendors.init();
1367 | pJS.fn.vendors.draw();
1368 | }
1369 |
1370 | };
1371 |
1372 |
1373 | pJS.fn.vendors.init = function(){
1374 |
1375 | /* init canvas + particles */
1376 | pJS.fn.retinaInit();
1377 | pJS.fn.canvasInit();
1378 | pJS.fn.canvasSize();
1379 | pJS.fn.canvasPaint();
1380 | pJS.fn.particlesCreate();
1381 | pJS.fn.vendors.densityAutoParticles();
1382 |
1383 | /* particles.line_linked - convert hex colors to rgb */
1384 | pJS.particles.line_linked.color_rgb_line = hexToRgb(pJS.particles.line_linked.color);
1385 |
1386 | };
1387 |
1388 |
1389 | pJS.fn.vendors.start = function(){
1390 |
1391 | if(isInArray('image', pJS.particles.shape.type)){
1392 | pJS.tmp.img_type = pJS.particles.shape.image.src.substr(pJS.particles.shape.image.src.length - 3);
1393 | pJS.fn.vendors.loadImg(pJS.tmp.img_type);
1394 | }else{
1395 | pJS.fn.vendors.checkBeforeDraw();
1396 | }
1397 |
1398 | };
1399 |
1400 |
1401 |
1402 |
1403 | /* ---------- pJS - start ------------ */
1404 |
1405 |
1406 | pJS.fn.vendors.eventsListeners();
1407 |
1408 | pJS.fn.vendors.start();
1409 |
1410 |
1411 |
1412 | };
1413 |
1414 | /* ---------- global functions - vendors ------------ */
1415 |
1416 | Object.deepExtend = function(destination, source) {
1417 | for (var property in source) {
1418 | if (source[property] && source[property].constructor &&
1419 | source[property].constructor === Object) {
1420 | destination[property] = destination[property] || {};
1421 | arguments.callee(destination[property], source[property]);
1422 | } else {
1423 | destination[property] = source[property];
1424 | }
1425 | }
1426 | return destination;
1427 | };
1428 |
1429 | window.requestAnimFrame = (function(){
1430 | return window.requestAnimationFrame ||
1431 | window.webkitRequestAnimationFrame ||
1432 | window.mozRequestAnimationFrame ||
1433 | window.oRequestAnimationFrame ||
1434 | window.msRequestAnimationFrame ||
1435 | function(callback){
1436 | window.setTimeout(callback, 1000 / 60);
1437 | };
1438 | })();
1439 |
1440 | window.cancelRequestAnimFrame = ( function() {
1441 | return window.cancelAnimationFrame ||
1442 | window.webkitCancelRequestAnimationFrame ||
1443 | window.mozCancelRequestAnimationFrame ||
1444 | window.oCancelRequestAnimationFrame ||
1445 | window.msCancelRequestAnimationFrame ||
1446 | clearTimeout
1447 | } )();
1448 |
1449 | function hexToRgb(hex){
1450 | // By Tim Down - http://stackoverflow.com/a/5624139/3493650
1451 | // Expand shorthand form (e.g. "03F") to full form (e.g. "0033FF")
1452 | var shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
1453 | hex = hex.replace(shorthandRegex, function(m, r, g, b) {
1454 | return r + r + g + g + b + b;
1455 | });
1456 | var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
1457 | return result ? {
1458 | r: parseInt(result[1], 16),
1459 | g: parseInt(result[2], 16),
1460 | b: parseInt(result[3], 16)
1461 | } : null;
1462 | };
1463 |
1464 | function clamp(number, min, max) {
1465 | return Math.min(Math.max(number, min), max);
1466 | };
1467 |
1468 | function isInArray(value, array) {
1469 | return array.indexOf(value) > -1;
1470 | }
1471 |
1472 |
1473 | /* ---------- particles.js functions - start ------------ */
1474 |
1475 | window.pJSDom = [];
1476 |
1477 | window.particlesJS = function(tag_id, params){
1478 |
1479 | //console.log(params);
1480 |
1481 | /* no string id? so it's object params, and set the id with default id */
1482 | if(typeof(tag_id) != 'string'){
1483 | params = tag_id;
1484 | tag_id = 'particles-js';
1485 | }
1486 |
1487 | /* no id? set the id to default id */
1488 | if(!tag_id){
1489 | tag_id = 'particles-js';
1490 | }
1491 |
1492 | /* pJS elements */
1493 | var pJS_tag = document.getElementById(tag_id),
1494 | pJS_canvas_class = 'particles-js-canvas-el',
1495 | exist_canvas = pJS_tag.getElementsByClassName(pJS_canvas_class);
1496 |
1497 | /* remove canvas if exists into the pJS target tag */
1498 | if(exist_canvas.length){
1499 | while(exist_canvas.length > 0){
1500 | pJS_tag.removeChild(exist_canvas[0]);
1501 | }
1502 | }
1503 |
1504 | /* create canvas element */
1505 | var canvas_el = document.createElement('canvas');
1506 | canvas_el.className = pJS_canvas_class;
1507 |
1508 | /* set size canvas */
1509 | canvas_el.style.width = "100%";
1510 | canvas_el.style.height = "100%";
1511 |
1512 | /* append canvas */
1513 | var canvas = document.getElementById(tag_id).appendChild(canvas_el);
1514 |
1515 | /* launch particle.js */
1516 | if(canvas != null){
1517 | pJSDom.push(new pJS(tag_id, params));
1518 | }
1519 |
1520 | };
1521 |
1522 | window.particlesJS.load = function(tag_id, path_config_json, callback){
1523 |
1524 | /* load json config */
1525 | var xhr = new XMLHttpRequest();
1526 | xhr.open('GET', path_config_json);
1527 | xhr.onreadystatechange = function (data) {
1528 | if(xhr.readyState == 4){
1529 | if(xhr.status == 200){
1530 | var params = JSON.parse(data.currentTarget.response);
1531 | window.particlesJS(tag_id, params);
1532 | if(callback) callback();
1533 | }else{
1534 | console.log('Error pJS - XMLHttpRequest status: '+xhr.status);
1535 | console.log('Error pJS - File config not found');
1536 | }
1537 | }
1538 | };
1539 | xhr.send();
1540 |
1541 | };
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | Disallow:
4 |
--------------------------------------------------------------------------------
/public/web-programming.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/screenshots/convex_instruct.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arnabuchiha/Algorithm-Visualizer/a19a588b18af38bff2a07341f9ed0cd09e131d2f/screenshots/convex_instruct.gif
--------------------------------------------------------------------------------
/screenshots/frontpage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arnabuchiha/Algorithm-Visualizer/a19a588b18af38bff2a07341f9ed0cd09e131d2f/screenshots/frontpage.png
--------------------------------------------------------------------------------
/screenshots/pathfinder.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arnabuchiha/Algorithm-Visualizer/a19a588b18af38bff2a07341f9ed0cd09e131d2f/screenshots/pathfinder.gif
--------------------------------------------------------------------------------
/screenshots/sorting.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arnabuchiha/Algorithm-Visualizer/a19a588b18af38bff2a07341f9ed0cd09e131d2f/screenshots/sorting.gif
--------------------------------------------------------------------------------
/src/App.css:
--------------------------------------------------------------------------------
1 | .App {
2 | text-align: center;
3 | }
4 |
5 | .App-logo {
6 | height: 40vmin;
7 | pointer-events: none;
8 | }
9 |
10 | @media (prefers-reduced-motion: no-preference) {
11 | .App-logo {
12 | animation: App-logo-spin infinite 20s linear;
13 | }
14 | }
15 |
16 | .App-header {
17 | background-color: #282c34;
18 | min-height: 100vh;
19 | display: flex;
20 | flex-direction: column;
21 | align-items: center;
22 | justify-content: center;
23 | font-size: calc(10px + 2vmin);
24 | color: white;
25 | }
26 |
27 | .App-link {
28 | color: #61dafb;
29 | }
30 |
31 | @keyframes App-logo-spin {
32 | from {
33 | transform: rotate(0deg);
34 | }
35 | to {
36 | transform: rotate(360deg);
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/App.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Route, Switch, Link, BrowserRouter as Router } from "react-router-dom";
3 | import './App.css';
4 | import Sorting from "./components/Sorting/Sorting";
5 | import Home from "./components/Home"
6 | import Pathfinding from "./components/Pathfinding/Pathfinding"
7 | import ConvexHull from './components/ConvexHull/ConvexHull';
8 | function App() {
9 | return (
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 | );
32 | }
33 |
34 | export default App;
35 |
--------------------------------------------------------------------------------
/src/App.test.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { render } from '@testing-library/react';
3 | import App from './App';
4 |
5 | test('renders learn react link', () => {
6 | const { getByText } = render( );
7 | const linkElement = getByText(/learn react/i);
8 | expect(linkElement).toBeInTheDocument();
9 | });
10 |
--------------------------------------------------------------------------------
/src/assets/Anurati-Regular.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arnabuchiha/Algorithm-Visualizer/a19a588b18af38bff2a07341f9ed0cd09e131d2f/src/assets/Anurati-Regular.otf
--------------------------------------------------------------------------------
/src/assets/analytics.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
7 |
9 |
10 |
11 |
12 |
13 |
16 |
17 |
18 |
19 |
20 |
23 |
24 |
25 |
26 |
27 |
30 |
31 |
32 |
33 |
34 |
37 |
38 |
39 |
40 |
41 |
44 |
45 |
46 |
47 |
48 |
51 |
52 |
53 |
54 |
55 |
58 |
59 |
60 |
61 |
62 |
65 |
66 |
67 |
68 |
69 |
72 |
73 |
74 |
75 |
76 |
79 |
80 |
81 |
82 |
83 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
--------------------------------------------------------------------------------
/src/assets/asteroid.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/assets/bar-chart.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
6 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/src/assets/convex.svg:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
10 |
11 |
12 |
13 |
19 |
20 |
21 |
22 |
28 |
29 |
30 |
31 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
307 |
308 |
309 |
310 |
311 |
312 |
315 |
316 |
317 |
318 |
319 |
320 |
321 |
322 |
323 |
344 |
350 |
351 |
352 |
353 |
354 |
355 |
356 |
357 |
358 |
359 |
360 |
361 |
362 |
363 |
364 |
365 |
366 |
367 |
391 |
392 |
393 |
394 |
395 |
396 |
397 |
398 |
399 |
400 |
401 |
402 |
403 |
404 |
405 |
406 |
407 |
408 |
425 |
426 |
427 |
428 |
429 |
430 |
431 |
432 |
433 |
434 |
435 |
436 |
437 |
438 |
439 |
440 |
441 |
442 |
472 |
473 |
474 |
475 |
476 |
477 |
478 |
479 |
480 |
481 |
482 |
483 |
484 |
485 |
486 |
487 |
488 |
489 |
528 |
529 |
530 |
531 |
532 |
533 |
534 |
535 |
536 |
537 |
538 |
539 |
540 |
541 |
542 |
543 |
544 |
545 |
558 |
559 |
560 |
561 |
562 |
563 |
564 |
565 |
566 |
567 |
568 |
569 |
570 |
571 |
574 |
575 |
576 |
577 |
578 |
579 |
580 |
581 |
582 |
583 |
584 |
585 |
586 |
587 |
588 |
589 |
590 |
591 |
592 |
593 |
594 |
595 |
596 |
597 |
598 |
599 |
600 |
601 |
602 |
603 |
604 |
605 |
606 |
607 |
608 |
609 |
610 |
611 |
612 |
613 |
614 |
615 |
616 |
617 |
618 |
619 |
620 |
621 |
622 |
623 |
624 |
625 |
626 |
627 |
628 |
629 |
630 |
631 |
632 |
633 |
634 |
635 |
636 |
637 |
638 |
639 |
640 |
641 |
642 |
643 |
644 |
645 |
646 |
647 |
648 |
649 |
650 |
653 |
654 |
655 |
658 |
659 |
660 |
663 |
664 |
665 |
668 |
669 |
670 |
671 |
672 |
673 |
674 |
675 |
676 |
677 |
--------------------------------------------------------------------------------
/src/assets/convex_hull.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arnabuchiha/Algorithm-Visualizer/a19a588b18af38bff2a07341f9ed0cd09e131d2f/src/assets/convex_hull.png
--------------------------------------------------------------------------------
/src/assets/convex_instruct.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arnabuchiha/Algorithm-Visualizer/a19a588b18af38bff2a07341f9ed0cd09e131d2f/src/assets/convex_instruct.gif
--------------------------------------------------------------------------------
/src/assets/github.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/assets/graph.svg:
--------------------------------------------------------------------------------
1 |
4 |
5 | untitled
6 |
7 | A
8 |
9 | A
10 |
11 | B
12 |
13 | B
14 |
15 | A--B
16 |
17 |
18 | C
19 |
20 | C
21 |
22 | B--C
23 |
24 |
25 | E
26 |
27 | E
28 |
29 | B--E
30 |
31 |
32 | D
33 |
34 | D
35 |
36 | C--D
37 |
38 |
39 | D--E
40 |
41 |
42 | E--A
43 |
44 |
45 | F
46 |
47 | F
48 |
49 | F--D
50 |
51 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/src/assets/heading_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arnabuchiha/Algorithm-Visualizer/a19a588b18af38bff2a07341f9ed0cd09e131d2f/src/assets/heading_logo.png
--------------------------------------------------------------------------------
/src/assets/linkedin.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
7 |
8 |
14 |
18 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
--------------------------------------------------------------------------------
/src/assets/particles.json:
--------------------------------------------------------------------------------
1 | {
2 | "particles":{
3 | "number":{
4 | "value":100,
5 | "density":{
6 | "enable":true,
7 | "value_area":800
8 | }
9 | },
10 | "color":{
11 | "value":"#2DD327"
12 | },
13 | "shape":{
14 | "type":"circle",
15 | "stroke":{
16 | "width":0,
17 | "color":"#ff0000"
18 | },
19 | "polygon":{
20 | "nb_sides":5
21 | },
22 | "image":{
23 | "src":"",
24 | "width":100,
25 | "height":100
26 | }
27 | },
28 | "opacity":{
29 | "value":0.5,
30 | "random":false,
31 | "anim":{
32 | "enable":false,
33 | "speed":2,
34 | "opacity_min":0,
35 | "sync":false
36 | }
37 | },
38 | "size":{
39 | "value":3,
40 | "random":false,
41 | "anim":{
42 | "enable":false,
43 | "speed":20,
44 | "size_min":0,
45 | "sync":false
46 | }
47 | },
48 | "line_linked":{
49 | "enable":true,
50 | "distance":150,
51 | "color":"#2DD327",
52 | "opacity":0.4,
53 | "width":1
54 | },
55 | "move":{
56 | "enable":true,
57 | "speed":2,
58 | "direction":"none",
59 | "random":false,
60 | "straight":false,
61 | "out_mode":"out",
62 | "bounce":false,
63 | "attract":{
64 | "enable":false,
65 | "rotateX":3000,
66 | "rotateY":3000
67 | }
68 | },
69 | "array":[]
70 | },
71 | "interactivity":{
72 | "detect_on":"window",
73 | "events":{
74 | "onhover":{
75 | "enable":true,
76 | "mode":"grab"
77 | },
78 | "onclick":{
79 | "enable":false,
80 | "mode":"push"
81 | },
82 | "resize":true
83 | },
84 | "modes":{
85 | "grab":{
86 | "distance":100,
87 | "line_linked":{
88 | "opacity":1
89 | }
90 | },
91 | "bubble":{
92 | "distance":200,
93 | "size":80,
94 | "duration":0.4
95 | },
96 | "repulse":{
97 | "distance":200,
98 | "duration":0.4
99 | },
100 | "push":{
101 | "particles_nb":4
102 | },
103 | "remove":{
104 | "particles_nb":2
105 | }
106 | },
107 | "mouse":{}
108 | },
109 | "retina_detect":false,
110 | "fn":{
111 | "interact":{},
112 | "modes":{},
113 | "vendors":{}
114 | },
115 | "tmp":{}
116 | }
--------------------------------------------------------------------------------
/src/assets/pathfinder.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arnabuchiha/Algorithm-Visualizer/a19a588b18af38bff2a07341f9ed0cd09e131d2f/src/assets/pathfinder.gif
--------------------------------------------------------------------------------
/src/assets/pathfinding_front.svg:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
14 |
15 |
18 |
19 |
20 |
21 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
52 |
56 |
57 |
59 |
61 |
62 | A
63 | B
64 |
65 |
66 |
--------------------------------------------------------------------------------
/src/assets/planet.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/assets/sorting.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arnabuchiha/Algorithm-Visualizer/a19a588b18af38bff2a07341f9ed0cd09e131d2f/src/assets/sorting.png
--------------------------------------------------------------------------------
/src/assets/space-ship.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/components/ConvexHull/ConvexHull.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import "../../styles/ConvexHull.css";
3 | import Instruct from "../Instructions/Instruct";
4 | import instruct_gif from "../../assets/convex_instruct.gif";
5 | import { NavLink } from "react-router-dom";
6 | class ConvexHull extends Component{
7 | constructor(){
8 | super()
9 | this.state={
10 | points:[],
11 | showModal:true
12 | }
13 | }
14 | showModal = () => {
15 | this.setState({
16 | showModal: true
17 | });
18 | };
19 |
20 | hideModal = () => {
21 | this.setState({ showModal: false });
22 | };
23 | componentDidMount(){
24 | window.addEventListener("resize",(e)=>{
25 | // var canvas = document.getElementById("myCanvas");
26 | this.canvas.setAttribute("width",0.7*window.innerWidth);
27 | this.canvas.setAttribute("height",0.7*window.innerHeight);
28 | this.setState({
29 | points:[]
30 | })
31 |
32 |
33 | })
34 | this.canvas = document.getElementById("myCanvas");
35 | this.canvas.addEventListener("mousedown",(e)=>this.makePoint(e));
36 | }
37 | makePoint=(event)=>{
38 | let rect = this.canvas.getBoundingClientRect();
39 | let x = event.clientX - rect.left;
40 | let y = event.clientY - rect.top;
41 | var ctx = this.canvas.getContext("2d");
42 | ctx.beginPath();
43 | ctx.arc(x, y, 10, 0, 2 * Math.PI);
44 | ctx.stroke();
45 | this.setState({
46 | points:[...this.state.points,{x,y}]
47 | })
48 | }
49 | drawAllNodes=()=>{
50 | var points=this.state.points;
51 | points.forEach(e=>{
52 | var ctx = this.canvas.getContext("2d");
53 | ctx.setLineDash([]);
54 | ctx.beginPath();
55 | ctx.strokeStyle="black";
56 | ctx.arc(e.x, e.y, 10, 0, 2 * Math.PI);
57 | ctx.stroke();
58 | ctx.closePath();
59 | })
60 | }
61 | drawDottedLine=(x1=this.state.points[0].x,y1=this.state.points[0].y,x2=this.state.points[1].x,y2=this.state.points[1].y)=>{
62 | var ctx = this.canvas.getContext("2d");
63 | ctx.setLineDash([5, 3]);
64 | ctx.beginPath();
65 | ctx.moveTo(x1,y1);
66 | ctx.lineTo(x2,y2);
67 | ctx.stroke();
68 | ctx.closePath();
69 | ctx.restore();
70 | }
71 | clearBoard=()=>{
72 | const context = this.canvas.getContext('2d');
73 | context.clearRect(0, 0, this.canvas.width, this.canvas.height);
74 | this.setState({
75 | points:[]
76 | })
77 | }
78 | drawLine=(x1=this.state.points[0].x,y1=this.state.points[0].y,x2=this.state.points[1].x,y2=this.state.points[1].y)=>{
79 | var ctx = this.canvas.getContext("2d");
80 | ctx.setLineDash([]);
81 | ctx.beginPath();
82 | ctx.strokeStyle = "blue";
83 | ctx.moveTo(x1,y1);
84 |
85 | ctx.lineTo(x2,y2);
86 | ctx.stroke();
87 | ctx.closePath();
88 | }
89 | makeCircle=(x,y)=>{
90 | var ctx = this.canvas.getContext("2d");
91 | ctx.beginPath();
92 | ctx.arc(x, y, 10, 0, 2 * Math.PI);
93 | ctx.strokeStyle = "#FF0000";
94 | ctx.stroke();
95 | ctx.closePath()
96 | }
97 |
98 | createRandomNodes=() =>{
99 | var context = this.canvas.getContext("2d");
100 | var num=10
101 | var max_width=this.canvas.width-20;
102 | var max_height=this.canvas.height-20;
103 | this.clearBoard();
104 | var points=[]
105 | for (var i = 0; i <=num; i++) {
106 | var x = Math.floor(Math.random() * (max_width-50)+50);
107 | var y = Math.floor(Math.random() * (max_height-50)+50);
108 | points.push({x,y})
109 |
110 | }
111 | this.setState({
112 | points:points
113 | },this.drawAllNodes)
114 |
115 | }
116 | compare=(a,b)=>{
117 | if(a.x{
122 | var alpha=(b.y-a.y)/(b.x-a.x);
123 | var beta=(c.y-b.y)/(c.x-b.x)
124 | if(alpha>beta)return 1;
125 | else if(beta>alpha)return -1;
126 | return 0;
127 | }
128 | convexHull=(e)=>{
129 | e.preventDefault()
130 | var points=this.state.points;
131 | if(points.length<=2){
132 | var error=document.getElementById("error");
133 | error.innerHTML="The available points is less than three!!";
134 | error.style.display="block";
135 | return;
136 | }
137 | document.getElementById("error").style.display="none";
138 | points.sort(this.compare);
139 | var n=points.length;
140 | var p1=points[0],p2=points[n-1];
141 | var up=[],lo=[];
142 | lo.push(p1);
143 | up.push(p1);
144 | const context = this.canvas.getContext('2d');
145 |
146 | // context.clearRect(0, 0, this.canvas.width, this.canvas.height);
147 | var animate=[]
148 | for(let i=1;i=2&&this.orientation(up[up.length-2],up[up.length-1],points[i])==-1){
152 | up.pop();
153 | animate.push(JSON.parse(JSON.stringify(up)));
154 | }
155 | up.push(points[i]);
156 |
157 | }
158 | if(i==n-1||this.orientation(p1,points[i],p2)!=1){
159 | animate.push(JSON.parse(JSON.stringify(lo)));
160 | while(lo.length>=2&&this.orientation(lo[lo.length-2],lo[lo.length-1],points[i])==1){
161 | lo.pop();
162 | animate.push(JSON.parse(JSON.stringify(lo)));
163 | }
164 | lo.push(points[i])
165 | }
166 | }
167 | animate.push(JSON.parse(JSON.stringify(up)));
168 | animate.push(JSON.parse(JSON.stringify(lo)));
169 | console.log(animate)
170 | var flag;
171 | for(let i=0;i{
174 | // context.clearRect(0, 0, this.canvas.width, this.canvas.height);
175 | this.drawAllNodes();
176 | var temp=animate[i]
177 | for(let j=0;j=0;i--){
189 | result.push(lo[i]);
190 | }
191 | setTimeout(()=>{
192 | context.clearRect(0, 0, this.canvas.width, this.canvas.height);
193 | this.drawAllNodes();
194 | this.makeCircle(p1.x,p1.y);
195 | this.makeCircle(p2.x,p2.y);
196 | for(let i=0;i
206 |
207 | How to use?
208 |
209 | Close
210 |
211 |
212 | ConvexHull Visualizer
213 |
214 |
215 |
216 |
217 |
239 |
240 |
241 |
242 |
243 | )
244 | }
245 | }
246 | export default ConvexHull;
--------------------------------------------------------------------------------
/src/components/Home.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import "../styles/Home.css"
3 | import Logo from "../assets/heading_logo.png";
4 | import convexhull from "../assets/convex_hull.png";
5 | import sorting from "../assets/sorting.png"
6 | import "particles.js";
7 | import particleJSON from "../assets/particles.json";
8 | import pathfinding_front from "../assets/pathfinding_front.svg";
9 | import {ReactComponent as Github} from "../assets/github.svg";
10 | import {ReactComponent as LinkedIn} from "../assets/linkedin.svg";
11 | import {ReactComponent as LogoIcon} from "../assets/analytics.svg";
12 | import bar from "../assets/bar-chart.svg";
13 | import graph from "../assets/graph.svg";
14 | import convex from "../assets/convex.svg";
15 | class Home extends Component{
16 | constructor(){
17 | super();
18 | this.state={
19 | problems:[
20 | {
21 | name:"Sorting",
22 | imgUrl:bar,
23 | link:"/sorting"
24 |
25 | },
26 | {
27 | name:"Pathfinding",
28 | imgUrl:graph,
29 | link:"/pathfind"
30 | },
31 | {
32 | name:"ConvexHull",
33 | imgUrl:convex,
34 | link:"/convexhull"
35 | }
36 | ]
37 | }
38 | }
39 | componentDidMount(){
40 |
41 | window.particlesJS("particles-js",particleJSON );
42 |
43 | }
44 | render(){
45 | return(
46 |
47 |
48 |
49 |
50 |
51 | window.open("https://github.com/arnabuchiha/Algorithm-Visualizer","_blank")}>
52 |
53 |
54 |
55 |
56 | window.open("https://www.linkedin.com/in/funky-poseidon/","_blank")}>
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 | ALGORITHM VISUALIZER
71 |
72 |
73 |
74 | Algorithm Visualizer is an interactive online platform that visualizes algorithms from code.
75 | Currently these include Sorting, Pathfind and ConvexHull Algorithms.
76 | More Algorithms will be coming soon!!
77 |
78 |
79 |
80 | {this.state.problems.map(element=>
81 | window.location.href=element.link}>
82 |
83 |
84 |
85 |
{element.name}
86 |
87 |
88 |
89 | )}
90 |
91 |
92 | )
93 | }
94 | }
95 | export default Home;
--------------------------------------------------------------------------------
/src/components/Instructions/Instruct.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import "./modal.css";
3 | class Instruct extends Component {
4 | // eslint-disable-next-line
5 | constructor(props){
6 | super(props);
7 | }
8 |
9 | render(){
10 |
11 | if(this.props.imageCSS){
12 | this.section="";
13 | this.showHideClassName = this.props.show ? this.props.imageCSS+" display-block" : this.props.imageCSS+" display-none";
14 | }
15 | else{
16 | this.section="modal-main";
17 | this.showHideClassName = this.props.show ? "modal display-block" : "modal display-none";
18 | }
19 | return (
20 |
21 |
22 | {this.props.children}
23 |
24 |
25 |
26 | );
27 | }
28 | };
29 | export default Instruct;
--------------------------------------------------------------------------------
/src/components/Instructions/modal.css:
--------------------------------------------------------------------------------
1 | .modal {
2 | position: fixed;
3 | top: 0;
4 | left: 0;
5 | width:100%;
6 | height: 100%;
7 | background: rgba(0, 0, 0, 0.6);
8 | z-index: 1000;
9 | border-radius: 5px;
10 | }
11 |
12 | .modal-main {
13 | position:fixed;
14 | padding: 10px;
15 | background: white;
16 | width: 80%;
17 | height: auto;
18 | top:50%;
19 | left:50%;
20 | transform: translate(-50%,-50%);
21 | z-index: 1000;
22 | border-radius: 5px;
23 | font-size: 20px;
24 | }
25 |
26 | .display-block {
27 | display: block;
28 | }
29 |
30 | .display-none {
31 | display: none;
32 | }
33 | .modalImage{
34 | position: fixed;
35 | z-index: 1;
36 | padding-top: 100px;
37 | left: 0;
38 | top: 0;
39 | width: 100%;
40 | height: 100%;
41 | overflow: auto;
42 | background-color: rgba(0, 0, 0, 0.6);
43 | }
--------------------------------------------------------------------------------
/src/components/Pathfinding/Node.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 |
3 | class Node extends Component{
4 | constructor(props){
5 | super(props);
6 | this.state={
7 |
8 | }
9 | }
10 | render(){
11 | const {
12 | isWall,
13 | isStart,
14 | isEnd,
15 | isVisited,
16 | isShortestPath,
17 | onMouseDown,
18 | row,
19 | col,
20 | onMouseEnter,
21 | onMouseUp,
22 | onMouseLeave
23 | }=this.props;
24 | const cName=isStart?"start":isEnd?"end":isWall?"wall":isShortestPath?"path":isVisited?"visited":"";
25 | return(
26 | onMouseDown(row,col)}
29 | onMouseEnter={()=>onMouseEnter(row,col)}
30 | onMouseUp={()=>onMouseUp()}
31 | onMouseLeave={()=>onMouseLeave(row,col)}
32 | // onTouchStart={()=>onMouseDown(row,col)}
33 | // onTouchEnd={()=>onMouseLeave(row,col)}
34 | // onTouchMove={()=>onMouseEnter(row,col)}
35 | >
36 | )
37 | }
38 | }
39 | export default Node;
--------------------------------------------------------------------------------
/src/components/Pathfinding/Pathfinding.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import "../../styles/Pathfinding.css";
3 | import Node from "./Node";
4 | import PriorityQueue from "js-priority-queue";
5 | import Dijkstra from "./algorithms/Dijkstra";
6 | import Instruct from "../Instructions/Instruct";
7 | import instruct_gif from "../../assets/pathfinder.gif";
8 | import { NavLink } from "react-router-dom";
9 | function node(row,col,dis){
10 | return({
11 | row,
12 | col,
13 | dis
14 | })
15 | }
16 |
17 | class Pathfinding extends Component{
18 | constructor(){
19 | super();
20 | this.state={
21 | method:"Algorithms",
22 | grid:[],
23 | mouseClicked:false,
24 | mainClicked:"",
25 | start_node:null,
26 | end_node:null,
27 | visited:0,
28 | shortestPath:0,
29 | number_of_nodes:0,
30 | algo_info:{
31 | "Algorithms":{
32 | text:"",
33 | url:""
34 | },
35 | "Dijkstra's Algorithm":{
36 | text:"Dijkstra’s algorithm is very similar to Prim’s algorithm for minimum spanning tree. Like Prim’s MST, we generate a SPT (shortest path tree) with given source as root. We maintain two sets, one set contains vertices included in shortest path tree, other set includes vertices not yet included in shortest path tree. At every step of the algorithm, we find a vertex which is in the other set (set of not yet included) and has a minimum distance from the source.",
37 | url:"https://www.geeksforgeeks.org/dijkstras-shortest-path-algorithm-greedy-algo-7/"
38 | },
39 | "A* Search":{
40 | text:"Informally speaking, A* Search algorithms, unlike other traversal techniques, it has “brains”. What it means is that it is really a smart algorithm which separates it from the other conventional algorithms. This fact is cleared in detail in below sections. And it is also worth mentioning that many games and web-based maps use this algorithm to find the shortest path very efficiently (approximation).",
41 | url:"https://www.geeksforgeeks.org/a-search-algorithm/"
42 | },
43 | "Breadth First Search":{
44 | text:"In Progress",
45 | url:"https://www.geeksforgeeks.org/a-search-algorithm/"
46 | }
47 | },
48 | showModal:true
49 |
50 | }
51 | this.animating=false;
52 | }
53 |
54 |
55 | makeGrid=()=>{
56 | if(this.animating)return;
57 | let row_size=Math.floor((window.innerHeight-60)/27);
58 | let col_size=Math.floor((window.innerWidth)/27);
59 | let arr=[]
60 | for(let i=0;i{
100 | this.makeGrid();
101 | })
102 | }
103 | handleMouseDown=(row,col)=>{
104 | if(this.animating)return;
105 | let arr=this.state.grid;
106 | if(arr[row][col].isStart){
107 | this.setState({
108 | mainClicked:"start"
109 | })
110 | }
111 | else if(arr[row][col].isEnd){
112 | this.setState({
113 | mainClicked:"end"
114 | })
115 | }
116 | if(!arr[row][col].isWall&&!arr[row][col].isStart&&!arr[row][col].isEnd)
117 | arr[row][col].isWall=true;
118 | else if(arr[row][col].isWall){
119 | arr[row][col].isWall=false;
120 | }
121 | this.setState({
122 | grid:arr,
123 | mouseClicked:true
124 | })
125 | }
126 | handleMouseEnter=(row,col)=>{
127 | if(this.animating)return;
128 | if(this.state.mouseClicked){
129 | let arr=this.state.grid;
130 | if(this.state.mainClicked=="start"){
131 | arr[row][col].isStart=true;
132 | this.setState({
133 | start_node:[row,col]
134 | })
135 | }
136 | else if(this.state.mainClicked=="end"){
137 | arr[row][col].isEnd=true;
138 | this.setState({
139 | end_node:[row,col]
140 | })
141 | }
142 | else if(!arr[row][col].isWall&&!arr[row][col].isStart&&!arr[row][col].isEnd)
143 | arr[row][col].isWall=true;
144 | else if(arr[row][col].isWall){
145 | arr[row][col].isWall=false;
146 | }
147 | this.setState({
148 | grid:arr,
149 | mouseClicked:true
150 | })
151 | }
152 |
153 | }
154 | handleMouseLeave=(row,col)=>{
155 | if(this.animating)return;
156 | let arr=this.state.grid;
157 | if(this.state.mainClicked!=""){
158 | arr[row][col].isStart=0;
159 | arr[row][col].isEnd=0;
160 | this.setState({
161 | grid:arr
162 | })
163 | }
164 |
165 | }
166 | handleMouseUp=()=>{
167 |
168 | if(this.animating)return;
169 | this.setState({
170 | mouseClicked:false,
171 | mainClicked:""
172 | })
173 | }
174 | isInsideGrid=(i,j) =>
175 | {
176 | return (i >= 0 && i < this.state.grid.length && j >= 0 && j < this.state.grid[0].length);
177 | }
178 | dijkshtra=(e)=>{
179 | e.preventDefault();
180 | if(this.animating)return;
181 | let arr=this.state.grid;
182 | for(let i=0;i{
195 |
196 | let i=0;
197 | let j=0;
198 | this.animating=true;
199 | const animateVisited=()=>{
200 | if(i==visited_nodes.length){
201 | requestAnimationFrame(animatePath);
202 | return;
203 | }
204 | arr[visited_nodes[i].row][visited_nodes[i].col].isVisited=true;
205 | // this.setState({
206 | // grid:arr
207 | // })
208 | if(!arr[visited_nodes[i].row][visited_nodes[i].col].isStart&&!arr[visited_nodes[i].row][visited_nodes[i].col].isEnd)
209 | document.getElementById(`node-${visited_nodes[i].row}-${visited_nodes[i].col}`).className="node_visited";
210 | ++i;
211 | requestAnimationFrame(animateVisited);
212 | // setTimeout(() => {
213 |
214 | // }, 1000 / 1000);
215 | }
216 |
217 | const animatePath=()=>{
218 | if(j==shortestPath.length){
219 | this.setState({
220 | grid:arr,
221 | visited:visited_nodes.length,
222 | shortestPath:shortestPath.length
223 | })
224 | this.animating=false;
225 | return;
226 | }
227 | arr[shortestPath[j].row][shortestPath[j].col].isShortestPath=true;
228 |
229 | if(!arr[shortestPath[j].row][shortestPath[j].col].isStart&&!arr[shortestPath[j].row][shortestPath[j].col].isEnd)
230 | document.getElementById(`node-${shortestPath[j].row}-${shortestPath[j].col}`).className="node_path";
231 | ++j;
232 |
233 | requestAnimationFrame(animatePath);
234 | }
235 | await requestAnimationFrame(animateVisited);
236 | }
237 | animate().then(()=>{
238 |
239 | });
240 | }
241 | toggleChat=()=>{
242 | var chatBody = document.getElementById("info-body");
243 | if(chatBody.style.display=='none') {
244 |
245 | chatBody.style.display = 'block';
246 | return;
247 | } else {
248 |
249 | chatBody.style.display = 'none';
250 | return;
251 | }
252 | }
253 | showModal = () => {
254 | this.setState({
255 | showModal: true
256 | });
257 | };
258 |
259 | hideModal = () => {
260 | this.setState({ showModal: false });
261 | };
262 | componentDidUpdate(){
263 | let method=this.state.method
264 | if(method!="Algorithms"){
265 | document.getElementById("info-btn").style.display="block";
266 | }
267 | }
268 | render(){
269 | return(
270 |
271 |
272 | How to use?
273 |
274 | Close
275 |
276 |
277 | Pathfinding Visualizer
278 |
279 |
280 |
281 |
282 |
327 |
328 |
329 | {
330 | this.state.grid.map((row,index)=>{
331 | return(
332 |
333 | {
334 | row.map((element,i)=>{
335 | return(
336 | this.handleMouseDown(row,col)}
347 | onMouseEnter={(row,col)=>this.handleMouseEnter(row,col)}
348 | onMouseUp={()=>this.handleMouseUp()}
349 | onMouseLeave={(row,col)=>this.handleMouseLeave(row,col)}
350 | />
351 | )
352 | })
353 | }
354 |
355 | )
356 | })
357 | }
358 |
359 |
360 |
ℹ
361 |
362 |
363 |
364 |
{this.state.method}
365 |
{this.state.algo_info[this.state.method].text}
366 |
More Info
367 |
368 |
369 |
370 |
371 |
372 | )
373 | }
374 | }
375 |
376 | export default Pathfinding;
--------------------------------------------------------------------------------
/src/components/Pathfinding/algorithms/Dijkstra.js:
--------------------------------------------------------------------------------
1 | import PriorityQueue from "js-priority-queue";
2 | function isInsideGrid(i,j,grid)
3 | {
4 | return (i >= 0 && i < grid.length && j >= 0 && j < grid[0].length);
5 | }
6 | const dijkstra = (grid, startNode, endNode) => {
7 |
8 | let arr=grid;
9 | let visited_nodes=[];
10 | let shortestPath=[];
11 | let start_node=startNode;
12 | let end_node=endNode;
13 | let pq=new PriorityQueue({
14 | comparator:function(a,b){
15 | return a.distance-b.distance;
16 | }
17 | });
18 | for(let i=0;i= 0 && i < grid.length && j >= 0 && j < grid[0].length);
5 | }
6 | const astar = (grid, startNode, endNode) => {
7 |
8 | let arr=grid;
9 | let visited_nodes=[];
10 | let shortestPath=[];
11 | let start_node=startNode;
12 | let end_node=endNode;
13 | let pq=new PriorityQueue({
14 | comparator:function(a,b){
15 | return a.distance-b.distance;
16 | }
17 | });
18 | for(let i=0;i{
30 | let arr=[];
31 | for(let i=0;i{
47 | this.createArray(e.target.value)
48 | }
49 | componentDidMount(){
50 | this.createArray();
51 | window.addEventListener("resize",(e)=>{
52 | this.createArray();
53 | })
54 | }
55 | randomize=()=>{
56 | this.createArray(this.state.length)
57 | }
58 | sortFunc=(e)=>{
59 | e.preventDefault();
60 | var arr=this.state.arr;
61 | let length=this.state.arr.length;
62 | var results=[]
63 | document.getElementById('error').style="display:none";
64 | if(this.state.method=="Algorithms"){
65 | document.getElementById('error').style="display:block";
66 | }
67 | else{
68 | if(this.state.method=="Selection Sort")
69 | results=selectionSort(arr,length);
70 | else if(this.state.method=="Merge Sort")
71 | results=mergeSort(arr,length);
72 | else if(this.state.method=="Quick Sort")
73 | results=quickSort(arr,length);
74 | for(let i=0;i{
76 | this.setState({
77 | arr:results[i]
78 | })
79 | },this.state.speed*i)
80 | }
81 | }
82 |
83 | }
84 |
85 | changeSpeed=(e)=>{
86 | this.setState({
87 | speed:1100-e.target.value
88 | })
89 | }
90 | render(){
91 | return(
92 |
93 |
94 | Sorting
95 |
96 |
97 |
98 |
99 |
141 |
142 |
143 | {
144 | (this.state.arr.map((element,index) =>
145 |
152 |
153 | {element.value}
154 |
155 |
156 | ))}
157 |
158 |
159 | )
160 | }
161 | }
162 | export default Sorting;
--------------------------------------------------------------------------------
/src/components/Sorting/algorithms/MergeSort.js:
--------------------------------------------------------------------------------
1 | const mergeSort=(arr,length)=>{
2 | // console.log(arr);
3 | var result=[]
4 | sort(arr,0,length-1,result);
5 | arr.forEach(element => {
6 | element.style="bar-sorted";
7 | });
8 | result.push(JSON.parse(JSON.stringify(arr)));
9 | return result;
10 | // console.log(result);
11 | }
12 | function sort(arr,l,r,result){
13 | if(l{
2 | var result=[]
3 | sort(arr,0,length-1,result);
4 | arr.forEach(element => {
5 | element.style="bar-sorted";
6 | });
7 | result.push(JSON.parse(JSON.stringify(arr)));
8 | return result;
9 | }
10 | function sort(arr,l,h,result){
11 | if(l{
2 | var results=[];
3 | for(let i=0;i
9 |
10 | ,
11 | document.getElementById('root')
12 | );
13 |
14 | // If you want your app to work offline and load faster, you can change
15 | // unregister() to register() below. Note this comes with some pitfalls.
16 | // Learn more about service workers: https://bit.ly/CRA-PWA
17 | serviceWorker.unregister();
18 |
--------------------------------------------------------------------------------
/src/logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/src/serviceWorker.js:
--------------------------------------------------------------------------------
1 | // This optional code is used to register a service worker.
2 | // register() is not called by default.
3 |
4 | // This lets the app load faster on subsequent visits in production, and gives
5 | // it offline capabilities. However, it also means that developers (and users)
6 | // will only see deployed updates on subsequent visits to a page, after all the
7 | // existing tabs open on the page have been closed, since previously cached
8 | // resources are updated in the background.
9 |
10 | // To learn more about the benefits of this model and instructions on how to
11 | // opt-in, read https://bit.ly/CRA-PWA
12 |
13 | const isLocalhost = Boolean(
14 | window.location.hostname === 'localhost' ||
15 | // [::1] is the IPv6 localhost address.
16 | window.location.hostname === '[::1]' ||
17 | // 127.0.0.0/8 are considered localhost for IPv4.
18 | window.location.hostname.match(
19 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
20 | )
21 | );
22 |
23 | export function register(config) {
24 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
25 | // The URL constructor is available in all browsers that support SW.
26 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href);
27 | if (publicUrl.origin !== window.location.origin) {
28 | // Our service worker won't work if PUBLIC_URL is on a different origin
29 | // from what our page is served on. This might happen if a CDN is used to
30 | // serve assets; see https://github.com/facebook/create-react-app/issues/2374
31 | return;
32 | }
33 |
34 | window.addEventListener('load', () => {
35 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
36 |
37 | if (isLocalhost) {
38 | // This is running on localhost. Let's check if a service worker still exists or not.
39 | checkValidServiceWorker(swUrl, config);
40 |
41 | // Add some additional logging to localhost, pointing developers to the
42 | // service worker/PWA documentation.
43 | navigator.serviceWorker.ready.then(() => {
44 | console.log(
45 | 'This web app is being served cache-first by a service ' +
46 | 'worker. To learn more, visit https://bit.ly/CRA-PWA'
47 | );
48 | });
49 | } else {
50 | // Is not localhost. Just register service worker
51 | registerValidSW(swUrl, config);
52 | }
53 | });
54 | }
55 | }
56 |
57 | function registerValidSW(swUrl, config) {
58 | navigator.serviceWorker
59 | .register(swUrl)
60 | .then(registration => {
61 | registration.onupdatefound = () => {
62 | const installingWorker = registration.installing;
63 | if (installingWorker == null) {
64 | return;
65 | }
66 | installingWorker.onstatechange = () => {
67 | if (installingWorker.state === 'installed') {
68 | if (navigator.serviceWorker.controller) {
69 | // At this point, the updated precached content has been fetched,
70 | // but the previous service worker will still serve the older
71 | // content until all client tabs are closed.
72 | console.log(
73 | 'New content is available and will be used when all ' +
74 | 'tabs for this page are closed. See https://bit.ly/CRA-PWA.'
75 | );
76 |
77 | // Execute callback
78 | if (config && config.onUpdate) {
79 | config.onUpdate(registration);
80 | }
81 | } else {
82 | // At this point, everything has been precached.
83 | // It's the perfect time to display a
84 | // "Content is cached for offline use." message.
85 | console.log('Content is cached for offline use.');
86 |
87 | // Execute callback
88 | if (config && config.onSuccess) {
89 | config.onSuccess(registration);
90 | }
91 | }
92 | }
93 | };
94 | };
95 | })
96 | .catch(error => {
97 | console.error('Error during service worker registration:', error);
98 | });
99 | }
100 |
101 | function checkValidServiceWorker(swUrl, config) {
102 | // Check if the service worker can be found. If it can't reload the page.
103 | fetch(swUrl, {
104 | headers: { 'Service-Worker': 'script' },
105 | })
106 | .then(response => {
107 | // Ensure service worker exists, and that we really are getting a JS file.
108 | const contentType = response.headers.get('content-type');
109 | if (
110 | response.status === 404 ||
111 | (contentType != null && contentType.indexOf('javascript') === -1)
112 | ) {
113 | // No service worker found. Probably a different app. Reload the page.
114 | navigator.serviceWorker.ready.then(registration => {
115 | registration.unregister().then(() => {
116 | window.location.reload();
117 | });
118 | });
119 | } else {
120 | // Service worker found. Proceed as normal.
121 | registerValidSW(swUrl, config);
122 | }
123 | })
124 | .catch(() => {
125 | console.log(
126 | 'No internet connection found. App is running in offline mode.'
127 | );
128 | });
129 | }
130 |
131 | export function unregister() {
132 | if ('serviceWorker' in navigator) {
133 | navigator.serviceWorker.ready
134 | .then(registration => {
135 | registration.unregister();
136 | })
137 | .catch(error => {
138 | console.error(error.message);
139 | });
140 | }
141 | }
142 |
--------------------------------------------------------------------------------
/src/setupTests.js:
--------------------------------------------------------------------------------
1 | // jest-dom adds custom jest matchers for asserting on DOM nodes.
2 | // allows you to do things like:
3 | // expect(element).toHaveTextContent(/react/i)
4 | // learn more: https://github.com/testing-library/jest-dom
5 | import '@testing-library/jest-dom/extend-expect';
6 |
--------------------------------------------------------------------------------
/src/styles/ConvexHull.css:
--------------------------------------------------------------------------------
1 |
2 | /* @media only screen and (max-width: 800px) {
3 | .canvas {
4 | background-color: #ffffff;
5 | background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100' height='100' viewBox='0 0 100 100'%3E%3Cg fill-rule='evenodd'%3E%3Cg fill='%23343a40' fill-opacity='0.21'%3E%3Cpath opacity='.5' d='M96 95h4v1h-4v4h-1v-4h-9v4h-1v-4h-9v4h-1v-4h-9v4h-1v-4h-9v4h-1v-4h-9v4h-1v-4h-9v4h-1v-4h-9v4h-1v-4h-9v4h-1v-4H0v-1h15v-9H0v-1h15v-9H0v-1h15v-9H0v-1h15v-9H0v-1h15v-9H0v-1h15v-9H0v-1h15v-9H0v-1h15v-9H0v-1h15V0h1v15h9V0h1v15h9V0h1v15h9V0h1v15h9V0h1v15h9V0h1v15h9V0h1v15h9V0h1v15h9V0h1v15h4v1h-4v9h4v1h-4v9h4v1h-4v9h4v1h-4v9h4v1h-4v9h4v1h-4v9h4v1h-4v9h4v1h-4v9zm-1 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-9-10h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm9-10v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-9-10h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm9-10v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-9-10h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm9-10v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-9-10h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9z'/%3E%3Cpath d='M6 5V0H5v5H0v1h5v94h1V6h94V5H6z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E");
6 | border: 1px solid black;
7 | margin: 5px;
8 | margin-top: 50px;
9 | width: 90%;
10 | height: 80vh;
11 | }
12 | }
13 | @media only screen and (min-width:800px){
14 |
15 | } */
16 | .canvas{
17 | background-color: #ffffff;
18 | background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100' height='100' viewBox='0 0 100 100'%3E%3Cg fill-rule='evenodd'%3E%3Cg fill='%23343a40' fill-opacity='0.21'%3E%3Cpath opacity='.5' d='M96 95h4v1h-4v4h-1v-4h-9v4h-1v-4h-9v4h-1v-4h-9v4h-1v-4h-9v4h-1v-4h-9v4h-1v-4h-9v4h-1v-4h-9v4h-1v-4h-9v4h-1v-4H0v-1h15v-9H0v-1h15v-9H0v-1h15v-9H0v-1h15v-9H0v-1h15v-9H0v-1h15v-9H0v-1h15v-9H0v-1h15v-9H0v-1h15V0h1v15h9V0h1v15h9V0h1v15h9V0h1v15h9V0h1v15h9V0h1v15h9V0h1v15h9V0h1v15h9V0h1v15h4v1h-4v9h4v1h-4v9h4v1h-4v9h4v1h-4v9h4v1h-4v9h4v1h-4v9h4v1h-4v9h4v1h-4v9zm-1 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-9-10h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm9-10v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-9-10h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm9-10v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-9-10h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm9-10v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-9-10h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9z'/%3E%3Cpath d='M6 5V0H5v5H0v1h5v94h1V6h94V5H6z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E");
19 | border: 1px solid black;
20 | margin: 5px;
21 | margin-top: 50px;
22 | border-radius: 10px;
23 | /* width: 90vw;
24 | height: 80vh; */
25 | }
--------------------------------------------------------------------------------
/src/styles/Home.css:
--------------------------------------------------------------------------------
1 | @font-face {
2 | font-family: Anurati;
3 | src: url(../assets/Anurati-Regular.otf);
4 | }
5 | :root{
6 | --home-color: #2ED327;
7 | }
8 | .algo-name {
9 | font-size: 18px;
10 | font-weight: 700;
11 | color:white;
12 | }
13 | .card{
14 | background-color: transparent;
15 | }
16 | .card::after{
17 | content: "";
18 | bottom: 0;
19 | top: 0;
20 | left: 0;
21 | position: absolute;
22 | height: 50%;
23 | width: 5px;
24 | color: #fff;
25 | }
26 | .algo-image{
27 | height: 175px;
28 | width: auto;
29 | object-fit:cover;
30 | fill: var(--home-color);
31 | background-color: transparent;
32 | }
33 | .back{
34 | background-color: #0E0E0E;
35 | min-height: 100vh;
36 | }
37 | #particles-js {
38 | position: absolute;
39 | width: 100%;
40 | height: 100%;
41 | background-color: transparent;
42 | background-image: url("");
43 | background-repeat: no-repeat;
44 | background-size: cover;
45 | background-position: 50% 50%;
46 | z-index: 0;
47 | top:0;
48 | left:0;
49 | }
50 |
51 | .logo{
52 | /* left: 50%;
53 | transform: translate( -50%,0); */
54 | position: relative;
55 | z-index: 100;
56 | float:top;
57 | }
58 | .links li{
59 | cursor: pointer;
60 | margin: 10px;
61 | fill: var(--home-color)!important;
62 | margin-top: 25px;
63 | /* display: inline; */
64 | }
65 | .links li svg{
66 | height: 20px;
67 | width: auto;
68 | }
69 | .links{
70 | position: sticky;
71 | z-index: 100;
72 | display: flex;
73 | list-style: none;
74 | vertical-align: top;
75 | float: left;
76 | cursor: pointer;
77 | /* position: absolute; */
78 | /* display: flex;
79 | flex-direction: row; */
80 | /* Below sets up your display method: flex-start|flex-end|space-between|space-around */
81 | justify-content: flex-start;
82 | /* Below removes bullets and cleans white-space */
83 | list-style: none;
84 | padding: 0;
85 | /* Bonus: forces no word-wrap */
86 | white-space: nowrap;
87 | }
88 | .main-title{
89 | font-size: 3rem;
90 | color: white;
91 | padding-top: 18vh;
92 | font-family: Anurati, sans-serif;
93 | letter-spacing: 5px;
94 | }
95 |
96 | .main-title svg{
97 | fill: var(--home-color);
98 | margin-bottom: 30px;
99 | height: 80px;
100 | width: auto;
101 | }
102 | .description-title{
103 | color: white;
104 | width: 50%;
105 | margin: auto;
106 | }
--------------------------------------------------------------------------------
/src/styles/Pathfinding.css:
--------------------------------------------------------------------------------
1 | td {
2 | border: 1px solid #5bc9b1;
3 | width: 25px;
4 | height: 25px;
5 | }
6 | tr {
7 | display: table-row;
8 | vertical-align: inherit;
9 | border-color: inherit;
10 | }
11 | table{
12 | position: absolute;
13 | top: 50%;
14 | left: 50%;
15 | margin-right: -50%;
16 | transform: translate(-50%, -50%);
17 | z-index: -1;
18 | }
19 | .node_start{
20 | background: url("../assets/space-ship.svg");
21 | background-size: cover;
22 | }
23 | .node_end{
24 | background: url("../assets/planet.svg");
25 | background-size: cover;
26 | }
27 | .node_wall{
28 | /* background: url("../assets/asteroid.svg"); */
29 | animation: pulse 0.5s 1;
30 | background-color: #202220;
31 | border: 1px solid #202220;
32 | }
33 |
34 | @keyframes pulse{
35 | 0%{
36 | background-color: grey;
37 |
38 | }
39 | 100%{
40 | background-color: #202220;
41 | }
42 | }
43 | .node_visited{
44 | /* background-color: lightseagreen; */
45 | background-color: rgba(4, 0, 255, 0.5);
46 | animation-name: visited;
47 | animation-duration: 1.2s;
48 | animation-iteration-count: 1;
49 | animation-direction: alternate;
50 | }
51 | @keyframes visited{
52 | 0% {
53 | transform: scale(0.3);
54 | background-color: rgba(255, 0, 191, 0.5);
55 | border-radius: 100%;
56 | }
57 |
58 | 50% {
59 | background-color: rgba(255, 0, 191, 0.5);
60 | }
61 |
62 | 75% {
63 | transform: scale(1.2);
64 | background-color: rgba(4, 0, 255, 0.5);
65 | }
66 |
67 | 100% {
68 | transform: scale(1);
69 | background-color:rgba(4, 0, 255, 0.5);
70 | }
71 | }
72 | .node_path{
73 | background-color: greenyellow;
74 | animation-name: path_anime;
75 | animation-duration: 2s;
76 | animation-timing-function: ease-out;
77 | animation-delay: 0;
78 | animation-direction: alternate;
79 | /* animation-iteration-count: infinite; */
80 | animation-fill-mode: none;
81 | animation-play-state: running;
82 | }
83 |
84 | @keyframes path_anime{
85 | 0% {
86 | transform: scale(0.3);
87 | background-color: red;
88 | border-radius: 100%;
89 | }
90 | 50% {
91 | background-color: orange;
92 | }
93 | 100% {
94 | transform: scale(1);
95 | background-color: yellow;
96 | }
97 | }
98 | .chat-container {
99 | display: flex;
100 | flex-direction: column;
101 | align-items: center;
102 | }
103 | .chat-btn {
104 | height: 50px;
105 | width: 50px;
106 | text-align: center;
107 | font-size: 2rem;
108 | color: #fff;
109 | background-color: #343A40;
110 | border: 1px solid #343A40;
111 | border-radius: 25px 25px;
112 | position: fixed;
113 | bottom: 10px;
114 | right: 10px;
115 | cursor: pointer;
116 |
117 | display: none;
118 | }
119 | .chat-btn:focus{
120 | animation: shadow-pulse 1s infinite;
121 | outline:none;
122 | }
123 | @keyframes shadow-pulse {
124 | 0% {
125 | box-shadow: 0 0 0 0 #343A40;
126 | }
127 | 100% {
128 | box-shadow: 0 0 0 20px rgba(130, 90, 164, 0);
129 | }
130 | }
131 | .chat-body {
132 | height: auto;
133 | width: auto;
134 | min-width: 10vw;
135 | /* min-height: 300px;
136 | min-width: 300px; */
137 | background:#343A40;
138 | position: absolute;
139 | bottom: 60px;
140 | right: 60px;
141 | box-shadow: 4px 4px 4px gray;
142 | border-radius: 8px;
143 | color: black;
144 | padding: 8px;
145 | margin-left: 10px;
146 | }
147 | .chat-body .chat-head {
148 | background: #343A40;
149 | padding: 10px;
150 | height: 20px;
151 | font-family: verdana;
152 | }
153 | .progress2 {
154 | border-radius: 30px;
155 | background-color: gray;
156 | }
157 |
158 | .progress-bar2 {
159 | height: 5px;
160 | border-radius: 30px;
161 | transition: 0.4s linear;
162 | transition-property: width, background-color;
163 | }
164 |
165 | .progress-moved .progress-bar2 {
166 | background-color: #f3c623;
167 | animation: progress 5s 1;
168 | }
169 | @keyframes progress {
170 | 0% {
171 | width: 0%;
172 | background: #f9bcca;
173 | }
174 |
175 | 60% {
176 | /* width: 60%; */
177 | background: #f3c623;
178 | box-shadow: 0 0 40px #f3c623;
179 | }
180 | }
181 | .progress-text{
182 | color: black;
183 | }
184 | .progress-text:hover .comment{
185 | display: block;
186 | }
187 | .progress-text:hover .span-text{
188 | display: none;
189 | }
190 | .comment{
191 | display: none;
192 | }
193 | .info-title{
194 | font-size: 2.125rem;
195 | font-weight: 400;
196 | line-height: 1.235;
197 | }
198 | ::-webkit-scrollbar {
199 | width: 5px;
200 | }
201 | ::-webkit-scrollbar-track {
202 | background: #f1f1f1;
203 | }
204 | ::-webkit-scrollbar-thumb {
205 | background: #888;
206 | }
207 | ::-webkit-scrollbar-thumb:hover {
208 | background: #555;
209 | }
--------------------------------------------------------------------------------
/src/styles/Sorting.css:
--------------------------------------------------------------------------------
1 | .bar{
2 | padding-top: 7px;
3 | font-family: sans-serif;
4 | font-weight: 700;
5 | display: inline-block;
6 | color:white;
7 | width:40px;
8 | margin-left:6px;
9 | background-color:#5bc9b1;
10 | }
11 | .bar-sorted{
12 | background-color:#b979ec;
13 |
14 | }
15 | .bar-swap{
16 | background-color:#57a846;
17 | }
18 | .bar-min{
19 | background-color: red;
20 | }
21 | .bars{
22 |
23 | /* display: -webkit-box;
24 | display: -webkit-flex;
25 | display: flex;
26 | -webkit-box-orient: horizontal;
27 | -webkit-flex-direction: horizontal;
28 | flex-direction: horizontal;
29 | -webkit-box-align: start;
30 | -webkit-align-items: flex-start;
31 | align-items: flex-start;
32 | position: absolute;
33 | top: 50%;
34 | left: 50%;
35 | margin-right: -50%;
36 | transform: translate(-50%, -50%);
37 | z-index: -1; */
38 | }
--------------------------------------------------------------------------------