├── .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 | Algo Visualizer 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 | ![Branch master](https://img.shields.io/badge/branch-master-brightgreen.svg?style=flat-square) [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](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 | 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 | Card image cap 209 | 210 |
211 | 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 | Card image cap 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 | Card image cap 274 | 275 |
276 | 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 |
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 | } --------------------------------------------------------------------------------