JSFiddle - React, Tailwind, and code Playground

HTML

<h2>Lucene PriorityQueue animation</h2>

<table>
    <tr>
        <td>Add doc with score:</td>
        <td>
            <button data-bind="disable: animating, click: function () { insertAndShow(10) }">10</button>
            <button data-bind="disable: animating, click: function () { insertAndShow(20) }">20</button>
            <button data-bind="disable: animating,click: function () { insertAndShow(30) }">30</button>
            <button data-bind="disable: animating,click: function () { insertAndShow(40) }">40</button>
            <button data-bind="disable: animating, click: function () { insertAndShow(50) }">50</button>
            <button data-bind="disable: animating, click: function () { addRandom() }">Add Randoms</button>
        </td>
    </tr>
    <tr>
        <td>Remove top doc:</td>
        <td>
            <button data-bind="disable: animating,click: function () { doPop() }">Pop</button>
        </td>
    </tr>
</table>
<em>Click on a bar to remove an entry</em>

<svg id="svgCanvas" width="100%" height="120" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" pointer-events="all" preserveAspectRatio="xMidYMid slice">
    <g>
        <g id="viewport">
            <line stroke="#000000" id="svg_3" data-bind="attr:{x1:1, x2:500, y2:100, y1:100}" fill="none" />
            <g data-bind="foreach: slots">
                <rect fill="#007fff" stroke-width="0" data-bind="attr:{x:x,y:y, width:width, height:height, class:clazz} ,click: function () { $root.doRemove($data) }" />
                <text text-anchor="right" font-family="Sans-serif" font-size="8" data-bind="text:doc, attr:{x:x,y:120}"></text>
            </g>
        </g>
    </g>
</svg> <span data-bind="text:status"></span>

CSS

.changedSlot {
    fill:red;
}
.unchangedSlot {
    fill:gray;
}
body {
    font-family:"Helvetica", "Arial", "FreeSans", "Verdana", "Tahoma", "Lucida Sans", "Lucida Sans Unicode", "Luxi Sans", sans-serif;
    font-size:12px;
}

JavaScript

function ScoreDoc(score, doc) {
    var self = this;
    self.doc = doc;
    self.score = score;
}

// For display purposes
function Bar(scoreDoc, pos) {
    var self = this;
    self.width = 10;
    self.clazz = "unchangedSlot";
    self.doc = scoreDoc.doc;
    self.pos = pos;
    self.x = pos * (self.width + 2);
    self.score = scoreDoc.score;
    self.height = self.score;
    self.y = 100 - self.height;
}

function AlgoViewModel() {
    var self = this;
    //PriorityQueue variables
    self.size = 0;
    self.maxSize = 40;
    self.heap = [null, null];

    //Display data
    self.animating = false;
    self.status = ko.observable();
    self.docNum = 0;
    self.slots = ko.observableArray();
    self.snapshotNum = 0;
    self.snapshots = [];
    self.animPause=10;

    //PriorityQueue functions
    self.add = function (val) {
        self.docNum++;
        var element = new ScoreDoc(val, self.docNum);
        self.size++;
        self.heap[self.size] = element;
        self.addSnapshot(element);
        self.upHeap();
    }
    //Change - new function to remove element
    self.remove = function (element) {
        if (self.size == 0) {
            return false;
        }
        for (var i = 1; i <= self.size; i++) {
            //have to compare doc ids here rather than object==object
            if (self.heap[i].doc == element.doc) {
                self.heap[i] = self.heap[self.size];
                self.addSnapshot(self.heap[i]);
                self.size--;
                self.addSnapshot(null);
                //Change- downHeap now takes a parameter
                self.downHeap(i);
                self.startAnimation();
                return;
            }
        }
    }

    self.pop = function () {
        if (self.size > 0) {
            var result = self.heap[1]; // save first value
            self.heap[1] = self.heap[self.size]; // move last to first
            self.addSnapshot(self.heap[1]);
            self.heap[self.size] = null; //...