Skip to content

Commit d71485b

Browse files
author
Oskar Widmark
committed
feat: 2d color matrix visualization
1 parent f32c573 commit d71485b

File tree

4 files changed

+119
-24
lines changed

4 files changed

+119
-24
lines changed

TODO.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ Features:
33
- [ ] Sub 1ms draw times
44
- [ ] Parallelization for algorithms
55
- [ ] Merge sort
6-
- [ ] 2D color matrix visualization
6+
- [x] 2D color matrix visualization
77
- [ ] Spiral visualization
88
- [ ] Highlight color based on action type
99
- [ ] Mobile browser support

src/App.tsx

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ class App extends React.Component<Props> {
128128
for (const data of drawData) {
129129
this.arr[data.index].value = data.value;
130130
}
131-
this.canvasController.redrawColumns(
131+
this.canvasController.redraw(
132132
this.arr,
133133
drawData.map(({ index }) => index),
134134
);
@@ -190,7 +190,7 @@ class App extends React.Component<Props> {
190190
if (!this.state.isSorting) throw Error('isSorting is false!');
191191

192192
this.swap(arr, i1, i2);
193-
this.canvasController.redrawColumns(arr, [i1, i2]);
193+
this.canvasController.redraw(arr, [i1, i2]);
194194
this.nbrOfSwaps++;
195195
if (this.state.settings.swapTime) {
196196
if (this.state.settings.playSoundOnSwap) {
@@ -202,7 +202,7 @@ class App extends React.Component<Props> {
202202
this.setState((prevState: AppState) => ({
203203
nbrOfSwaps: prevState.nbrOfSwaps + 1,
204204
}));
205-
this.canvasController.highlightColumns(arr, [i1, i2]);
205+
this.canvasController.highlight(arr, [i1, i2]);
206206
await sleep(this.state.settings.swapTime);
207207
}
208208
};
@@ -254,7 +254,7 @@ class App extends React.Component<Props> {
254254
nbrOfComparisons: prevState.nbrOfComparisons + 1,
255255
}));
256256
const indexes = 'value' in params ? [i1] : [i1, params.i2];
257-
this.canvasController.highlightColumns(arr, indexes);
257+
this.canvasController.highlight(arr, indexes);
258258
await sleep(this.state.settings.compareTime);
259259
}
260260

@@ -295,7 +295,7 @@ class App extends React.Component<Props> {
295295
this.setState((prevState: AppState) => ({
296296
nbrOfAuxWrites: prevState.nbrOfAuxWrites + 1,
297297
}));
298-
this.canvasController.highlightColumns(arr, [i]);
298+
this.canvasController.highlight(arr, [i]);
299299
await sleep(this.state.settings.auxWriteTime);
300300
}
301301
};
@@ -335,7 +335,7 @@ class App extends React.Component<Props> {
335335
this.resetCounters();
336336
this.arr = createArr(this.state.settings.columnNbr);
337337
this.resetPresets[this.state.settings.resetPreset]();
338-
this.canvasController.redraw(this.arr);
338+
this.canvasController.redrawAll(this.arr);
339339
};
340340

341341
shuffleAndRedraw = () => {
@@ -344,7 +344,7 @@ class App extends React.Component<Props> {
344344

345345
shuffleArray(this.arr);
346346

347-
this.canvasController.redraw(this.arr);
347+
this.canvasController.redrawAll(this.arr);
348348
};
349349

350350
startDrawOnCanvas = (mouseX: number, mouseY: number) => {
@@ -381,7 +381,7 @@ class App extends React.Component<Props> {
381381
}
382382
});
383383

384-
this.canvasController.redraw(this.arr);
384+
this.canvasController.redrawAll(this.arr);
385385
};
386386

387387
getBackgroundColor = () => {

src/canvas-controller.ts

Lines changed: 109 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ export class CanvasController {
137137
);
138138
}
139139

140-
getColumnColor1(value: number) {
140+
getColumnColor(value: number) {
141141
switch (this.context.colorPreset) {
142142
case ColorPreset.Custom:
143143
return this.context.columnColor1;
@@ -148,6 +148,21 @@ export class CanvasController {
148148
}
149149
}
150150

151+
getCellColor(value1: number, value2: number) {
152+
switch (this.context.colorPreset) {
153+
case ColorPreset.Custom:
154+
return this.context.columnColor1;
155+
case ColorPreset.CustomGradient:
156+
return this.getGradientColor((value1 + value2) / 2);
157+
case ColorPreset.Rainbow:
158+
return hsvToRgbHex(
159+
((value1 + value2) / this.context.columnNbr) * 180,
160+
1,
161+
1,
162+
);
163+
}
164+
}
165+
151166
getHighlightColor() {
152167
switch (this.context.colorPreset) {
153168
case ColorPreset.Custom:
@@ -172,28 +187,41 @@ export class CanvasController {
172187
this.drawAll(arr);
173188
};
174189

175-
highlightColumns = (arr: SortValue[], indices: number[]) => {
176-
//if (!this.state.isSorting) throw Error('isSorting is false!');
177-
190+
highlight = (arr: SortValue[], indices: number[]) => {
178191
if (this.prevHighlightIndices) {
179192
for (const idx of this.prevHighlightIndices) {
193+
if (this.context.visualizationType === VisualizationType.Matrix) {
194+
this.redrawCellRow(arr, idx);
195+
this.redrawCellColumn(arr, idx);
196+
continue;
197+
}
180198
this.redrawColumn(arr, idx);
181199
}
182200
}
183201
this.prevHighlightIndices = indices;
184202

185203
for (const idx of indices) {
204+
if (this.context.visualizationType === VisualizationType.Matrix) {
205+
this.redrawCellRow(arr, idx, this.getHighlightColor());
206+
this.redrawCellColumn(arr, idx, this.getHighlightColor());
207+
continue;
208+
}
186209
this.redrawColumn(arr, idx, this.getHighlightColor());
187210
}
188211
};
189212

190-
redrawColumns = (arr: SortValue[], indices: number[]) => {
191-
for (const index of indices) {
192-
this.redrawColumn(arr, index);
213+
redraw = (arr: SortValue[], indices: number[]) => {
214+
for (const idx of indices) {
215+
if (this.context.visualizationType === VisualizationType.Matrix) {
216+
this.redrawCellRow(arr, idx);
217+
this.redrawCellColumn(arr, idx);
218+
continue;
219+
}
220+
this.redrawColumn(arr, idx);
193221
}
194222
};
195223

196-
redraw = (arr: SortValue[]) => {
224+
redrawAll = (arr: SortValue[]) => {
197225
this.clearAll();
198226
this.drawAll(arr);
199227
};
@@ -260,15 +288,46 @@ export class CanvasController {
260288
};
261289

262290
private removeHighlight = (arr: SortValue[]) => {
263-
this.highlightColumns(arr, []);
291+
this.highlight(arr, []);
264292
};
265293

266294
private redrawColumn = (arr: SortValue[], i: number, color?: string) => {
267295
this.clearColumn(i);
268296
this.drawColumn(arr, i, color);
269297
};
270298

299+
private redrawCellColumn = (arr: SortValue[], i: number, color?: string) => {
300+
for (let j = 0; j < this.context.columnNbr; j++) {
301+
this.redrawCell(arr, i, j, color);
302+
}
303+
};
304+
305+
private redrawCellRow = (arr: SortValue[], j: number, color?: string) => {
306+
for (let i = 0; i < this.context.columnNbr; i++) {
307+
this.redrawCell(arr, i, j, color);
308+
}
309+
};
310+
311+
private redrawCell = (
312+
arr: SortValue[],
313+
i: number,
314+
j: number,
315+
color?: string,
316+
) => {
317+
this.clearCell(i, j);
318+
this.drawCell(arr, i, j, color);
319+
};
320+
271321
private drawAll = (arr: SortValue[]) => {
322+
if (this.context.visualizationType === VisualizationType.Matrix) {
323+
for (let i = 0; i < arr.length; i++) {
324+
for (let j = 0; j < arr.length; j++) {
325+
this.drawCell(arr, i, j);
326+
}
327+
}
328+
return;
329+
}
330+
272331
for (let i = 0; i < arr.length; i++) {
273332
this.drawColumn(arr, i);
274333
}
@@ -283,13 +342,29 @@ export class CanvasController {
283342
);
284343
};
285344

345+
private drawCell = (
346+
arr: SortValue[],
347+
i: number,
348+
j: number,
349+
color?: string,
350+
) => {
351+
const width = this.width / this.context.columnNbr - 1;
352+
const height = this.height / this.context.columnNbr - 1;
353+
const startX = (width + 1) * i;
354+
const startY = (height + 1) * j;
355+
356+
this.canvas2dCtx.fillStyle =
357+
color || this.getCellColor(arr[i].value, arr[j].value);
358+
this.fillRect(startX, startY, width, height);
359+
};
360+
286361
private drawColumn = (arr: SortValue[], i: number, color?: string) => {
287362
const width = this.width / this.context.columnNbr;
288363
const height = this.getColumnHeight(arr[i].value);
289364
const startX = width * i;
290365
const startY = this.getColumnStartY(arr[i].value);
291366

292-
this.canvas2dCtx.fillStyle = color || this.getColumnColor1(arr[i].value);
367+
this.canvas2dCtx.fillStyle = color || this.getColumnColor(arr[i].value);
293368
this.fillRect(startX, startY, width, height);
294369
};
295370

@@ -308,7 +383,7 @@ export class CanvasController {
308383
return (this.height / this.context.columnNbr) * (value + 1);
309384
case VisualizationType.Dots:
310385
return this.width / this.context.columnNbr;
311-
case VisualizationType.Colors:
386+
default:
312387
return this.height;
313388
}
314389
};
@@ -331,15 +406,34 @@ export class CanvasController {
331406
const width = this.width / this.context.columnNbr;
332407
const startX = width * idx;
333408

334-
this.clearRect(startX, width);
409+
this.clearRect({ startX, width });
335410
};
336411

337-
private clearRect = (startX: number, width: number) => {
412+
private clearCell = (i: number, j: number) => {
413+
const width = this.width / this.context.columnNbr;
414+
const height = this.height / this.context.columnNbr;
415+
const startX = width * i;
416+
const startY = height * j;
417+
418+
this.clearRect({ startX, startY, width, height });
419+
};
420+
421+
private clearRect = (params: {
422+
startX: number;
423+
startY?: number;
424+
width: number;
425+
height?: number;
426+
}) => {
427+
const { startX, startY, width, height } = params;
338428
this.canvas2dCtx.clearRect(
339429
startX - 1,
340-
0,
430+
startY != null
431+
? Math.floor(this.height) -
432+
Math.floor(startY) -
433+
Math.floor(height ?? this.height)
434+
: 0,
341435
Math.floor(width) + 2,
342-
Math.floor(this.height),
436+
height != null ? Math.floor(height) + 2 : Math.floor(this.height),
343437
);
344438
};
345439

src/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ export enum VisualizationType {
5252
Bars = 'Bars',
5353
Dots = 'Dots',
5454
Colors = 'Colors',
55+
Matrix = 'Matrix',
5556
}
5657

5758
export enum DisplayType {

0 commit comments

Comments
 (0)