/* In Popular Terms http://www.inpopularterms.net Programming: Gilbert Guerrero & Christian Nold Creative Commons, 2008 Attribution-Noncommercial-Share Alike 3.0 License */ import proxml.*; import traer.physics.*; Particle one,mouse; Particle[] words; ParticleSystem physics; String version = "in popular terms v0.5"; // A Request object, from the library XMLInOut xmlIO; Months fixedMonthIndicator; Months movingMonthIndicator; FloatingTerm[]flterms; Graph[]nGraph; PImage buttonCOver; PImage buttonHOut; PImage buttonHOver; PFont font; // font object boolean xmlLoaded = false; // variable to check if xml request was successful boolean loadingComplete = false; // variable to check if all xml loading is complete boolean InitalAnimation = false; // variable to check if all xml loading is complete int nrLoaded = 0; //nr of loaded xml files int[]termArrCount; //stored counts for terms float[]termH; int data[] = { }; int datei; int termClicked = 4; int iNearMouseX; float lineMouseX = 0; int angledX; int angledMonthX; int lineAngledX; int lineAngledMonthX; int woffset = 15; int xoffset = woffset + 0; int yoffset; float graphN; //month increment size for the graph int graphWidth = 920; int graphHeight = 130; int startyear = 2004; //default values String lastindex = "2008-01-04"; //value retreived from web param String lastyear = "2008"; //value retreived from web param String lastmonth = "01"; //value retreived from web param String datekey = "-1"; //value retreived from historical page String termkey = "4"; //value retreived from historical page String http_host; //value for the site. local, staging, or live. String site = ""; //local settings for no web server int dv = day(); // Values from 1 - 31 int mv = month(); // Values from 1 - 12 int yv = year(); // 2003, 2004, 2005, etc. float al = 0; String statusmsg; float r = 105; float g = 102; float b = 105; float a = 165; //alpha value String[]termQueries = { "agribusiness", "biosphere", "climate+change", "community+gardens", "conservation", "earth+day", "ecology", "environment", "factory+farming", "gaia", "global+warming", "green", "greenhouse+effect", "nature", "organic", "preservation", "spaceship+earth", "sustainable", "urban+farming", "wilderness" }; // hard coded Start positions for the words - this seems like a bad solution if we change the number of words or size etc.... float[]xi = { 466+xoffset, 472+xoffset, 86+xoffset, 10+xoffset, 83+xoffset, 592+xoffset, 324+xoffset, 375+xoffset, 341+xoffset, 789+xoffset, 220+xoffset, 300+xoffset, 141+xoffset, 706+xoffset, 626+xoffset, 33+xoffset, 353+xoffset, 170+xoffset, 404+xoffset, 58+xoffset }; float[]yi = { 244+yoffset, 48+yoffset, 274+yoffset, 50+yoffset, 117+yoffset, 169+yoffset, 22+yoffset, 168+yoffset, 211+yoffset, 118+yoffset, 202+yoffset, 100+yoffset, 322+yoffset, 268+yoffset, 84+yoffset, 214+yoffset, 310+yoffset, 69+yoffset, 324+yoffset, 167+yoffset }; void setup() { println(version); size(936,516); background(255); frameRate(18); physics = new ParticleSystem( 0, 0.4 ); mouse = physics.makeParticle(); mouse.makeFixed(); buttonCOver = loadImage("contemporary-over.gif"); buttonHOut = loadImage("historical-out.gif"); buttonHOver = loadImage("historical-over.gif"); // Load the font hint(ENABLE_NATIVE_FONTS); font = createFont("Helvetica",11); textFont(font); if(online) { // or "if (online == true)" /* remote settings */ lastindex = param("lastindex"); lastyear = param("lastyear"); lastmonth = param("lastmonth"); datekey = param("datekey"); termkey = param("termkey"); http_host = param("http_host"); site = "http://"+ http_host +"/app/"; println(site); } if(int(termkey) >= 0){ //check if termkey has been set, by default it is set to -1 termClicked = int(termkey); } //initialize the arrays flterms = new FloatingTerm[termQueries.length]; nGraph = new Graph[termQueries.length]; termH = new float[termQueries.length]; ///// particles words = new Particle[termQueries.length]; //// particles // setup up the term objects for(int i = 0; i < termQueries.length; i++){ // particle stuff // words[i] = physics.makeParticle( 1.0, random( 0, width ), random( 0, height ), 0 ); words[i] = physics.makeParticle( 1.0, xi[i], yi[i], 0 ); for(int v = 0; v < termQueries.length; v++){ if (v <= i){ //repulsion physics.makeAttraction( words[v], words[i], -100, 20 ); } ////// flterms[i] = new FloatingTerm(termQueries[i], i); nGraph[i] = new Graph(termQueries[i]); } // attracted to the mouse physics.makeAttraction( mouse, words[i], 400, 70 ); } int lastyearN = int(lastyear); int lastmonthN = int(lastmonth); graphN = graphWidth / ((lastyearN - startyear) * 12 + lastmonthN - 1); //increment size for each month in the graph fixedMonthIndicator = new Months(); // movingMonthIndicator = new Months(); //draw a box around the graph and words stroke(60); noFill(); rect(woffset,0,920,515); //make an initial XML request getXML(0); } void draw() { background( 255 ); showTabs(); mouse.moveTo( mouseX, mouseY, 0 ); physics.tick(); // draw text if everything is loaded if(loadingComplete){ if (InitalAnimation){ Run(); } else{ RunAnimation(); } } else { // draw some loading animation loadStatus(); // check if we are ready to load the next xml if (xmlLoaded) { // if so, make the new request. xmlLoaded = false; getXML(nrLoaded); al = 0; } // end if } //end if else } // end draw void mouseReleased(){ cursor(ARROW); //change the cursor back to arrow if(mouseX > 0 && mouseX < 15 && mouseY > 113 && mouseY < 166){ //load the historical web page link("http://www.inpopularterms.net/historical/?datekey="+ datei +"&termkey="+ termClicked +"&term="+termQueries[termClicked]); } if(mouseY > 365 && mouseX > woffset){ datei = iNearMouseX; lineMouseX = mouseX; lineAngledX = angledX; lineAngledMonthX = angledMonthX; } if(mouseY < 365) { for(int i = 0; i < termQueries.length; i++){ if(mouseX > flterms[i].tx && mouseX < flterms[i].tx + flterms[i].termWidth && mouseY > flterms[i].ty - termH[i] && mouseY < flterms[i].ty){ termClicked = i; } } } } void mouseDragged(){ cursor(HAND); //change the cursor Hand to indicate dragging is going on if(mouseY > 365 && mouseX > woffset){ datei = iNearMouseX; lineMouseX = mouseX; lineAngledX = angledX; lineAngledMonthX = angledMonthX; } if(mouseY < 365) { for(int i = 0; i < termQueries.length; i++){ if(mouseX > flterms[i].tx && mouseX < flterms[i].tx + flterms[i].termWidth && mouseY > flterms[i].ty - termH[i] && mouseY < flterms[i].ty){ termClicked = i; } } } } void showTabs(){ image(buttonCOver, 1, 35); image(buttonHOut, 1, 113); if(mouseX > 0 && mouseX < 15 && mouseY > 113 && mouseY < 166){ image(buttonHOver, 1, 113); } } void loadStatus(){ // draw some loading animation background(255); showTabs(); //draw a box around the graph and words stroke(60); noFill(); rect(woffset,0,920,515); textAlign(CENTER); textFont(font, 11); fill(60); text(statusmsg, width/2, height/2); fill(200); textFont(font, 20); text(version, width/2, height/2+40); } void detectMouseOnGraph(){ if(mouseY > 365) { for(int j = 0; j < termArrCount.length; j++){ float x1 = graphN*j; if(mouseX >= (graphN*j) && mouseX < (graphN*j + graphN)){ iNearMouseX = j; //set the date array to use this number to extract counts } } } } void getXML(int l) { xmlIO = new XMLInOut(this); // location of static xml file String location = "xml/"+ termQueries[l]+"_"+lastindex+".xml"; // location of php script to generate a new xml file String url = site +"data_xml.php?query="+ termQueries[l]; //load xml from file if it exists try{ xmlIO.loadElement(site + location); statusmsg = "searching for term: " + termQueries[l] + " (" + (l+1) + "/" + termQueries.length + ") "; println(statusmsg); } catch(Exception e){ //if the xml file could not be loaded it has to be created xmlIO.loadElement(url); statusmsg = "generating xml for term: " + termQueries[l] + " (" + (l+1) + "/" + termQueries.length + ") "; println(statusmsg); } } // When the request for the XML is made void xmlEvent(XMLElement element) { XMLElement results = element.getChild(1); // Retrieve an array of all XML elements that are children of XMLElement[] entries = results.getChildren(); termArrCount = new int[entries.length]; //fill up an array with the attributes of each entry for (int i = 0; i < entries.length; i++) { //get the text and display it String tcount = results.getChild(i).getAttribute("count"); termArrCount[i] = int(tcount); } //dump the data into the term object flterms[nrLoaded].addData(termArrCount); nGraph[nrLoaded].addData(termArrCount); nrLoaded++; //check if all the new arrays have been filled if (nrLoaded == termQueries.length) { loadingComplete = true; background(255); // delete the progress bar println("xml loading complete"); } // set this to true, so the draw-loop can start a new request xmlLoaded = true; } void RunAnimation(){ background(255); // delete the progress bar color Colour = color(88, 156, 28); if(datei == 0) { // if date i has not been set datei = termArrCount.length - 1; //this returns the count for the last entry in the xml, aka Today } else if(int(datekey) >= 0) { //check if the web param has been set, by default it is set to -1 datei = int(datekey); } for(int i = 0; i < termQueries.length; i++){ // display all of the text terms for the selected date flterms[i].updateTerm(datei, flterms[i].tx, flterms[i].ty, Colour); // date array key, x, y, color } InitalAnimation = true; println("InitalAnimation = "+InitalAnimation); } void Run(){ // This draws a green box at the bottom of the screen to cover our crap graphing :) noStroke(); fill(88, 156, 28); rect(woffset, height -11, width, 10); for(int i = 0; i < termQueries.length; i++){ flterms[i].updatePosition(); one = flterms[i].particle; handleBoundaryCollisions( one ); } if(datei == 0) { // if date i has not been set datei = termArrCount.length - 1; //this returns the count for the last entry in the xml, aka Today } color Colour = color(r,g,b,a); for(int i = 0; i < termQueries.length; i++){ // display all of the text terms for the selected date flterms[i].updateTerm(datei, flterms[i].tx, flterms[i].ty, Colour); // date array key, x, y, color } smooth(); // This is the same green as the selected term Colour = color(88, 156, 28); // x, y, GraphWidth, GraphHeight, LineColour, GraphCurvature nGraph[termClicked].display(woffset, 375, graphWidth, graphHeight, Colour, 10); detectMouseOnGraph(); //check if lineMouseX has been set if(lineMouseX > 0) { color fixedColour = color(0); stroke(0); fixedMonthIndicator.update(lineAngledMonthX, lineAngledX, lineMouseX, fixedColour, true); } else { color fixedColour = color(0); stroke(0); fixedMonthIndicator.update(graphWidth-127, graphWidth-37, graphWidth-3+woffset, fixedColour, true); } if(mouseY > 365 && mouseX > woffset) { //check the angle of the lines to be drawn if(mouseX > width-200) { angledX = mouseX - 30; angledMonthX = angledX - 90; } else { angledX = mouseX+30; angledMonthX = angledX; } stroke(150); // movingMonthIndicator.update(angledMonthX, angledX, mouseX, Colour, false); } //draw a box around the graph and words stroke(60); noFill(); rect(woffset,0,920,515); } // really basic collision strategy: // sides of the window are walls // if it hits a wall pull it outside the wall and flip the direction of the velocity // the collisions aren't perfect so we take them down a notch too void handleBoundaryCollisions( Particle p ){ if ( p.position().x() < 50 || p.position().x() > width-100 ) p.setVelocity( -0.9*p.velocity().x(), p.velocity().y(), 0 ); if ( p.position().y() < 50 || p.position().y() > height-150 ) p.setVelocity( p.velocity().x(), -0.9*p.velocity().y(), 0 ); p.moveTo( constrain( p.position().x(), 50, width-100 ), constrain( p.position().y(), 50, height-150 ), 0 ); }