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;
}