Skip to content

Commit 36563ac

Browse files
committed
Capture to canvas with time on y-axis
1 parent 55c9faf commit 36563ac

File tree

3 files changed

+164
-27
lines changed

3 files changed

+164
-27
lines changed

index.html

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,17 @@
77
<link href="main.css" rel="stylesheet" type="text/css">
88
</head>
99
<body>
10-
<center>
10+
<div style="display:flex; align-items: top; margin: 20px;">
11+
<div>
1112
<canvas id="canvas">Your browser doesn't supports canvas.</canvas>
12-
</center>
13+
</div>
14+
<div style="margin-left:20px;">
15+
<canvas id="canvas-2">Your browser doesn't supports canvas.</canvas>
16+
<div style="margin-top:10px">
17+
<a id="canvas-2-dl" href="#" download="canvas.png">Download</a>
18+
</div>
19+
</div>
20+
</div>
1321
<input type="file" id="image_upload" accept="image/*" style="visibility:hidden">
1422
<script src="https://d3js.org/d3.v4.min.js"></script>
1523
<script src="dat.gui.min.js"></script>

main.css

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
1-
html, body {
2-
width: 100%;
3-
height: 100%;
4-
margin: 0px;
5-
-webkit-touch-callout: none;
6-
-webkit-user-select: none;
7-
-khtml-user-select: none;
8-
-moz-user-select: none;
9-
-ms-user-select: none;
10-
user-select: none;
11-
overflow: hidden;
1+
html,
2+
body {
3+
width: 100%;
4+
height: 100%;
5+
margin: 0px;
6+
-webkit-touch-callout: none;
7+
-webkit-user-select: none;
8+
-khtml-user-select: none;
9+
-moz-user-select: none;
10+
-ms-user-select: none;
11+
user-select: none;
1212
}
1313
#top-left {
14-
position: absolute;
15-
left: 10px;
16-
top: 10px;
14+
position: absolute;
15+
left: 10px;
16+
top: 10px;
1717
}

sort.js

Lines changed: 140 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22

33
function color(x, width) {
44
return d3.interpolateViridis(x / width);
5-
// return "hsla(" + (x / width * 360) + ", 100%, 50%, 1.0)";
6-
//return "RGB(" + (x / width * 255) + ", 0, 0)";
75
}
86

97
function shuffle(array, start, end) {
@@ -20,10 +18,6 @@ var SG_MAGICCONST = 1.0 + Math.log(4.5);
2018
var LOG4 = Math.log(4.0);
2119

2220
function gamma_distribution(alpha, beta) {
23-
/*if (alpha <= 0.0 || beta <= 0.0) {
24-
throw new Error('gamma_distribution: alpha and beta must be > 0.0');
25-
}*/
26-
2721
if (alpha > 1) {
2822
var ainv = Math.sqrt(2.0 * alpha - 1.0);
2923
var bbb = alpha - LOG4;
@@ -99,6 +93,7 @@ function SortingVisualization(data, options, ctx) {
9993
}
10094

10195
this.data = data;
96+
this.captures = [];
10297

10398
this.options = options;
10499
this.ctx = ctx;
@@ -203,6 +198,26 @@ InsertionSort.prototype.sort = function(y, left, right) {
203198
}
204199
};
205200

201+
function StoogeSort() {
202+
SortingVisualization.apply(this, arguments);
203+
}
204+
205+
StoogeSort.prototype = Object.create(SortingVisualization.prototype);
206+
StoogeSort.prototype.constructor = SortingVisualization;
207+
208+
StoogeSort.prototype.sort = function(y, left, right) {
209+
if (this.cmp(this.data[y][right], this.data[y][left])) {
210+
this.swap(y, left, right);
211+
}
212+
213+
if (right - left >= 2) {
214+
var t = Math.round((right - left) / 3);
215+
this.sort(y, left, right - t);
216+
this.sort(y, left + t, right);
217+
this.sort(y, left, right - t);
218+
}
219+
};
220+
206221
function SelectionSort() {
207222
SortingVisualization.apply(this, arguments);
208223
}
@@ -305,6 +320,30 @@ ShellSort.prototype.sort = function(y, left, right) {
305320
}
306321
};
307322

323+
function CombSort() {
324+
SortingVisualization.apply(this, arguments);
325+
}
326+
327+
CombSort.prototype = Object.create(SortingVisualization.prototype);
328+
CombSort.prototype.constructor = SortingVisualization;
329+
330+
CombSort.prototype.sort = function(y, left, right) {
331+
var gap = right - left;
332+
var sorted = false;
333+
334+
while (!sorted) {
335+
gap = Math.max(Math.floor(gap / options.shrink_factor), 1);
336+
sorted = gap === 1;
337+
338+
for (var i = left; i + gap <= right; i++) {
339+
if (this.cmp(this.data[y][i + gap], this.data[y][i])) {
340+
sorted = false;
341+
this.swap(y, i, i + gap);
342+
}
343+
}
344+
}
345+
};
346+
308347
function QuickSort() {
309348
SortingVisualization.apply(this, arguments);
310349
}
@@ -410,27 +449,44 @@ document.addEventListener('DOMContentLoaded', function() {
410449
var canvas = document.getElementById('canvas');
411450
var ctx = canvas.getContext('2d');
412451

452+
var canvas2 = document.getElementById('canvas-2');
453+
var ctx2 = canvas2.getContext('2d');
454+
var canvas2dl = document.getElementById('canvas-2-dl');
455+
canvas2dl.addEventListener(
456+
'click',
457+
function() {
458+
var dt = canvas2.toDataURL('image/png');
459+
this.href = dt;
460+
},
461+
false,
462+
);
463+
413464
var processing = false;
414465

466+
var desiredCaptures = 100;
467+
415468
var data, sort_visualization;
416469

417470
var algorithms = {
418471
'Bubble sort': BubbleSort,
419472
'Insertion sort': InsertionSort,
473+
'Stooge sort': StoogeSort,
420474
'Selection sort': SelectionSort,
421475
'Cocktail sort': CocktailSort,
422476
'Odd-even sort': OddEvenSort,
423477
'Shell sort': ShellSort,
478+
'Comb sort': CombSort,
424479
'Quick sort': QuickSort,
425480
'Heap sort': HeapSort,
426481
};
427482

428483
options = {
429484
width: 100,
430-
height: 100,
485+
height: 1,
431486
speed: 1,
432487
algorithm: 'Bubble sort',
433488
pivot: 'Start',
489+
shrink_factor: 1.3,
434490
generate: 'Increasing',
435491
shuffle: function() {
436492
for (var y = 0; y < data.length; y++) {
@@ -440,6 +496,7 @@ document.addEventListener('DOMContentLoaded', function() {
440496
},
441497
zoom: 4,
442498
start: function() {
499+
options.shuffle();
443500
hide_gui_element('shuffle', true);
444501
hide_gui_element('start', true);
445502
hide_gui_element('stop', false);
@@ -449,17 +506,38 @@ document.addEventListener('DOMContentLoaded', function() {
449506
var algorithm = algorithms[options.algorithm];
450507
sort_visualization = new algorithm(data, options, ctx);
451508

509+
options.capture();
510+
452511
for (var y = 0; y < options.height; y++) {
453512
sort_visualization.sort(y, 0, options.width - 1);
454513
}
455514
sort_visualization.sort_end();
456515

516+
var currentFrame = 1;
517+
var totalFrames = d3.max(sort_visualization.swaps, swap => swap.length);
518+
var scale = d3
519+
.scaleLinear()
520+
.domain([0, desiredCaptures - 1])
521+
.range([0, totalFrames]);
522+
var captureFrames = d3
523+
.range(1, desiredCaptures)
524+
.map(scale)
525+
.map(Math.round);
526+
457527
function step() {
458528
if (!processing) {
459529
return;
460530
}
461-
for (var i = 0; i < options.speed; i++) {
462-
if (sort_visualization.step()) {
531+
for (var i = 0, done; i < options.speed; i++) {
532+
done = sort_visualization.step();
533+
534+
if (captureFrames[0] === currentFrame) {
535+
captureFrames.shift();
536+
options.capture();
537+
}
538+
currentFrame++;
539+
540+
if (done) {
463541
options.stop();
464542
return;
465543
}
@@ -476,16 +554,57 @@ document.addEventListener('DOMContentLoaded', function() {
476554

477555
data = sort_visualization.data;
478556

557+
options.renderCaptures();
558+
479559
processing = false;
480560
},
561+
capture: function() {
562+
sort_visualization.captures.push(
563+
ctx.getImageData(0, 0, canvas.width, canvas.height),
564+
);
565+
},
566+
renderCaptures: function() {
567+
var newCaptures = sort_visualization.captures;
568+
var renderHeight = Math.floor(canvas2.height / desiredCaptures);
569+
570+
// Changes rendering algorithm
571+
var alwaysRenderFirstRow = true;
572+
573+
for (var i = 0; i < newCaptures.length; i++) {
574+
if (alwaysRenderFirstRow) {
575+
ctx2.putImageData(
576+
newCaptures[i],
577+
0, // dx,
578+
i * renderHeight, // dy,
579+
0, // dirtyX, - dest x pos
580+
0, // dirtyY, - dest y pos
581+
canvas2.width, // dirtyWidth,
582+
renderHeight * options.zoom, // dirtyHeight
583+
);
584+
} else {
585+
ctx2.putImageData(
586+
newCaptures[i],
587+
0, // dx,
588+
0, // dy,
589+
0, // dirtyX, - dest x pos
590+
i * renderHeight, // dirtyY, - dest y pos
591+
canvas2.width, // dirtyWidth,
592+
renderHeight, // dirtyHeight
593+
);
594+
}
595+
}
596+
},
481597
distribution: {
482598
alpha: 1,
483599
beta: 1,
484600
},
485601
};
486602

487603
function draw(use_visualization_data) {
488-
var draw_data = use_visualization_data ? sort_visualization.data : data;
604+
var draw_data =
605+
use_visualization_data && sort_visualization
606+
? sort_visualization.data
607+
: data;
489608
canvas.width = options.width * options.zoom;
490609
canvas.height = options.height * options.zoom;
491610

@@ -503,6 +622,13 @@ document.addEventListener('DOMContentLoaded', function() {
503622
);
504623
}
505624
}
625+
626+
canvas2.width = canvas.width;
627+
canvas2.height = desiredCaptures * options.zoom;
628+
canvas2.style.width = canvas2.width + 'px';
629+
canvas2.style.height = canvas2.height + 'px';
630+
ctx2.fillStyle = '#cccccc';
631+
ctx2.fillRect(0, 0, canvas2.width, canvas2.height);
506632
}
507633

508634
function resize() {
@@ -544,14 +670,16 @@ document.addEventListener('DOMContentLoaded', function() {
544670
.name('Algorithm')
545671
.onChange(function() {
546672
hide_gui_element('pivot', options.algorithm !== 'Quick sort');
673+
hide_gui_element('shrink_factor', options.algorithm !== 'Comb sort');
547674
});
548675
gui.add(options, 'pivot', ['Start', 'Middle', 'End', 'Random']).name('Pivot');
676+
gui.add(options, 'shrink_factor', 1.001, 3).name('Shrink factor');
549677
gui
550678
.add(options, 'generate', ['Increasing', 'Decreasing'])
551679
.name('Generate')
552680
.onChange(resize);
553681
gui.add(options, 'shuffle').name('Shuffle');
554-
gui.add(options, 'zoom', 1, 10, 1).name('Zoom').onChange(function() {
682+
gui.add(options, 'zoom', 1, 50, 1).name('Zoom').onChange(function() {
555683
draw(true);
556684
});
557685
gui.add(options, 'start').name('Start');
@@ -573,4 +701,5 @@ document.addEventListener('DOMContentLoaded', function() {
573701

574702
hide_gui_element('stop', true);
575703
hide_gui_element('pivot', true);
704+
hide_gui_element('shrink_factor', true);
576705
});

0 commit comments

Comments
 (0)