├── .gitignore
├── README.md
├── newer_ui_tailwind.JPG
├── older_ui.JPG
├── package-lock.json
├── package.json
├── postcss.config.js
├── public
├── favicon.ico
├── index.html
├── logo192.png
├── logo512.png
├── manifest.json
└── robots.txt
├── sorting_visualizer.gif
├── src
├── App.css
├── App.js
├── SortingAlgorithms
│ ├── BubbleSort.js
│ ├── HeapSort.js
│ ├── InsertionSort.js
│ ├── MergeSort.js
│ ├── QuickSort.js
│ └── SelectionSort.js
├── SortingVisualizer
│ ├── SortingVisualizer.css
│ └── SortingVisualizer.js
└── index.js
├── styles.css
└── tailwind.config.js
/.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 |
25 | .cursorrules
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Sorting Visualizer
2 | A visualization for various sorting algorithms like merge sort, heap sort, quick sort, insertion sort, bubble sort and selection sort.
3 | Access it using this link https://csals.github.io/Sorting-Visualizer/
4 |
5 | Rewrote it with **Cursor + Claude** to enhance the UI and complete all the TODOs
6 |
7 | ## before & after
8 |
9 | Before:
10 | 
11 |
12 | After:
13 | 
14 |
15 |
16 | ## NOTES
17 | - in every sorting algo I am returning two comparisions.
18 | - that's because when I am comparing 2 bars first I will change their color to red and again need to change to original color
19 | - for that reason every time 2 bars are compared we need 2 comparisions
20 |
21 |
22 | - Huge thanks to [Clément Mihailescu](https://github.com/clementmihailescu) for this project idea.
23 |
--------------------------------------------------------------------------------
/newer_ui_tailwind.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CSALS/Sorting-Visualizer/e4b5409ea5d0eb856c04bfb9a68e936bd071de44/newer_ui_tailwind.JPG
--------------------------------------------------------------------------------
/older_ui.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CSALS/Sorting-Visualizer/e4b5409ea5d0eb856c04bfb9a68e936bd071de44/older_ui.JPG
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "sorting-visualizer",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "react": "^16.11.0",
7 | "react-dom": "^16.11.0",
8 | "react-scripts": "^5.0.1"
9 | },
10 | "homepage": "http://CSALS.github.io/Sorting-Visualizer",
11 | "scripts": {
12 | "start": "react-scripts start",
13 | "build": "react-scripts build",
14 | "test": "react-scripts test",
15 | "eject": "react-scripts eject",
16 | "predeploy": "npm run build",
17 | "deploy": "gh-pages -d build"
18 | },
19 | "eslintConfig": {
20 | "extends": "react-app"
21 | },
22 | "browserslist": {
23 | "production": [
24 | ">0.2%",
25 | "not dead",
26 | "not op_mini all"
27 | ],
28 | "development": [
29 | "last 1 chrome version",
30 | "last 1 firefox version",
31 | "last 1 safari version"
32 | ]
33 | },
34 | "devDependencies": {
35 | "autoprefixer": "^10.4.20",
36 | "gh-pages": "^6.1.1",
37 | "postcss": "^8.4.41",
38 | "tailwindcss": "^3.4.10"
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {},
5 | },
6 | }
7 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CSALS/Sorting-Visualizer/e4b5409ea5d0eb856c04bfb9a68e936bd071de44/public/favicon.ico
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 |
13 |
17 |
18 |
27 | Sorting Visualizer
28 |
29 |
30 |
31 |
32 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/public/logo192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CSALS/Sorting-Visualizer/e4b5409ea5d0eb856c04bfb9a68e936bd071de44/public/logo192.png
--------------------------------------------------------------------------------
/public/logo512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CSALS/Sorting-Visualizer/e4b5409ea5d0eb856c04bfb9a68e936bd071de44/public/logo512.png
--------------------------------------------------------------------------------
/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
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": "#fcfcfc",
24 | "background_color": "#fcfcfc"
25 | }
26 |
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 |
--------------------------------------------------------------------------------
/sorting_visualizer.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CSALS/Sorting-Visualizer/e4b5409ea5d0eb856c04bfb9a68e936bd071de44/sorting_visualizer.gif
--------------------------------------------------------------------------------
/src/App.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
4 |
5 | html,body {
6 | height:100%;
7 | width:100%;
8 | margin: 0;
9 | padding: 0;
10 | }
11 | body {
12 | background: #DAE0E2;
13 | }
14 | .App {
15 | }
16 |
--------------------------------------------------------------------------------
/src/App.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import SortingVisualizer from './SortingVisualizer/SortingVisualizer'
3 | import './App.css'
4 |
5 | function App() {
6 | return (
7 |
8 |
9 |
10 | );
11 | }
12 |
13 | export default App;
--------------------------------------------------------------------------------
/src/SortingAlgorithms/BubbleSort.js:
--------------------------------------------------------------------------------
1 | export function getBubbleSortAnimations(array) {
2 | let animations = [];
3 | let auxillaryArray = array.slice();
4 | bubbleSort(auxillaryArray, animations);
5 | const javaScriptSortedArray = array.slice().sort((a, b) => a - b);
6 | console.log("sort works correctly? ",arraysAreEqual(javaScriptSortedArray, auxillaryArray));
7 | array = auxillaryArray;
8 | return [animations, array];
9 | }
10 |
11 | function bubbleSort(auxillaryArray, animations) {
12 | const N = auxillaryArray.length;
13 | let iters = N - 1;
14 | while(iters > 0) {
15 | let swapped = false;
16 | for(let i = 0; i < iters; ++i) {
17 | animations.push(["comparision1", i, i + 1]);
18 | animations.push(["comparision2", i, i + 1]);
19 | if(auxillaryArray[i] > auxillaryArray[i + 1]) {
20 | swapped = true;
21 | animations.push(["swap", i, auxillaryArray[i + 1]]);
22 | animations.push(["swap", i + 1, auxillaryArray[i]]);
23 | swap(auxillaryArray, i, i + 1);
24 | }
25 | }
26 | if(swapped === false) break;
27 | iters--;
28 | }
29 | }
30 |
31 | function swap(auxillaryArray, firstIndex, secondIndex) {
32 | let temp = auxillaryArray[firstIndex];
33 | auxillaryArray[firstIndex] = auxillaryArray[secondIndex];
34 | auxillaryArray[secondIndex] = temp;
35 | }
36 |
37 | function arraysAreEqual(firstArray, secondArray) {
38 | if (firstArray.length !== secondArray.length) {
39 | return false;
40 | }
41 | for (let i = 0; i < firstArray.length; i++) {
42 | if (firstArray[i] !== secondArray[i]) {
43 | return false;
44 | }
45 | }
46 | return true;
47 | }
--------------------------------------------------------------------------------
/src/SortingAlgorithms/HeapSort.js:
--------------------------------------------------------------------------------
1 | export function getHeapSortAnimations(array) {
2 | let animations = [];
3 | let auxillaryArray = array.slice();
4 | heapSort(auxillaryArray, animations);
5 | const javaScriptSortedArray = array.slice().sort((a, b) => a - b);
6 | console.log("sort works correctly? ", arraysAreEqual(javaScriptSortedArray, auxillaryArray));
7 | return [animations, auxillaryArray];
8 | }
9 |
10 | function heapSort(auxillaryArray, animations) {
11 | const N = auxillaryArray.length;
12 |
13 | // Build heap (rearrange array)
14 | for (let i = Math.floor(N / 2) - 1; i >= 0; i--) {
15 | heapify(auxillaryArray, N, i, animations);
16 | }
17 |
18 | // One by one extract an element from heap
19 | for (let i = N - 1; i > 0; i--) {
20 | animations.push(["comparision1", 0, i]); // Color change for comparison
21 | animations.push(["comparision2", 0, i]); // Color change for comparison
22 | animations.push(["swap", 0, auxillaryArray[i]]);
23 | animations.push(["swap", i, auxillaryArray[0]]);
24 | swap(auxillaryArray, 0, i);
25 | heapify(auxillaryArray, i, 0, animations);
26 | }
27 | }
28 |
29 | function heapify(auxillaryArray, N, i, animations) {
30 | let largest = i; // Initialize largest as root
31 | let left = 2 * i + 1; // left = 2*i + 1
32 | let right = 2 * i + 2; // right = 2*i + 2
33 |
34 | // If left child is larger than root
35 | if (left < N && auxillaryArray[left] > auxillaryArray[largest]) {
36 | animations.push(["comparision1", left, largest]); // Color change for comparison
37 | animations.push(["comparision2", left, largest]); // Color change for comparison
38 | largest = left;
39 | }
40 |
41 | // If right child is larger than largest so far
42 | if (right < N && auxillaryArray[right] > auxillaryArray[largest]) {
43 | animations.push(["comparision1", right, largest]); // Color change for comparison
44 | animations.push(["comparision2", right, largest]); // Color change for comparison
45 | largest = right;
46 | }
47 |
48 | // If largest is not root
49 | if (largest !== i) {
50 | animations.push(["swap", i, auxillaryArray[largest]]);
51 | animations.push(["swap", largest, auxillaryArray[i]]);
52 | swap(auxillaryArray, i, largest);
53 | heapify(auxillaryArray, N, largest, animations);
54 | }
55 | }
56 |
57 | function swap(auxillaryArray, firstIndex, secondIndex) {
58 | let temp = auxillaryArray[firstIndex];
59 | auxillaryArray[firstIndex] = auxillaryArray[secondIndex];
60 | auxillaryArray[secondIndex] = temp;
61 | }
62 |
63 | function arraysAreEqual(firstArray, secondArray) {
64 | if (firstArray.length !== secondArray.length) {
65 | return false;
66 | }
67 | for (let i = 0; i < firstArray.length; i++) {
68 | if (firstArray[i] !== secondArray[i]) {
69 | return false;
70 | }
71 | }
72 | return true;
73 | }
--------------------------------------------------------------------------------
/src/SortingAlgorithms/InsertionSort.js:
--------------------------------------------------------------------------------
1 | export function getInsertionSortAnimations(array) {
2 | let animations = [];
3 | let auxillaryArray = array.slice();
4 | insertionSort(auxillaryArray, animations);
5 | const javaScriptSortedArray = array.slice().sort((a, b) => a - b);
6 | console.log("sort works correctly? ",arraysAreEqual(javaScriptSortedArray, auxillaryArray));
7 | array = auxillaryArray;
8 | return [animations, array];
9 | }
10 |
11 | function insertionSort(auxillaryArray, animations) {
12 | const N = auxillaryArray.length;
13 | for (let i = 1; i < N; i++) {
14 | let key = auxillaryArray[i];
15 | let j = i - 1;
16 | animations.push(["comparision1", j, i]);
17 | animations.push(["comparision2", j, i]);
18 | while(j >= 0 && auxillaryArray[j] > key) {
19 | animations.push(["overwrite", j + 1, auxillaryArray[j]]);
20 | auxillaryArray[j + 1] = auxillaryArray[j];
21 | j = j - 1;
22 | if(j >= 0) {
23 | animations.push(["comparision1", j, i]);
24 | animations.push(["comparision2", j, i]);
25 | }
26 | }
27 | animations.push(["overwrite", j + 1, key]);
28 | auxillaryArray[j + 1] = key;
29 | }
30 | }
31 |
32 | function arraysAreEqual(firstArray, secondArray) {
33 | if (firstArray.length !== secondArray.length) {
34 | return false;
35 | }
36 | for (let i = 0; i < firstArray.length; i++) {
37 | if (firstArray[i] !== secondArray[i]) {
38 | return false;
39 | }
40 | }
41 | return true;
42 | }
--------------------------------------------------------------------------------
/src/SortingAlgorithms/MergeSort.js:
--------------------------------------------------------------------------------
1 | export function getMergeSortAnimations(array) {
2 | let animations = [];
3 | let auxillaryArray = array.slice();
4 | mergeSort(auxillaryArray, 0, auxillaryArray.length - 1, animations);
5 | const javaScriptSortedArray = array.slice().sort((a, b) => a - b);
6 | console.log(arraysAreEqual(javaScriptSortedArray, auxillaryArray));
7 | array = auxillaryArray;
8 | return [animations, array];
9 | }
10 |
11 | function mergeSort(auxillaryArray, startIndex, endIndex, animations) {
12 | if(startIndex === endIndex)
13 | return;
14 | const middleIndex = Math.floor((startIndex + endIndex)/2);
15 | mergeSort(auxillaryArray, startIndex, middleIndex, animations);
16 | mergeSort(auxillaryArray, middleIndex + 1, endIndex, animations);
17 | merge(auxillaryArray, startIndex, middleIndex, endIndex, animations);
18 | }
19 |
20 | function merge(auxillaryArray, startIndex, middleIndex, endIndex, animations) {
21 | let sortArray = [];
22 | let i = startIndex;
23 | let j = middleIndex + 1;
24 | while(i <= middleIndex && j <= endIndex) {
25 | //Comparing value at ith and jth index so push them to change their color
26 | animations.push(["comparision1", i, j]);
27 | //By changing color we imply that we are comparing those two values and then again we should revert back to their original color so push them again
28 | animations.push(["comparision2", i, j]);
29 | if(auxillaryArray[i] <= auxillaryArray[j]) {
30 | sortArray.push(auxillaryArray[i++]);
31 | }
32 | else {
33 | sortArray.push(auxillaryArray[j++]);
34 | }
35 | }
36 | while(i <= middleIndex) {
37 | animations.push(["comparision1", i, i]);
38 | animations.push(["comparision2", i, i]);
39 | sortArray.push(auxillaryArray[i++]);
40 | }
41 | while(j <= endIndex) {
42 | animations.push(["comparision1", j, j]);
43 | animations.push(["comparision2", j, j]);
44 | sortArray.push(auxillaryArray[j++]);
45 | }
46 | for (let i = startIndex; i <= endIndex; i++) {
47 | animations.push(["comparision1", i, i - startIndex]);
48 | animations.push(["overwrite", i, sortArray[i - startIndex]]);
49 | animations.push(["comparision2", i, i - startIndex]);
50 | auxillaryArray[i] = sortArray[i - startIndex];
51 | }
52 | }
53 |
54 | function arraysAreEqual(firstArray, secondArray) {
55 | if (firstArray.length !== secondArray.length) {
56 | return false;
57 | }
58 | for (let i = 0; i < firstArray.length; i++) {
59 | if (firstArray[i] !== secondArray[i]) {
60 | return false;
61 | }
62 | }
63 | return true;
64 | }
--------------------------------------------------------------------------------
/src/SortingAlgorithms/QuickSort.js:
--------------------------------------------------------------------------------
1 | export function getQuickSortAnimations(array) {
2 | let animations = [];
3 | let auxillaryArray = array.slice();
4 | quickSort(auxillaryArray, 0, auxillaryArray.length - 1, animations);
5 | const javaScriptSortedArray = array.slice().sort((a, b) => a - b);
6 | console.log("sort works correctly? ",arraysAreEqual(javaScriptSortedArray, auxillaryArray));
7 | array = auxillaryArray;
8 | return [animations, array];
9 | }
10 |
11 | function quickSort(auxillaryArray, startIndex, endIndex, animations) {
12 | let pivotIndex;
13 | if (startIndex < endIndex) {
14 | pivotIndex = partitionArray(auxillaryArray, startIndex, endIndex, animations);
15 | quickSort(auxillaryArray, startIndex, pivotIndex - 1, animations);
16 | quickSort(auxillaryArray, pivotIndex + 1, endIndex, animations);
17 | }
18 | }
19 |
20 | function partitionArray(auxillaryArray, startIndex, endIndex, animations) {
21 | let pivotIndex = randomIntFromInterval(startIndex, endIndex);
22 |
23 | animations.push(["comparision1", pivotIndex, endIndex]);
24 | animations.push(["swap", pivotIndex, auxillaryArray[endIndex]]);
25 | animations.push(["swap", endIndex, auxillaryArray[pivotIndex]]);
26 | animations.push(["comparision2", pivotIndex, endIndex]);
27 | swap(auxillaryArray, pivotIndex, endIndex);
28 |
29 | let lessTailIndex = startIndex;
30 |
31 | for(let i = startIndex; i < endIndex; ++i) {
32 | animations.push(["comparision1", i, endIndex]);
33 | animations.push(["comparision2", i, endIndex]);
34 | if(auxillaryArray[i] <= auxillaryArray[endIndex]) {
35 | animations.push(["comparision1", i, lessTailIndex]);
36 | animations.push(["swap", i, auxillaryArray[lessTailIndex]]);
37 | animations.push(["swap", lessTailIndex, auxillaryArray[i]]);
38 | animations.push(["comparision2", i, lessTailIndex]);
39 | swap(auxillaryArray, i, lessTailIndex);
40 | lessTailIndex++;
41 | }
42 | }
43 | animations.push(["comparision1", lessTailIndex, endIndex]);
44 | animations.push(["swap", endIndex, auxillaryArray[lessTailIndex]]);
45 | animations.push(["swap", lessTailIndex, auxillaryArray[endIndex]]);
46 | animations.push(["comparision2", lessTailIndex, endIndex]);
47 |
48 | swap(auxillaryArray, lessTailIndex, endIndex);
49 | return lessTailIndex;
50 |
51 | // let pivot = auxillaryArray[endIndex];
52 | // let pivotIndex = startIndex;
53 | // for (let i = startIndex; i <= endIndex - 1; i++) {
54 | // animations.push([i, endIndex]);
55 | // animations.push([i, endIndex]);
56 | // if (auxillaryArray[i] <= pivot) {
57 | // //Swap these two heights
58 | // animations.push([i, auxillaryArray[pivotIndex]]);
59 | // animations.push([pivotIndex, auxillaryArray[i]]);
60 | // swap(auxillaryArray, i , pivotIndex);
61 | // pivotIndex++;
62 | // }
63 | // else {
64 | // animations.push([-1, -1]);
65 | // animations.push([-1, -1]);
66 | // }
67 | // animations.push([-1, -1]);
68 | // animations.push([-1, -1]);
69 | // }
70 | // animations.push([-1, -1]);
71 | // animations.push([-1, -1]);
72 | // animations.push([-1, -1]);
73 | // animations.push([-1, -1]);
74 | // //Swap these two heights
75 | // animations.push([pivotIndex, auxillaryArray[endIndex]]);
76 | // animations.push([endIndex, auxillaryArray[pivotIndex]]);
77 | // swap(auxillaryArray, pivotIndex, endIndex);
78 | // return pivotIndex;
79 | }
80 |
81 | function swap(auxillaryArray, firstIndex, secondIndex) {
82 | let temp = auxillaryArray[firstIndex];
83 | auxillaryArray[firstIndex] = auxillaryArray[secondIndex];
84 | auxillaryArray[secondIndex] = temp;
85 | }
86 |
87 | function arraysAreEqual(firstArray, secondArray) {
88 | if (firstArray.length !== secondArray.length) {
89 | return false;
90 | }
91 | for (let i = 0; i < firstArray.length; i++) {
92 | if (firstArray[i] !== secondArray[i]) {
93 | return false;
94 | }
95 | }
96 | return true;
97 | }
98 |
99 | function randomIntFromInterval(min, max) {
100 | // min and max included
101 | return Math.floor(Math.random() * (max - min + 1) + min);
102 | }
--------------------------------------------------------------------------------
/src/SortingAlgorithms/SelectionSort.js:
--------------------------------------------------------------------------------
1 | export function getSelectionSortAnimations(array) {
2 | let animations = [];
3 | let auxillaryArray = array.slice();
4 | selectionSort(auxillaryArray, animations);
5 | const javaScriptSortedArray = array.slice().sort((a, b) => a - b);
6 | console.log("sort works correctly? ",arraysAreEqual(javaScriptSortedArray, auxillaryArray));
7 | array = auxillaryArray;
8 | return [animations, array];
9 | }
10 |
11 | function selectionSort(auxillaryArray, animations) {
12 | const N = auxillaryArray.length;
13 | for (let i = 0; i < N - 1; i++) {
14 | let minIndex = i; //Finding minimum element in unsorted array
15 | for (let j = i + 1; j < N; j++) {
16 | animations.push(["comparision1", j, minIndex]);
17 | animations.push(["comparision2", j, minIndex]);
18 | if (auxillaryArray[j] < auxillaryArray[minIndex]) {
19 | minIndex = j;
20 | }
21 | }
22 | animations.push(["swap", minIndex, auxillaryArray[i]]);
23 | animations.push(["swap", i, auxillaryArray[minIndex]]);
24 | // Swap the found minimum element with the first element
25 | swap(auxillaryArray, minIndex, i);
26 | }
27 | }
28 |
29 | function swap(auxillaryArray, firstIndex, secondIndex) {
30 | let temp = auxillaryArray[firstIndex];
31 | auxillaryArray[firstIndex] = auxillaryArray[secondIndex];
32 | auxillaryArray[secondIndex] = temp;
33 | }
34 |
35 | function arraysAreEqual(firstArray, secondArray) {
36 | if (firstArray.length !== secondArray.length) {
37 | return false;
38 | }
39 | for (let i = 0; i < firstArray.length; i++) {
40 | if (firstArray[i] !== secondArray[i]) {
41 | return false;
42 | }
43 | }
44 | return true;
45 | }
--------------------------------------------------------------------------------
/src/SortingVisualizer/SortingVisualizer.css:
--------------------------------------------------------------------------------
1 | .array-bar {
2 | box-shadow: 0 0 10px rgba(56, 189, 248, 0.5);
3 | }
--------------------------------------------------------------------------------
/src/SortingVisualizer/SortingVisualizer.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect, useRef } from 'react';
2 | import { getMergeSortAnimations } from '../SortingAlgorithms/MergeSort';
3 | import { getQuickSortAnimations } from '../SortingAlgorithms/QuickSort';
4 | import { getBubbleSortAnimations } from '../SortingAlgorithms/BubbleSort';
5 | import { getInsertionSortAnimations } from '../SortingAlgorithms/InsertionSort';
6 | import { getSelectionSortAnimations } from '../SortingAlgorithms/SelectionSort';
7 | import { getHeapSortAnimations } from '../SortingAlgorithms/HeapSort';
8 |
9 | // Constants
10 | let WINDOW_WIDTH = window.innerWidth;
11 | let WINDOW_HEIGHT = window.innerHeight;
12 | let NUMBER_OF_ARRAY_BARS = Math.floor(WINDOW_WIDTH / 8);
13 | const ANIMATION_SPEED_OPTIONS = {
14 | '0.25x': 150,
15 | '0.5x': 75,
16 | '1x': 5,
17 | '1.5x': 2.5,
18 | '2x': 1.5,
19 | };
20 | const PRIMARY_COLOR = '#2db5a3'; // Darker teal color
21 | const SECONDARY_COLOR = '#f43f5e'; // Darker red color
22 | const BACKGROUND_COLOR = '#1e293b'; // Darker background color
23 |
24 | const SortingVisualizer = () => {
25 | const [array, setArray] = useState([]);
26 | const [selectedAlgorithm, setSelectedAlgorithm] = useState('');
27 | const [isSorting, setIsSorting] = useState(false); // Track sorting state
28 | const [playbackSpeed, setPlaybackSpeed] = useState('1x'); // New state for playback speed
29 | const timeoutsRef = useRef([]); // Store timeouts
30 |
31 | useEffect(() => {
32 | resetArray();
33 | window.addEventListener('resize', handleResize);
34 | return () => window.removeEventListener('resize', handleResize);
35 | }, []);
36 |
37 | const handleResize = () => {
38 | WINDOW_WIDTH = window.innerWidth;
39 | WINDOW_HEIGHT = window.innerHeight;
40 | NUMBER_OF_ARRAY_BARS = Math.floor(WINDOW_WIDTH / 8);
41 | resetArray();
42 | };
43 |
44 | const resetArray = () => {
45 | if (isSorting) {
46 | clearTimeouts(); // Clear ongoing animations
47 | setIsSorting(false);
48 | resetBarColors(); // Reset bar colors
49 | }
50 | const newArray = [];
51 | for (let i = 0; i < NUMBER_OF_ARRAY_BARS; i++) {
52 | newArray.push(randomIntFromInterval(5, WINDOW_HEIGHT / 2));
53 | }
54 | setArray(newArray);
55 | };
56 |
57 | const resetBarColors = () => {
58 | const arrayBars = document.getElementsByClassName('array-bar');
59 | for (let i = 0; i < arrayBars.length; i++) {
60 | arrayBars[i].style.backgroundColor = PRIMARY_COLOR; // Reset to primary color
61 | }
62 | };
63 |
64 | const disableSortButtons = () => {
65 | // No buttons to disable since we removed them
66 | };
67 |
68 | const restoreStoreButtons = () => {
69 | // No buttons to restore since we removed them
70 | };
71 |
72 | const mergeSort = () => {
73 | disableSortButtons();
74 | const [animations, sortArray] = getMergeSortAnimations(array);
75 | animateSort(animations);
76 | const RESTORE_TIME = parseInt(ANIMATION_SPEED_OPTIONS[playbackSpeed] * animations.length / 2 + 3000);
77 | setTimeout(() => restoreStoreButtons(), RESTORE_TIME);
78 | };
79 |
80 | const quickSort = () => {
81 | disableSortButtons();
82 | const [animations, sortArray] = getQuickSortAnimations(array);
83 | animateSort(animations);
84 | const RESTORE_TIME = parseInt(ANIMATION_SPEED_OPTIONS[playbackSpeed] * animations.length / 2 + 3000);
85 | setTimeout(() => restoreStoreButtons(), RESTORE_TIME);
86 | };
87 |
88 | const bubbleSort = () => {
89 | disableSortButtons();
90 | const [animations, sortArray] = getBubbleSortAnimations(array);
91 | animateSort(animations);
92 | const RESTORE_TIME = parseInt(ANIMATION_SPEED_OPTIONS[playbackSpeed] * animations.length / 2 + 3000);
93 | setTimeout(() => restoreStoreButtons(), RESTORE_TIME);
94 | };
95 |
96 | const insertionSort = () => {
97 | disableSortButtons();
98 | const [animations, sortArray] = getInsertionSortAnimations(array);
99 | animateSort(animations);
100 | const RESTORE_TIME = parseInt(ANIMATION_SPEED_OPTIONS[playbackSpeed] * animations.length / 2 + 3000);
101 | setTimeout(() => restoreStoreButtons(), RESTORE_TIME);
102 | };
103 |
104 | const selectionSort = () => {
105 | disableSortButtons();
106 | const [animations, sortArray] = getSelectionSortAnimations(array);
107 | animateSort(animations);
108 | const RESTORE_TIME = parseInt(ANIMATION_SPEED_OPTIONS[playbackSpeed] * animations.length / 2 + 3000);
109 | setTimeout(() => restoreStoreButtons(), RESTORE_TIME);
110 | };
111 |
112 | const heapSort = () => {
113 | disableSortButtons();
114 | const [animations, sortArray] = getHeapSortAnimations(array);
115 | animateSort(animations);
116 | const RESTORE_TIME = parseInt(ANIMATION_SPEED_OPTIONS[playbackSpeed] * animations.length / 2 + 3000);
117 | setTimeout(() => restoreStoreButtons(), RESTORE_TIME);
118 | };
119 |
120 | const handleAlgorithmChange = (e) => {
121 | setSelectedAlgorithm(e.target.value);
122 | };
123 |
124 | const handlePlaybackSpeedChange = (e) => {
125 | setPlaybackSpeed(e.target.value);
126 | };
127 |
128 | const executeSelectedSort = () => {
129 | if (!selectedAlgorithm) return;
130 |
131 | disableSortButtons();
132 | switch (selectedAlgorithm) {
133 | case 'mergeSort':
134 | mergeSort();
135 | break;
136 | case 'quickSort':
137 | quickSort();
138 | break;
139 | case 'bubbleSort':
140 | bubbleSort();
141 | break;
142 | case 'insertionSort':
143 | insertionSort();
144 | break;
145 | case 'selectionSort':
146 | selectionSort();
147 | break;
148 | case 'heapSort':
149 | heapSort();
150 | break;
151 | default:
152 | restoreStoreButtons();
153 | }
154 | };
155 |
156 | const animateSort = (animations) => {
157 | setIsSorting(true); // Set sorting state to true
158 | const speedMultiplier = ANIMATION_SPEED_OPTIONS[playbackSpeed]; // Get speed multiplier
159 | for (let i = 0; i < animations.length; i++) {
160 | const arrayBars = document.getElementsByClassName('array-bar');
161 | const isColorChange = animations[i][0] === "comparision1" || animations[i][0] === "comparision2";
162 | if (isColorChange) {
163 | const color = animations[i][0] === "comparision1" ? SECONDARY_COLOR : PRIMARY_COLOR;
164 | const [, barOneIndex, barTwoIndex] = animations[i];
165 | const barOneStyle = arrayBars[barOneIndex].style;
166 | const barTwoStyle = arrayBars[barTwoIndex].style;
167 | const timeoutId = setTimeout(() => {
168 | barOneStyle.backgroundColor = color;
169 | barTwoStyle.backgroundColor = color;
170 | }, i * speedMultiplier);
171 | timeoutsRef.current.push(timeoutId); // Store timeout
172 | } else {
173 | const [, barIndex, newHeight] = animations[i];
174 | if (barIndex === -1) {
175 | continue;
176 | }
177 | const barStyle = arrayBars[barIndex].style;
178 | const timeoutId = setTimeout(() => {
179 | barStyle.height = `${newHeight}px`;
180 | }, i * speedMultiplier);
181 | timeoutsRef.current.push(timeoutId); // Store timeout
182 | }
183 | }
184 | };
185 |
186 | const clearTimeouts = () => {
187 | timeoutsRef.current.forEach(timeoutId => clearTimeout(timeoutId)); // Clear all timeouts
188 | timeoutsRef.current = []; // Reset the array
189 | };
190 |
191 | return (
192 |
193 |
194 | Sorting Visualizer
195 |
196 |
197 |
205 | {/* Dropdown for selecting sorting algorithm */}
206 |
219 | {/* Dropdown for selecting playback speed */}
220 |
229 | {/* Submit button to execute the selected sort */}
230 |
239 |
240 |
241 | {array.map((value, idx) => (
242 |
250 | ))}
251 |
252 |
253 | );
254 | };
255 |
256 | function randomIntFromInterval(min, max) {
257 | return Math.floor(Math.random() * (max - min + 1) + min);
258 | }
259 |
260 | export default SortingVisualizer;
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import App from './App';
4 |
5 | ReactDOM.render(
6 | ,
7 | document.getElementById("root")
8 | );
--------------------------------------------------------------------------------
/styles.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | }
4 |
5 | .container {
6 | max-w-md mx-auto p-4 mt-4 bg-gray-100 rounded-lg shadow-md;
7 | }
8 |
9 | .bar {
10 | float: left;
11 | width: 20px;
12 | height: 100px;
13 | margin: 0 2px;
14 | background-color: #4CAF50;
15 | }
16 |
17 | .bar:hover {
18 | background-color: #3e8e41;
19 | }
20 |
21 | #array-size {
22 | display: flex;
23 | align-items: center;
24 | margin-bottom: 20px;
25 | }
26 |
27 | #array-size span {
28 | margin-left: 10px;
29 | }
30 |
31 | #array-size input[type="range"] {
32 | -webkit-appearance: none;
33 | width: 100%;
34 | height: 10px;
35 | border-radius: 5px;
36 | background: #d3d3d3;
37 | outline: none;
38 | padding: 0;
39 | margin: 0 10px;
40 | }
41 |
42 | #array-size input[type="range"]::-webkit-slider-thumb {
43 | -webkit-appearance: none;
44 | width: 20px;
45 | height: 20px;
46 | border-radius: 50%;
47 | background: #4CAF50;
48 | cursor: pointer;
49 | margin-top: -5px;
50 | }
51 |
52 | #chart {
53 | height: 400px;
54 | width: 100%;
55 | background-color: #fff;
56 | border: 1px solid #ddd;
57 | padding: 20px;
58 | margin-top: 20px;
59 | }
60 |
61 | #chart canvas {
62 | height: 100%;
63 | width: 100%;
64 | }
--------------------------------------------------------------------------------
/tailwind.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | content: [
3 | "./src/**/*.{js,jsx,ts,tsx}",
4 | ],
5 | theme: {
6 | extend: {},
7 | },
8 | plugins: [],
9 | }
--------------------------------------------------------------------------------