Implement snapshot-based sorting visualizer
Refactor sorting to produce and consume SortSnapshot sequences for visualization. SortingService now creates immutable snapshots and implements bubble, quick and heap sorts (with helper methods) instead of performing UI delays; a swap/heapify/partition flow records state changes. SortingComponent was updated to animate snapshots (with start/stop timeout handling), added array size input and controls, stores an unsorted copy for resets, and uses ChangeDetectorRef for updates. Minor UI tweaks: faster bar transitions, info color, updated default array size and animation speed, and added i18n keys for ARRAY_SIZE (en/de).
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { SortData } from '../sorting.models';
|
import {SortData, SortSnapshot} from '../sorting.models';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
@@ -8,90 +8,171 @@ export class SortingService {
|
|||||||
|
|
||||||
constructor() { }
|
constructor() { }
|
||||||
|
|
||||||
async bubbleSort(array: SortData[], animationSpeed: number): Promise<void> {
|
private createSnapshot(array: SortData[]): SortSnapshot {
|
||||||
console.log(animationSpeed);
|
return {
|
||||||
const n = array.length;
|
array: array.map(item => ({ ...item }))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
bubbleSort(array: SortData[]): SortSnapshot[] {
|
||||||
|
const snapshots: SortSnapshot[] = [];
|
||||||
|
const arr = array.map(item => ({ ...item }));
|
||||||
|
const n = arr.length;
|
||||||
|
|
||||||
|
snapshots.push(this.createSnapshot(arr));
|
||||||
|
|
||||||
for (let i = 0; i < n - 1; i++) {
|
for (let i = 0; i < n - 1; i++) {
|
||||||
console.log("1");
|
|
||||||
for (let j = 0; j < n - i - 1; j++) {
|
for (let j = 0; j < n - i - 1; j++) {
|
||||||
console.log("2");
|
arr[j].state = 'comparing';
|
||||||
array[j].state = 'comparing';
|
arr[j + 1].state = 'comparing';
|
||||||
array[j + 1].state = 'comparing';
|
snapshots.push(this.createSnapshot(arr)); // Snapshot Vergleich
|
||||||
await this.delay(animationSpeed);
|
|
||||||
|
|
||||||
if (array[j].value > array[j + 1].value) {
|
if (arr[j].value > arr[j + 1].value) {
|
||||||
// Swap elements
|
const temp = arr[j].value;
|
||||||
const temp = array[j].value;
|
arr[j].value = arr[j + 1].value;
|
||||||
array[j].value = array[j + 1].value;
|
arr[j + 1].value = temp;
|
||||||
array[j + 1].value = temp;
|
|
||||||
|
snapshots.push(this.createSnapshot(arr));
|
||||||
}
|
}
|
||||||
|
|
||||||
array[j].state = 'unsorted';
|
arr[j].state = 'unsorted';
|
||||||
array[j + 1].state = 'unsorted';
|
arr[j + 1].state = 'unsorted';
|
||||||
}
|
}
|
||||||
array[n - 1 - i].state = 'sorted'; // Mark the largest element as sorted
|
arr[n - 1 - i].state = 'sorted';
|
||||||
}
|
snapshots.push(this.createSnapshot(arr));
|
||||||
array[0].state = 'sorted'; // Mark the last element as sorted (if n > 0)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async selectionSort(array: SortData[], animationSpeed: number): Promise<void> {
|
arr[0].state = 'sorted';
|
||||||
const n = array.length;
|
snapshots.push(this.createSnapshot(arr));
|
||||||
for (let i = 0; i < n - 1; i++) {
|
|
||||||
let minIdx = i;
|
|
||||||
array[i].state = 'comparing';
|
|
||||||
for (let j = i + 1; j < n; j++) {
|
|
||||||
array[j].state = 'comparing';
|
|
||||||
await this.delay(animationSpeed);
|
|
||||||
|
|
||||||
if (array[j].value < array[minIdx].value) {
|
return snapshots;
|
||||||
minIdx = j;
|
|
||||||
}
|
|
||||||
if (j !== minIdx) { // Only reset if it wasn't the minimum
|
|
||||||
array[j].state = 'unsorted';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (minIdx !== i) {
|
|
||||||
// Swap elements
|
|
||||||
const temp = array[i].value;
|
|
||||||
array[i].value = array[minIdx].value;
|
|
||||||
array[minIdx].value = temp;
|
|
||||||
}
|
|
||||||
array[i].state = 'sorted'; // Mark the current element as sorted
|
|
||||||
if (minIdx !== i) {
|
|
||||||
array[minIdx].state = 'unsorted';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
array[n - 1].state = 'sorted'; // Mark the last element as sorted
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async insertionSort(array: SortData[], animationSpeed: number): Promise<void> {
|
// --- QUICK SORT ---
|
||||||
const n = array.length;
|
quickSort(array: SortData[]): SortSnapshot[] {
|
||||||
for (let i = 1; i < n; i++) {
|
const snapshots: SortSnapshot[] = [];
|
||||||
const key = array[i].value;
|
const arr = array.map(item => ({ ...item }));
|
||||||
array[i].state = 'comparing';
|
snapshots.push(this.createSnapshot(arr));
|
||||||
let j = i - 1;
|
|
||||||
|
|
||||||
while (j >= 0 && array[j].value > key) {
|
this.quickSortHelper(arr, 0, arr.length - 1, snapshots);
|
||||||
array[j].state = 'comparing';
|
|
||||||
await this.delay(animationSpeed);
|
|
||||||
|
|
||||||
array[j + 1].value = array[j].value;
|
arr.forEach(i => i.state = 'sorted');
|
||||||
array[j + 1].state = 'unsorted'; // Reset after shifting
|
snapshots.push(this.createSnapshot(arr));
|
||||||
j = j - 1;
|
|
||||||
}
|
return snapshots;
|
||||||
await this.delay(animationSpeed); // Delay after loop for final position
|
|
||||||
array[j + 1].value = key;
|
|
||||||
array[i].state = 'unsorted'; // Reset original 'key' position
|
|
||||||
array.forEach((item, idx) => { // Mark sorted up to i
|
|
||||||
if (idx <= i) {
|
|
||||||
item.state = 'sorted';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
array.forEach(item => item.state = 'sorted'); // Mark all as sorted at the end
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private delay(ms: number): Promise<void> {
|
private quickSortHelper(arr: SortData[], low: number, high: number, snapshots: SortSnapshot[]) {
|
||||||
return new Promise(resolve => setTimeout(resolve, ms));
|
if (low < high) {
|
||||||
|
const pi = this.partition(arr, low, high, snapshots);
|
||||||
|
|
||||||
|
this.quickSortHelper(arr, low, pi - 1, snapshots);
|
||||||
|
this.quickSortHelper(arr, pi + 1, high, snapshots);
|
||||||
|
} else if (low >= 0 && high >= 0 && low === high) {
|
||||||
|
arr[low].state = 'sorted';
|
||||||
|
snapshots.push(this.createSnapshot(arr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private partition(arr: SortData[], low: number, high: number, snapshots: SortSnapshot[]): number {
|
||||||
|
const pivot = arr[high];
|
||||||
|
arr[high].state = 'comparing'; // Pivot visualisieren
|
||||||
|
snapshots.push(this.createSnapshot(arr));
|
||||||
|
|
||||||
|
let i = (low - 1);
|
||||||
|
|
||||||
|
for (let j = low; j <= high - 1; j++) {
|
||||||
|
arr[j].state = 'comparing';
|
||||||
|
snapshots.push(this.createSnapshot(arr));
|
||||||
|
|
||||||
|
if (arr[j].value < pivot.value) {
|
||||||
|
i++;
|
||||||
|
this.swap(arr, i, j);
|
||||||
|
snapshots.push(this.createSnapshot(arr));
|
||||||
|
}
|
||||||
|
arr[j].state = 'unsorted';
|
||||||
|
}
|
||||||
|
this.swap(arr, i + 1, high);
|
||||||
|
|
||||||
|
arr[high].state = 'unsorted';
|
||||||
|
arr[i + 1].state = 'sorted';
|
||||||
|
snapshots.push(this.createSnapshot(arr));
|
||||||
|
|
||||||
|
return i + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- HEAP SORT ---
|
||||||
|
heapSort(array: SortData[]): SortSnapshot[] {
|
||||||
|
const snapshots: SortSnapshot[] = [];
|
||||||
|
const arr = array.map(item => ({ ...item }));
|
||||||
|
const n = arr.length;
|
||||||
|
|
||||||
|
snapshots.push(this.createSnapshot(arr));
|
||||||
|
|
||||||
|
for (let i = Math.floor(n / 2) - 1; i >= 0; i--) {
|
||||||
|
this.heapify(arr, n, i, snapshots);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = n - 1; i > 0; i--) {
|
||||||
|
arr[0].state = 'comparing';
|
||||||
|
arr[i].state = 'comparing';
|
||||||
|
snapshots.push(this.createSnapshot(arr));
|
||||||
|
|
||||||
|
this.swap(arr, 0, i);
|
||||||
|
|
||||||
|
arr[0].state = 'unsorted';
|
||||||
|
arr[i].state = 'sorted';
|
||||||
|
snapshots.push(this.createSnapshot(arr));
|
||||||
|
|
||||||
|
this.heapify(arr, i, 0, snapshots);
|
||||||
|
}
|
||||||
|
arr[0].state = 'sorted';
|
||||||
|
snapshots.push(this.createSnapshot(arr));
|
||||||
|
|
||||||
|
return snapshots;
|
||||||
|
}
|
||||||
|
|
||||||
|
private heapify(arr: SortData[], n: number, i: number, snapshots: SortSnapshot[]) {
|
||||||
|
let largest = i;
|
||||||
|
const l = 2 * i + 1;
|
||||||
|
const r = 2 * i + 2;
|
||||||
|
|
||||||
|
if (l < n) {
|
||||||
|
arr[l].state = 'comparing';
|
||||||
|
arr[largest].state = 'comparing';
|
||||||
|
snapshots.push(this.createSnapshot(arr));
|
||||||
|
|
||||||
|
if (arr[l].value > arr[largest].value) {
|
||||||
|
largest = l;
|
||||||
|
}
|
||||||
|
arr[l].state = 'unsorted';
|
||||||
|
arr[largest].state = 'unsorted';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Vergleich Rechts
|
||||||
|
if (r < n) {
|
||||||
|
arr[r].state = 'comparing';
|
||||||
|
arr[largest].state = 'comparing';
|
||||||
|
snapshots.push(this.createSnapshot(arr));
|
||||||
|
|
||||||
|
if (arr[r].value > arr[largest].value) {
|
||||||
|
largest = r;
|
||||||
|
}
|
||||||
|
arr[r].state = 'unsorted';
|
||||||
|
arr[largest].state = 'unsorted';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (largest !== i) {
|
||||||
|
this.swap(arr, i, largest);
|
||||||
|
snapshots.push(this.createSnapshot(arr));
|
||||||
|
|
||||||
|
this.heapify(arr, n, largest, snapshots);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private swap(arr: SortData[], i: number, j: number) {
|
||||||
|
const temp = arr[i].value;
|
||||||
|
arr[i].value = arr[j].value;
|
||||||
|
arr[j].value = temp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,20 +7,34 @@
|
|||||||
<div class="controls-panel">
|
<div class="controls-panel">
|
||||||
<mat-form-field appearance="fill">
|
<mat-form-field appearance="fill">
|
||||||
<mat-label>{{ 'ALGORITHM.SORTING.ALGORITHM' | translate }}</mat-label>
|
<mat-label>{{ 'ALGORITHM.SORTING.ALGORITHM' | translate }}</mat-label>
|
||||||
<mat-select [(ngModel)]="selectedAlgorithm" [disabled]="isSorting">
|
<mat-select [(ngModel)]="selectedAlgorithm">
|
||||||
@for (algo of availableAlgorithms; track algo.value) {
|
@for (algo of availableAlgorithms; track algo.value) {
|
||||||
<mat-option [value]="algo.value">{{ algo.name }}</mat-option>
|
<mat-option [value]="algo.value">{{ algo.name }}</mat-option>
|
||||||
}
|
}
|
||||||
</mat-select>
|
</mat-select>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
|
||||||
<button mat-raised-button color="primary" (click)="startSorting()" [disabled]="isSorting">
|
<mat-form-field appearance="outline">
|
||||||
|
<mat-label>{{ 'ALGORITHM.SORTING.ARRAY_SIZE' | translate }}</mat-label>
|
||||||
|
<input
|
||||||
|
matInput
|
||||||
|
type="number"
|
||||||
|
[min]="MIN_ARRAY_SIZE"
|
||||||
|
[max]="MAX_ARRAY_SIZE"
|
||||||
|
[(ngModel)]="arraySize"
|
||||||
|
(blur)="newArraySizeSet()"
|
||||||
|
(keyup.enter)="newArraySizeSet()"
|
||||||
|
/>
|
||||||
|
</mat-form-field>
|
||||||
|
</div>
|
||||||
|
<div class="controls-panel">
|
||||||
|
<button mat-raised-button color="primary" (click)="startSorting()">
|
||||||
<mat-icon>play_arrow</mat-icon> {{ 'ALGORITHM.SORTING.START' | translate }}
|
<mat-icon>play_arrow</mat-icon> {{ 'ALGORITHM.SORTING.START' | translate }}
|
||||||
</button>
|
</button>
|
||||||
<button mat-raised-button color="warn" (click)="resetSorting()" [disabled]="isSorting">
|
<button mat-raised-button color="warn" (click)="resetSorting()">
|
||||||
<mat-icon>refresh</mat-icon> {{ 'ALGORITHM.SORTING.RESET' | translate }}
|
<mat-icon>refresh</mat-icon> {{ 'ALGORITHM.SORTING.RESET' | translate }}
|
||||||
</button>
|
</button>
|
||||||
<button mat-raised-button (click)="generateNewArray()" [disabled]="isSorting">
|
<button mat-raised-button (click)="generateNewArray()">
|
||||||
<mat-icon>add_box</mat-icon> {{ 'ALGORITHM.SORTING.GENERATE_NEW_ARRAY' | translate }}
|
<mat-icon>add_box</mat-icon> {{ 'ALGORITHM.SORTING.GENERATE_NEW_ARRAY' | translate }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -35,7 +35,7 @@
|
|||||||
.bar {
|
.bar {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
background-color: #424242; /* Default unsorted color */
|
background-color: #424242; /* Default unsorted color */
|
||||||
transition: height 0.1s ease-in-out, background-color 0.1s ease-in-out;
|
transition: height 0.05s ease-in-out, background-color 0.05s ease-in-out;
|
||||||
width: 10px; /* Default width, flex-grow will adjust */
|
width: 10px; /* Default width, flex-grow will adjust */
|
||||||
min-width: 1px; /* Ensure bars are always visible */
|
min-width: 1px; /* Ensure bars are always visible */
|
||||||
|
|
||||||
@@ -56,7 +56,7 @@
|
|||||||
.info-panel {
|
.info-panel {
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
font-size: 0.9em;
|
font-size: 0.9em;
|
||||||
color: #555;
|
color: #FFFFFF;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Component, OnInit } from '@angular/core';
|
import {ChangeDetectorRef, Component, OnInit} from '@angular/core';
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
import {MatCardModule} from "@angular/material/card";
|
import {MatCardModule} from "@angular/material/card";
|
||||||
import {MatFormFieldModule} from "@angular/material/form-field";
|
import {MatFormFieldModule} from "@angular/material/form-field";
|
||||||
@@ -7,86 +7,134 @@ import {MatButtonModule} from "@angular/material/button";
|
|||||||
import {MatIconModule} from "@angular/material/icon";
|
import {MatIconModule} from "@angular/material/icon";
|
||||||
import {TranslateModule} from "@ngx-translate/core";
|
import {TranslateModule} from "@ngx-translate/core";
|
||||||
import { SortingService } from './service/sorting.service';
|
import { SortingService } from './service/sorting.service';
|
||||||
import { SortData } from './sorting.models';
|
import {SortData, SortSnapshot} from './sorting.models';
|
||||||
import { FormsModule } from '@angular/forms';
|
import { FormsModule } from '@angular/forms';
|
||||||
|
import {MatInput} from '@angular/material/input';
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-sorting',
|
selector: 'app-sorting',
|
||||||
standalone: true,
|
standalone: true,
|
||||||
imports: [CommonModule, MatCardModule, MatFormFieldModule, MatSelectModule, MatButtonModule, MatIconModule, TranslateModule, FormsModule],
|
imports: [CommonModule, MatCardModule, MatFormFieldModule, MatSelectModule, MatButtonModule, MatIconModule, TranslateModule, FormsModule, MatInput],
|
||||||
templateUrl: './sorting.component.html',
|
templateUrl: './sorting.component.html',
|
||||||
styleUrls: ['./sorting.component.scss']
|
styleUrls: ['./sorting.component.scss']
|
||||||
})
|
})
|
||||||
export class SortingComponent implements OnInit {
|
export class SortingComponent implements OnInit {
|
||||||
|
|
||||||
|
readonly MAX_ARRAY_SIZE: number = 200;
|
||||||
|
readonly MIN_ARRAY_SIZE: number = 20;
|
||||||
|
|
||||||
|
private timeoutIds: any[] = [];
|
||||||
sortArray: SortData[] = [];
|
sortArray: SortData[] = [];
|
||||||
arraySize: number = 50;
|
unsortedArrayCopy: SortData[] = [];
|
||||||
|
arraySize: number = 100;
|
||||||
maxArrayValue: number = 100;
|
maxArrayValue: number = 100;
|
||||||
animationSpeed: number = 10; // Milliseconds per step
|
animationSpeed: number = 50; // Milliseconds per step
|
||||||
|
|
||||||
// Placeholder for available sorting algorithms
|
// Placeholder for available sorting algorithms
|
||||||
availableAlgorithms: { name: string; value: string }[] = [
|
availableAlgorithms: { name: string; value: string }[] = [
|
||||||
{ name: 'Bubble Sort', value: 'bubbleSort' },
|
{ name: 'Bubble Sort', value: 'bubbleSort' },
|
||||||
{ name: 'Selection Sort', value: 'selectionSort' },
|
{ name: 'Quick Sort', value: 'quickSort' },
|
||||||
{ name: 'Insertion Sort', value: 'insertionSort' },
|
{ name: 'Heap Sort', value: 'heapSort' },
|
||||||
];
|
];
|
||||||
selectedAlgorithm: string = this.availableAlgorithms[0].value;
|
selectedAlgorithm: string = this.availableAlgorithms[0].value;
|
||||||
isSorting: boolean = false;
|
|
||||||
executionTime: number = 0;
|
executionTime: number = 0;
|
||||||
|
|
||||||
constructor(private sortingService: SortingService) { }
|
constructor(private readonly sortingService: SortingService, private readonly cdr: ChangeDetectorRef) { }
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.generateNewArray();
|
this.generateNewArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
newArraySizeSet()
|
||||||
|
{
|
||||||
|
if (this.arraySize == this.sortArray.length)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.generateNewArray();
|
||||||
|
}
|
||||||
|
|
||||||
generateNewArray(): void {
|
generateNewArray(): void {
|
||||||
this.isSorting = false;
|
this.resetSorting();
|
||||||
this.executionTime = 0;
|
this.executionTime = 0;
|
||||||
|
this.unsortedArrayCopy = [];
|
||||||
this.sortArray = [];
|
this.sortArray = [];
|
||||||
|
|
||||||
for (let i = 0; i < this.arraySize; i++) {
|
for (let i = 0; i < this.arraySize; i++) {
|
||||||
|
const randomValue = Math.floor(Math.random() * this.maxArrayValue) + 1;
|
||||||
this.sortArray.push({
|
this.sortArray.push({
|
||||||
value: Math.floor(Math.random() * this.maxArrayValue) + 1,
|
value: randomValue,
|
||||||
|
state: 'unsorted'
|
||||||
|
});
|
||||||
|
|
||||||
|
this.unsortedArrayCopy.push({
|
||||||
|
value: randomValue,
|
||||||
state: 'unsorted'
|
state: 'unsorted'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async startSorting(): Promise<void> {
|
private resetSortState() {
|
||||||
if (this.isSorting) {
|
for (let i = 0; i < this.sortArray.length; i++) {
|
||||||
return;
|
let element = this.sortArray[i];
|
||||||
|
let unsortedElement = this.unsortedArrayCopy[i];
|
||||||
|
element.value = unsortedElement.value;
|
||||||
|
element.state = 'unsorted';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
console.log('Starting sorting...');
|
|
||||||
this.isSorting = true;
|
|
||||||
this.executionTime = 0;
|
|
||||||
|
|
||||||
// Reset states for visualization
|
async startSorting(): Promise<void> {
|
||||||
this.sortArray.forEach(item => item.state = 'unsorted');
|
this.resetSorting();
|
||||||
const startTime = performance.now();
|
const startTime = performance.now();
|
||||||
console.log("Select algorithm ", this.selectedAlgorithm);
|
let snapshots: SortSnapshot[] = [];
|
||||||
|
|
||||||
switch (this.selectedAlgorithm) {
|
switch (this.selectedAlgorithm) {
|
||||||
case 'bubbleSort':
|
case 'bubbleSort':
|
||||||
await this.sortingService.bubbleSort(this.sortArray, this.animationSpeed);
|
snapshots = this.sortingService.bubbleSort(this.sortArray);
|
||||||
break;
|
break;
|
||||||
case 'selectionSort':
|
case 'quickSort':
|
||||||
await this.sortingService.selectionSort(this.sortArray, this.animationSpeed);
|
snapshots = this.sortingService.quickSort(this.sortArray);
|
||||||
break;
|
break;
|
||||||
case 'insertionSort':
|
case 'heapSort':
|
||||||
await this.sortingService.insertionSort(this.sortArray, this.animationSpeed);
|
snapshots = this.sortingService.heapSort(this.sortArray);
|
||||||
break;
|
|
||||||
default:
|
|
||||||
console.warn('Unknown sorting algorithm selected:', this.selectedAlgorithm);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
console.log("Done with sorting...");
|
|
||||||
const endTime = performance.now();
|
const endTime = performance.now();
|
||||||
this.executionTime = Math.round(endTime - startTime);
|
this.executionTime = parseFloat((endTime - startTime).toFixed(4));
|
||||||
this.isSorting = false;
|
|
||||||
this.sortArray.forEach(item => item.state = 'sorted'); // Mark all as sorted after completion
|
console.log(snapshots.length);
|
||||||
|
this.animateSorting(snapshots);
|
||||||
|
}
|
||||||
|
|
||||||
|
private animateSorting(snapshots: SortSnapshot[]): void {
|
||||||
|
snapshots.forEach((snapshot, index) => {
|
||||||
|
const id = setTimeout(() => {
|
||||||
|
for (let i = 0; i < this.sortArray.length; i++) {
|
||||||
|
if (snapshot.array[i]) {
|
||||||
|
this.sortArray[i].value = snapshot.array[i].value;
|
||||||
|
this.sortArray[i].state = snapshot.array[i].state;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.cdr.detectChanges();
|
||||||
|
|
||||||
|
if (index === snapshots.length - 1) {
|
||||||
|
this.sortArray.forEach(item => item.state = 'sorted');
|
||||||
|
this.cdr.detectChanges();
|
||||||
|
}
|
||||||
|
}, index * this.animationSpeed);
|
||||||
|
|
||||||
|
this.timeoutIds.push(id);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private stopAnimations(): void {
|
||||||
|
this.timeoutIds.forEach(id => clearTimeout(id));
|
||||||
|
this.timeoutIds = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
resetSorting(): void {
|
resetSorting(): void {
|
||||||
this.generateNewArray();
|
this.stopAnimations();
|
||||||
|
this.resetSortState();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,3 +2,7 @@ export interface SortData {
|
|||||||
value: number;
|
value: number;
|
||||||
state: 'sorted' | 'comparing' | 'unsorted';
|
state: 'sorted' | 'comparing' | 'unsorted';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface SortSnapshot {
|
||||||
|
array: SortData[];
|
||||||
|
}
|
||||||
|
|||||||
@@ -334,7 +334,8 @@
|
|||||||
"START": "Sortierung starten",
|
"START": "Sortierung starten",
|
||||||
"RESET": "Zurücksetzen",
|
"RESET": "Zurücksetzen",
|
||||||
"GENERATE_NEW_ARRAY": "Neues Array generieren",
|
"GENERATE_NEW_ARRAY": "Neues Array generieren",
|
||||||
"EXECUTION_TIME": "Ausführungszeit"
|
"EXECUTION_TIME": "Ausführungszeit",
|
||||||
|
"ARRAY_SIZE": "Anzahl der Balken"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -334,7 +334,8 @@
|
|||||||
"START": "Start Sorting",
|
"START": "Start Sorting",
|
||||||
"RESET": "Reset",
|
"RESET": "Reset",
|
||||||
"GENERATE_NEW_ARRAY": "Generate New Array",
|
"GENERATE_NEW_ARRAY": "Generate New Array",
|
||||||
"EXECUTION_TIME": "Execution Time"
|
"EXECUTION_TIME": "Execution Time",
|
||||||
|
"ARRAY_SIZE": "Number of Bars"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user