Edit in JSFiddle

var scripts = document.getElementsByTagName("script");
for (var i = 0; i < scripts.length; i++) {
    if (scripts[i].type == "application/processing") {
        var src = scripts[i].src,
            canvas = scripts[i].nextSibling;
        if (src && src.indexOf("#")) {
            canvas = document.getElementById(src.substr(src.indexOf("#") + 1));
        } else {
            while (canvas && canvas.nodeName.toUpperCase() != "CANVAS")
            canvas = canvas.nextSibling;
        }
        if (canvas) {
            new Processing(canvas, scripts[i].text);
        }
    }
}
<script type="application/processing">
    float angle = 0.0;
    ArrayList peers = new ArrayList();
    ArrayList tmp = new ArrayList();
    ArrayList connections = new ArrayList();
    float rot = -1;
    Torrent testTorrent = new Torrent(30);
    int initialSeeders = 2;
    int initialPeers = 8;

    void setup() {
        size(450, 450);
        fill(256);
        fill(0);
        textAlign(CENTER);

        // establish initial seeds/peers
        // Modified to add seeds to random positions
        int seeds = 0;
        int peers = 0;
        for (int i = 0; i < initialSeeders + initialPeers; i++) {
            if (random(0, 1) > 0.8 && seeds < initialSeeders || peers == initialPeers) {
                seeds++;
                addSeeder();
            } else {
                peers++;
                addPeer();
            }
        }
        //for (int i = 0; i < initialPeers; i++) {
        //    addPeer();
        //}
    }

    ArrayList shuffle(ArrayList input) {
        ArrayList yin = new ArrayList();
        for (int i = 0; i < input.size(); i++) {
            yin.add(input.get(i));
        }

        ArrayList temp = new ArrayList();
        while (yin.size() > 0) {
            int x = int(random(0, yin.size()));
            temp.add(yin.get(x));
            yin.remove(x);
        }
        return (temp);
    }

    class Bit {
        int id;
        int bitHue;

        Bit(int i, int hu) {
            id = i;
            bitHue = hu;
        }
    }


    class Torrent {
        ArrayList bits = new ArrayList();

        Torrent(int totbits) {
            for (int i = 0; i < totbits; i++) {
                int ll = (255 / totbits) * i;
                Bit k = new Bit(i, ll);
                bits.add(k);
            }
        }
    }

    class Kibble {
        float starttime;
        float endtime;
        float big;

        Kibble() {
            starttime = 0;
            endtime = 0;
            big = (random(0, 4));
        }
    }

    class Peer {
        int index;
        float pwait;
        float sxpos; // x of peer
        float sypos; // y of peer
        float expos; // x of where peer should be
        float eypos; // y of where peer should be
        float cxpos;
        float cypos;
        float smovetime;
        float emovetime;
        float percent;
        float chue;
        float ehue;
        float shue;
        color ccolor;
        int removing;
        int lastcheck;
        ArrayList knex;
        ArrayList actBits;
        ArrayList myBits;
        ArrayList needBits;

        Peer(float pct) {
            int szv = peers.size();
            if (szv == 0) {
                szv++;
            }
            pwait = random(1, 9) * 1000;
            myBits = new ArrayList();
            needBits = new ArrayList();
            knex = new ArrayList();
            actBits = new ArrayList();

            pushMatrix();
            translate(width / 2, height / 2);
            ellipseMode(CENTER);
            float angle = 3;
            rotate(radians(angle));
            expos = (width / 2) + (230 * cos(radians(angle))); // screenX(0, 230)
            eypos = (height / 2) + (230 * sin(radians(angle))); // screenY(0, 230)
            sxpos = width / 2;
            sypos = height / 2;
            smovetime = millis();
            emovetime = smovetime + 1250;
            percent = pct;
            colorMode(HSB);

            lastcheck = millis();

            chue = 5;

            popMatrix();
            setupBits();
        }

        void setupBits() {
            for (int i = 0; i < testTorrent.bits.size(); i++) {
                if (!myBits.contains(testTorrent.bits.get(i))) {
                    needBits.add(testTorrent.bits.get(i));
                }
            }
        }

        void findPeer() {
            for (int i = 0; i < needBits.size(); i++) {
                needBits = shuffle(needBits);
                Bit b = (Bit) needBits.get(i);
                for (int o = 0; o < peers.size(); o++) {
                    Peer p = (Peer) peers.get(o);
                    if (p.myBits.contains(b) && !(p.removing > 0) && !(removing > 0) && !p.knex.contains((Peer) peers.get(index)) && p.index != index && !actBits.contains(b)) {
                        bitRequest(p, b);
                    }
                }
            }
        }

        void bitRequest(Peer k, Bit j) {
            if (k.knex.size() < 4) {
                Connection mz = new Connection(k, (Peer) peers.get(index), j);
                k.knex.add(peers.get(index));
                actBits.add(j);
                connections.add(mz);
            }
        }

        void reConfigure(int i) {
            int k;
            pushMatrix();
            translate(width / 2, height / 2);
            ellipseMode(CENTER);

            if (peers.size() == 0) {
                k = 1;
            } else {
                k = peers.size();
            }

            index = i;
            float angle = ((360 / k) * i) + rot;
            rotate(radians(angle));
            sxpos = cxpos;
            sypos = cypos;
            expos = (width / 2) + (180 * cos(radians(angle))); // screenX(0, 180, 0);
            eypos = (height / 2) + (180 * sin(radians(angle))); // screenY(0, 180, 0);
            smovetime = millis();
            emovetime = smovetime + 3000;

            popMatrix();
            shue = chue;
            ehue = (255 / peers.size() - 1) * i;

            ccolor = color(chue, 255, 255, 133);
        }

        void moveSelf() {
            if (millis() > emovetime) {
                cxpos = expos;
                cypos = eypos;
                chue = ehue;
            } else {
                float diff = (millis() - smovetime) / (emovetime - smovetime);
                cxpos = sxpos * (1 - diff) + expos * diff;
                cypos = sypos * (1 - diff) + eypos * diff;
                chue = shue * (1 - diff) + ehue * diff;
            }

        }

        void drawSelf() {
            fill(ccolor);

            stroke(myBits.size());
            // strokeWeight(1);
            noStroke();
            ellipseMode(CENTER);
            ellipse(cxpos, cypos, 50, 50);

            fill(0);
            float w = testTorrent.bits.size() - 1;
            rect(cxpos - w / 2, cypos - 5, w, 10);
            for (int i = 0; i < myBits.size(); i++) {
                Bit k = (Bit) myBits.get(i);
                colorMode(HSB);
                stroke(k.bitHue, 255, 255);
                line(cxpos - w / 2 + (1 * k.id), cypos - 5, cxpos - w / 2 + (1 * k.id), cypos + 5);
            }
        }
    }

    class Connection {
        int lastdraw;
        Peer from;
        Peer to;
        boolean stream;
        ArrayList kibbles;
        int deadkibbles;
        int speed;
        Bit theBit;

        Connection(Peer f, Peer t, Bit b) {
            theBit = (Bit) b;
            kibbles = new ArrayList()
            from = f;
            to = t;
            stream = true;
            lastdraw = millis();
            deadkibbles = 0;
            speed = int(random(30, 500));
        }

        int getIdxTo() {
            return to.index;
        }

        int getIdxFrom() {
            return from.index;
        }


        void manageKibbles() {
            if (from.removing >= 1 || to.removing >= 1 || deadkibbles > 125) {
                stream = false;
            } else {
                if (lastdraw < millis() - speed) {
                    newKibble();
                }
            }
        }

        void newKibble() {
            Kibble k = new Kibble();
            k.starttime = millis();
            k.endtime = k.starttime + 5000;
            kibbles.add(k);
            lastdraw = millis();
        }

        void drawKibbles() {
            for (int i = 0; i < kibbles.size(); i++) {
                Kibble k = (Kibble) kibbles.get(i);
                if (millis() > k.endtime) {
                    kibbles.remove(i);
                    deadkibbles++;
                } else {
                    float diff = (millis() - k.starttime) / (k.endtime - k.starttime);

                    float xpos = from.cxpos * (1 - diff) + (to.cxpos) * diff;
                    float ypos = from.cypos * (1 - diff) + (to.cypos) * diff;

                    colorMode(HSB);
                    fill(theBit.bitHue, 255, 255);
                    stroke(theBit.bitHue, 255, 255);
                    strokeWeight(1); // k.big);
                    ellipse(xpos, ypos, k.big, k.big);
                }
            }
        }
    }

    void addPeer() {
        int cc = peers.size();
        Peer k = new Peer(random(0, 1));
        peers.add(k);
    }

    void addSeeder() {
        int cc = peers.size();

        Peer p = new Peer(random(0, 1));
        peers.add(p);

        for (int i = 0; i < testTorrent.bits.size(); i++) {
            p.myBits.add(testTorrent.bits.get(i));
        }

        p.needBits = new ArrayList();
    }

    void removePeer() {
        int i = int(random(0, peers.size() - 1));
        Peer toRemove = (Peer) peers.get(i);
        toRemove.removing = 1;
    }

    void keyPressed() {
        if (key == 'p') {
            addPeer();
        }
        if (key == 's') {
            addSeeder();
        }
        if (key == 'r') {
            removePeer();
        }
    }

    void draw() {
        background(255);

        // rotate peers and seeds (disabled by default)
        if (rot >= 0) {
            if (rot < 360) {
                rot += .2;
            } else {
                rot = rot - 360;
            }
        }

        for (int i = 0; i < connections.size(); i++) {
            Connection c = (Connection) connections.get(i);
            c.manageKibbles();
            c.drawKibbles();

            if (c.kibbles.isEmpty() && c.stream == false) {
                if (c.to.removing >= 1) {
                    c.to.removing++;
                }
                if (c.from.removing >= 1) {
                    c.from.removing++;
                }

                c.from.knex.remove(c.from.knex.indexOf(c.to));
                c.to.myBits.add(c.theBit);
                if (c.to.needBits.indexOf(c.theBit) != -1) {
                    c.to.needBits.remove(c.to.needBits.indexOf(c.theBit));
                }
                if (c.to.knex.indexOf(c.theBit) != -1) {
                    c.to.knex.remove(c.to.knex.indexOf(c.theBit));
                }
                connections.remove(i);
            }
        }

        for (int i = 0; i < peers.size(); i++) {
            Peer p = (Peer) peers.get(i);
            p.moveSelf();
            p.drawSelf();
            p.reConfigure(i);
            if (p.removing > 1) {
                peers.remove(i);
            }
        }

        ArrayList tmp = shuffle(peers);
        for (int i = 0; i < tmp.size(); i++) {
            Peer cpeer = (Peer) tmp.get(i);
            if (cpeer.lastcheck < millis() - cpeer.pwait) {
                cpeer.findPeer();
                cpeer.lastcheck = millis();
            }
        }
    }
</script>

<h1>BitTorrent visualisointi</h1>

<canvas width="500px" height="500px"></canvas>
<p>Voit lisätä solmuja (peer) kirjaimella 'p', sekä jakajia (seed) kirjaimella 's'. Painamalla 'r' näppäintä poistat satunnaisen solmun tai jakajan. Muokattu <a href="http://mg8.org/processing/">täältä</a> löytyvästä versiosta, <a href="http://aphid.org/btsim/">alkuperäistä</a> ei enää ole saatavilla.</p>
h1 {
    text-align: center;
}