//import processing.opengl.*; //import processing.xml.*; //import org.json.*; PFont font; PFont bigfont; String[] Series_Data; ArrayList SeriesList = new ArrayList(60000); HashMap SeriesMap = new HashMap(60000); int numSeries = 0; int graph_start_year = 1790; int graph_end_year = 2010; int graph_span = graph_end_year - graph_start_year; int grid_width = 400; int grid_height = 330; //int square_dim = 2; float grid_dim = 3; SeriesSquare[][] theGrid = new SeriesSquare[grid_width][grid_height]; SeriesSquare selectedSeries; SeriesSquare latchedSeries; float sq_scale = 0.5; // scale factor for squares int selected_row = 0; int selected_col= 0; int[] row_labels = new int[grid_height]; int sort_by = 1; // 0 for content, 1 for accumulation int xmargin = 20; int ymargin = 40; PImage grid_bg; PImage grid_bg_bw; void setup() { colorMode(HSB,255); //size(1480, 1200,OPENGL); size(1280,1060);//grid_width*grid_dim+(xmargin*2)+40,grid_height*grid_dim+(ymargin*2)); background(0); font = createFont("Arial",11); //bigfont = loadFont("Helvetica-Bold-36.vlw"); Ingest("Series_Links_lines.json", SeriesList); // args file path, arraylist grid_bg = loadImage("grid_squarepack_links_recording.png"); grid_bg_bw = grid_bg.get(); grid_bg_bw.filter(GRAY); // grid_bg_bw.filter(BLUR,1); //grid_bg_bw = loadImage("grid_squarepack_links_bw.png"); sortSeries(); packGrid(); smooth(); } void draw(){ //noLoop(); background(0); if (latchedSeries == null){ image(grid_bg,0,0); } else { image(grid_bg_bw,0,0); } translate(xmargin,ymargin); //drawGrid(); if (latchedSeries != null){ noStroke(); fill(0,120); rect(0,0,grid_width*grid_dim,grid_height*grid_dim); drawSeries(latchedSeries); drawLinks(latchedSeries); } hoverLabels(); Labels(); //Caption(); } void packGrid(){ int grid_row = 0; int grid_col = 0; ArrayList PackingList = new ArrayList(5000); // arraylist to store the current year's squares int packing_year = 0; int end_row = 0; int end_col = 0; for (int s=0; s < SeriesList.size(); s++){ if (s%10000 == 0) println("packing series "+ s + " into row " + grid_row); SeriesSquare thisSeries = (SeriesSquare) SeriesList.get(s); //println("Series: " + s + " dim: "+ thisSeries.dimension + " col: " + grid_col + " row: " + grid_row); int this_year = 0; if (sort_by == 0) this_year = thisSeries.ContStartDate; else if (sort_by == 1) this_year = thisSeries.AccumStartDate; if (this_year == packing_year) { PackingList.add(thisSeries); // put it in the packing list } else { // a new year - first sort and pack the list we've made Comparator bySize = new DimComparator(); // make a new comparator for sorting the list by size (descending) java.util.Collections.sort(PackingList,bySize); // sort the packing list int start_row = end_row; // start from where the previous year ended int start_col = end_col; //println("packing year " + packing_year + " - " + PackingList.size() + " series"); for (int p=0; p= grid_width){ // check first that there's space on the grid grid_col = 0; // if not, move down a row grid_row++; } for (int c=grid_col; c<(grid_col+PackSquare.dimension); c++){ if (theGrid[c][grid_row] != null) { collide = true; SeriesSquare collideSeries = (SeriesSquare) theGrid[c][grid_row]; // series we're colliding with grid_col = c+collideSeries.dimension; // jump to the end of the series we collided with break; // hop out of the for loop, keep searching for a place } } // if we get this far, collide == false and we have found a space } PackSquare._x = grid_col; PackSquare._y = grid_row; if ((grid_row*grid_width)+grid_col > (end_row*grid_width)+end_col){ end_row = grid_row; end_col = grid_col; } for (int r=grid_row; r 0) colourString = theSeries.Recording_Agencies[0]; fill(agencyColour(colourString)); rect(theSeries._x*grid_dim,theSeries._y*grid_dim,theSeries.dimension*grid_dim,theSeries.dimension*grid_dim); // now the inside square float insideDim = max(0,(theSeries.dimension - (sqrt(theSeries.Items)*0.05)-1)); // dimension fill(60); rect((theSeries._x+((theSeries.dimension-insideDim)*0.5))*grid_dim,(theSeries._y+((theSeries.dimension-insideDim)*0.5))*grid_dim,insideDim*grid_dim,insideDim*grid_dim); } void drawGrid(){ for (int s=0; s < SeriesList.size(); s++){ SeriesSquare thisSeries = (SeriesSquare) SeriesList.get(s); if (thisSeries == selectedSeries){ stroke(255); } else { stroke(0); } strokeWeight(0.5); String colourString = "ZZ 0000"; if (thisSeries.Recording_Agencies.length > 0) colourString = thisSeries.Recording_Agencies[0]; fill(agencyColour(colourString)); rect(thisSeries._x*grid_dim,thisSeries._y*grid_dim,thisSeries.dimension*grid_dim,thisSeries.dimension*grid_dim); // now the inside square float insideDim = max(0,(thisSeries.dimension - (sqrt(thisSeries.Items)*0.05)-1)); // dimension fill(60); rect((thisSeries._x+((thisSeries.dimension-insideDim)*0.5))*grid_dim,(thisSeries._y+((thisSeries.dimension-insideDim)*0.5))*grid_dim,insideDim*grid_dim,insideDim*grid_dim); } if (latchedSeries != null){ drawLinks(latchedSeries); } } void drawLinks(SeriesSquare selectedSeries){ for (int l=0; l 0) recAgency1 = selectedSeries.Recording_Agencies[0]; String theCaption2 = selectedSeries.AccumStartDate + "-" + selectedSeries.AccumEndDate + " " + selectedSeries.Items + " items in "+ selectedSeries.Metres +"m " + " Recording Agency 1: " + recAgency1;//map(selectedSeries.Items,0,50000,40,255); if (theCaption.length() > 100) theCaption = theCaption.substring(0,100)+ "..."; // trim the text to 100 chars float txtWidth = max(textWidth(theCaption),textWidth(theCaption2)); fill(0,180); noStroke(); rect(min((grid_width*grid_dim)-txtWidth-10,(selectedSeries._x*grid_dim)+xtextpos-10),(selectedSeries._y*grid_dim)-40,txtWidth+10,35); fill(255); text(theCaption, min((grid_width*grid_dim)-txtWidth-5,(selectedSeries._x*grid_dim)+xtextpos-5), (selectedSeries._y*grid_dim)-26); text(theCaption2, min((grid_width*grid_dim)-txtWidth-5,(selectedSeries._x*grid_dim)+xtextpos-5), (selectedSeries._y*grid_dim)-11); //text("brightness key: "+ keyLabel,0,(grid_height*grid_dim)+15); } void Labels(){ fill(255); int labelcount =0; for (int l=0; l 0){ textFont(font,11); float xpos = -30; /*if (labelcount%2 ==1)*/ xpos = (grid_width*grid_dim)+10; // odd numbered labels go on the right if (labelcount < 1 || labelcount > 4){ text(row_labels[l],xpos,((l+1)*grid_dim)+2); } labelcount++; } } } void sortSeries(){ if (sort_by == 1){ Comparator byAccum = new AccumStartDateComparator(); java.util.Collections.sort(SeriesList,byAccum); // pass in comparator as an argument to sort } else if (sort_by == 0){ Comparator byCont = new ContStartDateComparator(); java.util.Collections.sort(SeriesList,byCont); // pass in comparator as an argument to sort } } void keyPressed(){ if (key == 's'){ save("grid_squarepack_links.png"); } if (keyCode == UP){ selected_row--; } else if (keyCode == DOWN){ selected_row++; } else if (keyCode == LEFT){ selected_col--; } else if (keyCode == RIGHT){ selected_col++; } //selectedSeries = theGrid[selected_col][selected_row]; } void hoverLabels(){ if ((mouseX > xmargin) && (mouseY > ymargin) && (mouseX < xmargin+(grid_dim*grid_width)) && (mouseY < ymargin+(grid_dim*grid_width))){ selected_row = int((mouseY-ymargin)/grid_dim); selected_col = int((mouseX-xmargin)/grid_dim); selectedSeries = theGrid[selected_col][selected_row]; if (selectedSeries != null) Caption(); } } void mousePressed(){ if (selectedSeries == latchedSeries){ latchedSeries = null; } else if (selectedSeries != null){ latchedSeries = selectedSeries; } }