// Site class. A site is an disc object with a size (representing inbound links), position and // an array of lines (representing oubound links from this site to other sites). class Site { float xpos, ypos, rsize; String label; int index; int[] links = new int[0]; Site (float x, float y, float radius, String labeltext) { ypos = y; xpos = x; rsize = radius; label = labeltext; } //Site oubound links void addlink(int siteindex) { links = append(links, siteindex); Sites[siteindex].resize(Sites[siteindex].rsize + 1); } void move(float x, float y) { if(x > width - (rsize/2)) { x = width - (rsize/2); } if(y > height - (rsize/2)) { y = height - (rsize/2); } if(x < rsize/2) { x = rsize/2; } if(y < rsize/2) { y = rsize/2; } ypos = y; xpos = x; } void increase() { rsize = rsize + 1; } void resize(float newsize) { rsize = newsize; } void collide() { //Check if we are over one of the other sites for(int i=0;i < Sites.length; i++) { float X = Sites[i].xpos; float Y = Sites[i].ypos; float R = Sites[i].rsize; float deltax = X-xpos; float deltay = Y-ypos; float d = sqrt(pow(deltax,2)+pow(deltay,2)); if ( d < (rsize + R)/2 && d > 0 ) { //direction? float dir = deltax/-deltax; //who is largest? if(rsize > Sites[i].rsize) { //move other site Sites[i].move(Sites[i].xpos + dir * (deltax + d), Sites[i].ypos); } else { //move this site move(xpos + dir * (deltax + d), ypos); } } } } void makeMove() { if(rsize > sizemovethreshold) { move(xpos, ypos - (rsize/50)); } } void displayLinks() { if(overSite(int(xpos), int(ypos), int(rsize))) { stroke(10); if(mousePressed) { move(mouseX, mouseY); } } else { stroke(150); } //draw link lines for(int i=0;i < links.length; i++) { if(links[i] > -1) { //Get target site Site target = Sites[links[i]]; line(xpos, ypos, target.xpos, target.ypos); } } } void displayDisc() { strokeWeight(1); stroke(100); if(overSite(int(xpos), int(ypos), int(rsize))) { fill(200, 100, 100); } else { fill(255, 255, 255); } ellipse(xpos, ypos, rsize+1, rsize+1); fill(10); text(label, xpos-floor(rsize/2), ypos+ (rsize/2) + labelsize); text(str(int(rsize - sitestartsize)), xpos-floor(rsize/2), ypos + (rsize/2) + labelsize*2); stroke(0); } } //This method will create sites and add them to the global site array if they doesn't exist already). void AddLinkData(String startsite, String endsite) { //Set up sites and link Site startSite = GetSite(startsite); Site endSite = GetSite(endsite); startSite.addlink(endSite.index); } //Get a site reference from the global site array. Create a new site if it doesen't exist already. Site GetSite(String url) { for(int i=0;i < Sites.length; i++) { if(Sites[i] != null) { if(Sites[i].label.equals(url)) { return Sites[i]; } } } //Site does not exist. Create new site and return it Site newSite = new Site(int(random(0, width - 100)), int(random(height - height/3, height - sitestartsize - 20)), sitestartsize, url); //append it to global array newSite.index = AddSiteToArray(newSite); return newSite; } boolean overSite(int x, int y, int radius) { if (mouseX >= (x-radius/2) && mouseX <= (x+radius/2) && mouseY >= (y-radius/2) && mouseY <= (y+radius/2)) { return true; } else { return false; } } //Add a site to the global sites array. int AddSiteToArray(Site site) { Site[] Sites_temp = new Site[Sites.length + 1]; System.arraycopy(Sites, 0, Sites_temp, 0, Sites.length); Sites_temp[Sites.length] = site; Sites = Sites_temp; return Sites.length - 1; } //Set up base objects PFont font; Site[] Sites = new Site[0]; int sitestartsize = 10; int sizemovethreshold = sitestartsize + 2; float resizescale = 1.0; float noisescale = 0.5; int labelsize = 10; String[] linkdata; int currentitemindex = 0; //Set up canvas void setup() { size(900, 600); smooth(); background(230, 230, 255); noStroke(); font = loadFont("Verdana-10.vlw"); textFont(font, 10); //parse indata file linkdata = loadStrings("linkdata.txt"); } //draw void draw() { background(210, 210, 210); if(currentitemindex < linkdata.length) { //add sites String data[] = split(linkdata[currentitemindex],";"); if(data[0]!=null && data[1]!=null) { AddLinkData(trim(data[0]), trim(data[1])); } currentitemindex++; } for(int i=0;i < Sites.length; i++) { Sites[i].displayLinks(); } for(int i=0;i < Sites.length; i++) { Sites[i].collide(); Sites[i].makeMove(); Sites[i].displayDisc(); } }