/* * Author : Bita Mazloom * Course : MAT259 Winter 2011 * Title : Dewey TreeMap Animation * Reference : Ben Fry's Visualizing Data */ import java.io.File; import java.io.PrintWriter; import java.util.regex.*; import java.lang.Integer; import java.text.Format; import java.text.SimpleDateFormat; import java.util.GregorianCalendar; import java.util.Calendar; import java.util.Date; import de.bezier.data.sql.*; import processing.core.PApplet; import processing.core.PFont; import processing.core.PImage; public class DeweyTreeMap extends PApplet { private static final long serialVersionUID = 1L; // SBK:warning fix in final String TITLE = "Checkout Transactions from Dewey Classes to Books"; final String REFERENCE_LABEL = "Visualizing Data, Bita Mazloom"; final String REFERENCE_LINK = "http://benfry.com"; final boolean DEBUG_MODE = true; final int DEBUG_ZOOM_MULTIPLE = 1; final boolean CONNECT_TO_MYSQL = true; final boolean QUERY_CKOUT_COUNT = false; final boolean ENABLE_BARCODE2TITLE_SEARCH = false; final boolean ENABLE_TIMELINE_AT_EACH_ZOOP_DEPTH = false; final int MAX_NUM_DEWEY_CLASSES = 10; final int DEWEY_CLASS_SIZE = 100; final int DEWEY_SUBCLASS1_SIZE = 10; final int DEWEY_SUBCLASS2_SIZE = 1; final int MAX_NUM_SUBCLASS3_DEWEYS = 0; // <-------- NOTE: not used. orignially set due to out of heap memory final int MAX_NUM_SUBCLASS3_TITLES = 2; //5; final int WIDTH = 1024; final int HEIGHT = 730; final int MARGIN_SIZE = 10; final int BUTTON_MARGIN_SIZE = 10; final int TREEMAP_PANEL_WIDTH = (WIDTH - MARGIN_SIZE * 2); final int TREEMAP_PANEL_HEIGHT = (HEIGHT - MARGIN_SIZE * 4) / 3; final int TIMELINE_PANEL_WIDTH = TREEMAP_PANEL_WIDTH; final int TIMELINE_PANEL_HEIGHT = (HEIGHT - MARGIN_SIZE * 4) / 3; final int BOTTOM_PANEL_WIDTH = TREEMAP_PANEL_WIDTH; final int BOTTOM_PANEL_HEIGHT = (HEIGHT - MARGIN_SIZE * 4) / 3; final int TITLE_TEXT_COLOR = 255; final int TITLE_HEIGHT = 30; final int TITLE_VERTICAL_SPACE = 0; final int COUNT_LEGEND_HEIGHT = 80; final int IMAGE_BOOK_WIDTH = 100; final int IMAGE_BOOK_HEIGHT = 57; final int BACKGROUND_COLOR = 200; final int PANEL_BACKGROUND_COLOR = 215; final int PANEL_BORDER_COLOR = 125; final int PANEL_BORDER_STROKE_WEIGHT = 4; final int LEGEND_COLOR = 75; final int LEGEND_STROKE_COLOR = 100; final int LEGEND_STROKE_HIGHLIGHT_COLOR = 50; final int ZOOMBAR_FACE_COLOR = 235; final int ZOOMBAR_BORDER_COLOR = 200; final int ZOOMBAR_SHADOW_COLOR = 125; final int TIMELINE_AREA_COLOR = 235; final int ZOOM_DEPTH = 4; final int ZOOM_PLUS = ZOOM_DEPTH; final int ZOOM_MINUS = ZOOM_DEPTH+1; final int ZOOM_BUTTON_SIZE = 30; final int MAX_INVALID_ZOOMIN_MESSAGE_TIME = 1; final int TIMELINE_BUTTON_SIZE = 32; final int TIMELINE_INTERVAL_INDICATOR_SIZE = 10; final int TIMELINE_DRAW_DELAY_TIME = 1; final int NUM_YEARS = 2010-2005; final int NUM_MONTHS = 12; final int NUM_DAYS = 31; final int STARTING_YEAR = 2005; final int TIMELINE_HEIGHT = 80; final int TIMELINE_LABEL_HEIGHT = 20; final String titleHistoryFreqFileName = "freq_title_war.tsv"; final String barcodeFileName = "barcodes.tsv"; final String barcodeTitleFileName = "barcode_titles.tsv"; final String monthNames[] = {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"}; Coordinates treemap_panel_coordinates; Coordinates timeline_panel_coordinates; Coordinates bottom_panel_coordinates; Coordinates treemap_coordinates; Coordinates timeline_coordinates; Coordinates zoombar_coordinates; Coordinates zoomlabel_coordinates; Coordinates countbar_coordinates; Coordinates title_coordinates; Coordinates reference_label_coordinates; DeweyClass rootItem; SubClass rolloverItem; DeweyClass taggedItem; BoundsIntegrator zoomBounds; DeweyClass zoomItem; DeweyClass highlightedItem; Coordinates[] zoomBarPositions = new Coordinates[ZOOM_DEPTH+2]; // + 2 for plus and minus signs String[] zoomBarLabels = new String[ZOOM_DEPTH]; double[] zoomBarCounts = new double[ZOOM_DEPTH]; int[] zoomBarColors = new int[ZOOM_DEPTH]; SubClass[] zoomedInSubClassLevels = new DeweyClass[ZOOM_DEPTH]; int zoombar_section_width = 8; int zoombar_section_height; int currentZoomDepth = 0; int mouseX_prev_class, mouseY_prev_class; int invalidZoomInMessageStartTime = 0; boolean showZoomInMessage = false; Coordinates timelineLegend[] = new Coordinates[NUM_YEARS + 1]; Coordinates timelinePlayButton; Coordinates timelinePlayLocation; Coordinates timelineZoomOutButton; Coordinates timelineStartIndicatorInitial, timelineStartIndicator; Coordinates timelineStopIndicatorInitial, timelineStopIndicator; Coordinates timelineIntervalIndicatorInitial, timelineIntervalIndicator; Coordinates timelineZoomIntervalIndicator; Coordinates dateIndicator; int playTime; int redrawTimelineStartTime = 0; boolean playAnimation = false; boolean update = true; boolean pressedPlayLocation = false; boolean zoomOutTimeLine = false; boolean pressedtimelineStartIndicator = false; boolean releasedtimelineStartIndicator = true; boolean pressedtimelineStopIndicator = false; boolean releasedtimelineStopIndicator = true; DateInterval all_dates; int draggedToPoint[] = new int[2]; RankedLongArray numTransactions = new RankedLongArray(); PFont font; PFont title_font; PFont reference_font; PFont invalid_action_font; PFont date_indicator_font; PFont timeline_zoomOut_font; static File C_FILE; // Used for getting file separator in platform independent manner String server = "vislab2.mat.ucsb.edu"; String user = "mat259"; String pass = "V1sual1zat1on"; String database = "spl"; String table_items = "items"; String table_transactions = "transactions"; MySQL msql; public void setup() { // NOTE : numeric values required for Eclipse Processing exporter size(1024, 730); //size(WIDTH, HEIGHT); // Fonts font = createFont("SansSerif", 13); title_font = createFont("SansSerif", 16, true); reference_font = createFont("SansSerif", 8, true); invalid_action_font = createFont("SansSerif", 12, true); date_indicator_font = createFont("SansSerif-bold", 24, true); timeline_zoomOut_font = createFont("Sanserif-bold", 16, true); // Coordinates of the panels treemap_panel_coordinates = new Coordinates(MARGIN_SIZE, MARGIN_SIZE, MARGIN_SIZE + TREEMAP_PANEL_WIDTH, MARGIN_SIZE + TREEMAP_PANEL_HEIGHT); timeline_panel_coordinates = new Coordinates(MARGIN_SIZE, treemap_panel_coordinates.getY1() + MARGIN_SIZE, width - MARGIN_SIZE, treemap_panel_coordinates.getY1() + MARGIN_SIZE + TIMELINE_PANEL_HEIGHT); bottom_panel_coordinates = new Coordinates(MARGIN_SIZE, timeline_panel_coordinates.getY1() + MARGIN_SIZE, width - MARGIN_SIZE, timeline_panel_coordinates.getY1() + MARGIN_SIZE + BOTTOM_PANEL_HEIGHT); // Coordinates of the sub-panels treemap_coordinates = new Coordinates(treemap_panel_coordinates.getX0(), treemap_panel_coordinates.getY0(), treemap_panel_coordinates.getX1()+8, treemap_panel_coordinates.getY1()); timeline_coordinates = new Coordinates(timeline_panel_coordinates.getX0() + MARGIN_SIZE, timeline_panel_coordinates.getY0() + MARGIN_SIZE, timeline_panel_coordinates.getX1() - MARGIN_SIZE, timeline_panel_coordinates.getY1()); zoombar_coordinates = new Coordinates(bottom_panel_coordinates.getX0(), bottom_panel_coordinates.getY0(), bottom_panel_coordinates.getX0() + IMAGE_BOOK_WIDTH, bottom_panel_coordinates.getY1()); zoomlabel_coordinates = new Coordinates(zoombar_coordinates.getX1() + MARGIN_SIZE, bottom_panel_coordinates.getY0(), zoombar_coordinates.getX1() + (bottom_panel_coordinates.getWidth() - zoombar_coordinates.getWidth() - MARGIN_SIZE*2)/2, bottom_panel_coordinates.getY1()); countbar_coordinates = new Coordinates(zoomlabel_coordinates.getX1() + MARGIN_SIZE, bottom_panel_coordinates.getY0() + MARGIN_SIZE*2, zoomlabel_coordinates.getX1() + zoomlabel_coordinates.getWidth(), bottom_panel_coordinates.getY1() - MARGIN_SIZE); zoomBounds = new BoundsIntegrator(treemap_panel_coordinates.getX0(), treemap_panel_coordinates.getY0(), treemap_panel_coordinates.getWidth(), treemap_panel_coordinates.getHeight()); // begin play indicator at beginning of timeline timelinePlayLocation = new Coordinates(timeline_coordinates.getX0(), timeline_coordinates.getY0(), timeline_coordinates.getX0(), timeline_coordinates.getY0() + timeline_coordinates.getHeight()/2); // timelinePlayButton = new Coordinates(x0, timeline_panel_coordinates.getY1()-timeline_panel_coordinates.getHeight()/4, zoomBarPositions[ZOOM_PLUS].getX0()+zoomBarPositions[ZOOM_PLUS].getWidth()/2+TIMELINE_BUTTON_SIZE/2, timeline_panel_coordinates.getY1()-timeline_panel_coordinates.getHeight()/4+TIMELINE_BUTTON_SIZE); // timelinePlayButton = new Coordinates(timeline_panel_coordinates.getX0()+MARGIN_SIZE, timeline_panel_coordinates.getY1()-timeline_panel_coordinates.getHeight()/4, timeline_panel_coordinates.getX0()+MARGIN_SIZE+TIMELINE_BUTTON_SIZE, timeline_panel_coordinates.getY1()-timeline_panel_coordinates.getHeight()/4+TIMELINE_BUTTON_SIZE); timelineIntervalIndicatorInitial = timelineIntervalIndicator = new Coordinates(timeline_coordinates.getX0(), timeline_panel_coordinates.getY1()-timeline_panel_coordinates.getHeight()/4-BUTTON_MARGIN_SIZE-TIMELINE_INTERVAL_INDICATOR_SIZE/2, timeline_coordinates.getX1(), timeline_panel_coordinates.getY1()-timeline_panel_coordinates.getHeight()/4-BUTTON_MARGIN_SIZE-TIMELINE_INTERVAL_INDICATOR_SIZE/2); timelineStartIndicatorInitial = timelineStartIndicator = new Coordinates(timeline_coordinates.getX0(), timelineIntervalIndicator.getY0()-BUTTON_MARGIN_SIZE/2, timeline_coordinates.getX0()+TIMELINE_INTERVAL_INDICATOR_SIZE, timelineIntervalIndicator.getY0()+BUTTON_MARGIN_SIZE/2); timelineStopIndicatorInitial = timelineStopIndicator = new Coordinates(timeline_coordinates.getX1()-BUTTON_MARGIN_SIZE, timelineIntervalIndicator.getY0()-BUTTON_MARGIN_SIZE/2, timeline_coordinates.getX1(), timelineIntervalIndicator.getY0()+BUTTON_MARGIN_SIZE/2); textFont(title_font); title_coordinates = new Coordinates(bottom_panel_coordinates.getX1() - (int)textWidth(TITLE) - MARGIN_SIZE/2, bottom_panel_coordinates.getY1(), bottom_panel_coordinates.getX1() - MARGIN_SIZE/2, bottom_panel_coordinates.getY1() - MARGIN_SIZE); textFont(reference_font); reference_label_coordinates = new Coordinates((bottom_panel_coordinates.getX1()-(int)(textAscent() - textDescent())), (bottom_panel_coordinates.getY0()+(int)textWidth(REFERENCE_LABEL)-MARGIN_SIZE*3), (bottom_panel_coordinates.getX1()), bottom_panel_coordinates.getY1()); // start at first day playTime = 0; cursor(CROSS); rectMode(CORNERS); smooth(); noStroke(); for(int i=0; i < ZOOM_DEPTH; i++) { zoomBarLabels[i] = ""; zoomBarCounts[i] = 0; } if(!DEBUG_MODE) { msql = new MySQL( this, server, database, user, pass ); print("DeweyTreeMap : setup() : Connecting to mysql...\n\n"); if ( msql.connect() ) System.out.println("DeweyTreeMap : setup() : SUCCESS connected to database!"); else { System.out.println("DeweyTreeMap : setup() : WARNING unable to connect to database or database connection disabled."); msql = null; } } if(ENABLE_BARCODE2TITLE_SEARCH && msql != null && !(new File(".." + File.separator + "data" + File.separator + barcodeTitleFileName).exists())) { System.out.println("DeweyTreeMap : setup() : file barcode_title.tsv found."); queryBarcodeTitles(); } DeweyClass root_dewey = buildDeweyRanges(); if(msql != null && !(new File(".." + File.separator + "data" + File.separator + titleHistoryFreqFileName).exists())) { queryCheckoutCount(" War "); } readCheckoutCount(root_dewey); setRoot(root_dewey); } public void testSetCheckoutCount(DeweyClass root_dewey) { // int dewey = 782; // String subclass_3 = ".91"; // Date date = DEBUG_DATE; // Range testrange = new Range(dewey, dewey, "." + subclass_3, null); // CheckoutFrequency testfreq = new CheckoutFrequency(200, date); // root_dewey.addFrequencyToChild(testrange, testfreq); } public void queryBarcodeTitles() { String query; String barcode, title; String[] lines; String dataDir = ".." + File.separator + "data" + File.separator; String filename = dataDir + barcodeTitleFileName; PrintWriter outfile = createWriter(filename); outfile.println("barcode\ttitle"); lines = loadStrings(dataDir + barcodeFileName); for (int i = 1; i < lines.length; i++) { barcode = lines[i].replaceAll("\\n", ""); query = "SELECT title FROM items WHERE barcode = \'" + barcode + "\'"; msql.query(query); if(msql.next()) { title = msql.getString("title"); System.out.println(i + "\t" + barcode + "\t" + title); outfile.println(barcode + "\t" + title); } } outfile.close(); } public DeweyClass buildDeweyRanges() { int i = 0, low, high; int subclass_1, subclass_2; String label = ""; String dataDir = ".." + File.separator + "data" + File.separator; String filename; String lines[ ]; Pattern pattern_deweyClass = Pattern.compile("^class\t*"); Pattern pattern_subclass_1 = Pattern.compile("^subclass_1\t*"); Pattern pattern_subclass_2 = Pattern.compile("^\tsubclass_2\t*"); Pattern pattern_unassigned1 = Pattern.compile("Unassigned"); Pattern pattern_unassigned2 = Pattern.compile("Not assigned"); Pattern pattern; Matcher matcher; DeweyClass root_dewey; Range dewey_range; DeweyClass[] dewey_classes = new DeweyClass[MAX_NUM_DEWEY_CLASSES]; ReadDeweyProperties read_dewey; ReadDeweyProperties[] read_deweys = new ReadDeweyProperties[MAX_NUM_DEWEY_CLASSES]; filename = dataDir + "dewey_class_hierarchy.txt"; lines = loadStrings(filename); for (i = 0; i < MAX_NUM_DEWEY_CLASSES; i++) { matcher = pattern_deweyClass.matcher(lines[i]); if(matcher.find()) { low = Integer.parseInt(lines[i].substring(6, 9)); high = low + DEWEY_CLASS_SIZE-1; label = lines[i].substring(9); dewey_range = new Range(low, high, label, msql); read_dewey = new ReadDeweyProperties(dewey_range, 0); read_deweys[low/DEWEY_CLASS_SIZE] = read_dewey; } } for (; i < lines.length; i++) { matcher = pattern_unassigned1.matcher(lines[i]); if (matcher.find()) continue; matcher = pattern_unassigned2.matcher(lines[i]); if (matcher.find()) continue; matcher = pattern_subclass_1.matcher(lines[i]); if (matcher.find()) { low = Integer.parseInt(lines[i].substring(11, 14)); high = low + DEWEY_SUBCLASS1_SIZE-1; label = lines[i].substring(15); dewey_range = new Range(low, high, label, msql); read_dewey = new ReadDeweyProperties(dewey_range, 0); read_deweys[low/DEWEY_CLASS_SIZE].addChild(read_dewey); subclass_1 = (low%DEWEY_CLASS_SIZE)/DEWEY_SUBCLASS1_SIZE; for(subclass_2 = low; subclass_2 < (low+DEWEY_SUBCLASS1_SIZE); subclass_2++) { dewey_range = new Range(subclass_2, subclass_2+DEWEY_SUBCLASS2_SIZE-1, "[UNASSIGNED]", msql); read_dewey = new ReadDeweyProperties(dewey_range, 0); read_deweys[low/DEWEY_CLASS_SIZE].getChildAt(subclass_1).addChild(read_dewey); } continue; } matcher = pattern_subclass_2.matcher(lines[i]); if (matcher.find()) { low = Integer.parseInt(lines[i].substring(12, 15)); subclass_1 = (low%DEWEY_CLASS_SIZE)/DEWEY_SUBCLASS1_SIZE; subclass_2 = (low%10); //high = low + DEWEY_SUBCLASS2_SIZE-1; label = lines[i].substring(16); read_deweys[low/DEWEY_CLASS_SIZE].getChildAt((low%DEWEY_CLASS_SIZE)/DEWEY_SUBCLASS1_SIZE).setChildsLabel(subclass_2, label); continue; } } // FOR-LOOP : LINE IN FILE //System.out.println("dewey hierarchy = " ); //for(i = 0; i < read_deweys.length; i++) // System.out.println(read_deweys[i]); filename = dataDir + "dewey_transactions.tsv"; lines = loadStrings(filename); int dewey, count; String subclass_3 = ""; String[] barcodes; pattern = Pattern.compile("^([A-Za-z]*+)([0-9]++)(.[0-9]*+)?\t([0-9]*+)\t([0-9,]++)"); boolean matchFound; for (i = 0; i < lines.length; i++) { matcher = pattern.matcher(lines[i]); matchFound = matcher.find(); if (matchFound) { dewey = Integer.parseInt(matcher.group(2)); if(dewey < 0 || dewey > 999) continue; count = Integer.parseInt(matcher.group(4)); subclass_1 = (dewey%DEWEY_CLASS_SIZE)/DEWEY_SUBCLASS1_SIZE; subclass_2 = (dewey%10); if(matcher.group(3) != null) subclass_3 = (matcher.group(3)).substring(1); else subclass_3 = ""; barcodes = (matcher.group(5)).split(","); for(int j = 0; j max_class_size) max_class_size = size_of_children; else if(size_of_children < min_class_size) min_class_size = size_of_children; root_read_dewey.addChild(read_deweys[i]); } //System.out.println("DeweTreeMap : buildDeweyRanges() : size of smallest top level class = " + min_class_size + " size of largest top level class = " + max_class_size); dewey_classes[0] = new DeweyClass(null, root_read_dewey, 0, 0, this); root_dewey = dewey_classes[0]; if (root_dewey == null) System.err.println("DeweTreeMap : buildDeweyRanges() : ERROR Root dewey is null!"); return root_dewey; } public void readCheckoutCount(DeweyClass root_dewey) { int dewey, count; String subclass_3 = ""; String label = ""; String dataDir = ".." + File.separator + "data" + File.separator; String lines[ ]; Pattern pattern = Pattern.compile("^([A-Za-z]*+)([0-9]++)(.[0-9]*+)?\t([0-9]*+)\t([0-9]{4})\t([0-9]{1,2})\t([0-9]{1,2})\t([0-9,]++)"); Matcher matcher; boolean matchFound; Range dewey_range; Date date; Range book; CheckoutFrequency freq; long low_point; String dewey_class; String barcodes; String[] tmp; Date start_date = new GregorianCalendar(STARTING_YEAR, 0, 1).getTime(); Date end_date = new GregorianCalendar(STARTING_YEAR + NUM_YEARS, NUM_MONTHS-1, NUM_DAYS).getTime(); all_dates = new DateInterval(start_date, end_date); TimeLine t = new TimeLine(all_dates); TimeLine dewey_timelines[] = new TimeLine[MAX_NUM_DEWEY_CLASSES]; lines = loadStrings(dataDir + titleHistoryFreqFileName); for(int i = 0; i < lines.length; i++) { matcher = pattern.matcher(lines[i]); matchFound = matcher.find(); if (matchFound) { dewey = Integer.parseInt(matcher.group(2)); if(dewey < 0 || dewey > 999) continue; if(matcher.group(3) != null) subclass_3 = (matcher.group(3)).substring(1); else subclass_3 = ""; count = Integer.parseInt(matcher.group(4)); date = new GregorianCalendar(Integer.parseInt(matcher.group(5)), Integer.parseInt(matcher.group(6))-1, Integer.parseInt(matcher.group(7))-1).getTime(); //System.out.println("\nline[" + i + "] = " + lines[i]); freq = new CheckoutFrequency(count, date); t.updateFrequencyOfDate(count, date); // --------------------------------------------- // Set the frequency of dewey subclass // --------------------------------------------- // Create timeline for subclass1 only if(dewey_timelines[dewey/DEWEY_CLASS_SIZE] == null) dewey_timelines[dewey/DEWEY_CLASS_SIZE] = new TimeLine(all_dates); dewey_timelines[dewey/DEWEY_CLASS_SIZE].updateFrequencyOfDate(count, date); // Create timeline for all leafs if (ENABLE_TIMELINE_AT_EACH_ZOOP_DEPTH) { Matcher matcher2; Pattern pattern_test_dewey = Pattern.compile("940.5426"); matcher2 = pattern_test_dewey.matcher(lines[i]); if(matcher2.find()) { System.out.println("DeweyTreeMap : readCheckoutCount() : low/high = " + dewey + " subclass_3 = " + subclass_3); book = new Range(dewey, dewey, subclass_3, null); System.out.println("DeweyTreeMap : readCheckoutCount() : book dewey = " + book.getDewey()); root_dewey.addFrequencyToChild(book, freq); } } // IF-STATMENT ENABLE_TIMELINE_AT_EACH_ZOOP_DEPTH } } root_dewey.setTimeLine(t); if(root_dewey.timeLine == null) System.err.println("DeweTreeMap : buildDeweyRanges() : WARNING :Root Dewey class timeline is null!"); for(int i = 0; i < MAX_NUM_DEWEY_CLASSES; i++) { root_dewey.addTimeLineToChild(dewey_timelines); } System.out.println(""); } public void queryCheckoutCount(String title) { String query =""; String dataDir = ".." + File.separator + "data" + File.separator; String filename = dataDir + titleHistoryFreqFileName; PrintWriter outfile = createWriter(filename); CheckoutFrequency freq; Date date; String dewey_class; String barcodes; Calendar tmpcal = new GregorianCalendar(); outfile.println("deweyClass\tnumberOfCheckouts\tckoutYear\tckoutMonth\tckoutDay\tbookTitle\tlistOfBarcodes"); //for(int year_num = 0; year_num < NUM_YEARS; year_num++) { for(int month = 1; month <= NUM_MONTHS; month++) { for(int day = 1; day <= NUM_DAYS; day++) { query = "SELECT deweyclass AS deweyClass, count(*) AS numberOfCheckouts, " + "YEAR(ckoutDateTime) AS ckoutYear, MONTH(ckoutDateTime) AS ckoutMonth, DAY(ckoutDateTime) AS ckoutDay, " + "title AS bookTitle, " + "group_concat(distinct i.barcode) AS listOfBarcodes FROM transactions t,items i " + "WHERE (t.barcode = i.barcode) AND (i.title LIKE '%" + title + "%') AND " + "(YEAR(t.ckoutDateTime) = '" + 2010 + "') AND " + "(MONTH(t.ckoutDateTime) = '" + month + "') AND " + "(DAY(t.ckoutDateTime) = '" + day + "') AND " + "deweyclass IS NOT NULL " + "GROUP BY deweyclass ORDER BY deweyClass desc;"; //-System.out.println("\nquery = " + query); msql.query(query); while (msql.next()) { dewey_class = msql.getString("deweyClass"); tmpcal.set(msql.getInt("ckoutYear"), msql.getInt("ckoutMonth"), msql.getInt("ckoutDay")); date = tmpcal.getTime(); freq = new CheckoutFrequency(msql.getInt("numberOfCheckouts"), date); barcodes = msql.getString("listOfBarcodes"); outfile.println(dewey_class + "\t" + freq.getCount() + "\t" + getYear(freq.getDate())+ "\t" + getMonth(freq.getDate()) + "\t" + getDay(freq.getDate()) + "\t" + barcodes + "\t" + msql.getString("bookTitle")); } } // FOR-LOOP day } // FOR-LOOP month } // FOR-LOOP year_num outfile.close(); } void setRoot(DeweyClass root_dewey) { root_dewey.setBounds(treemap_panel_coordinates.getX0(), treemap_panel_coordinates.getY0(), treemap_panel_coordinates.getWidth(), treemap_panel_coordinates.getHeight()); root_dewey.contentsVisible = true; rootItem = root_dewey; rootItem.zoomIn(); rootItem.updateColors(); if(rootItem.timeLine == null) System.out.println("rootItem timeline IS null :'-("); } public void draw() { background(BACKGROUND_COLOR); textFont(font); frameRate(30); drawTreemapPanel(); drawFrameBorder(); drawBottomPanel(); drawTimeLinePanel(); drawZoomBarPosition(); drawInvalidZoomInMessage(); drawTitle(); drawReferenceLabel(); strokeWeight(1); rectMode(CORNERS); stroke(BACKGROUND_COLOR); } public int drawMultiLineText(String text, PFont f, int x0, int y0, int max_text_width, int color) { int c = 0; int label_width, hyphen_width; int label_height; String label; hyphen_width = (int)textWidth("-"); label_height = (int)(textAscent() - textDescent()) + 3; fill(color); while(c < text.length()) { label = ""; label_width = 0; for(; c < text.length() && (label_width+hyphen_width) < max_text_width; c++) { label += text.charAt(c); label_width = (int)textWidth(label); } if(c != text.length()) label += "-"; text(label, x0, y0); y0 += label_height + 1; } // return new Y0 for following text return y0 + label_height; } public void drawTreemapPanel() { zoomBounds.update(); rolloverItem = null; taggedItem = null; if (rootItem != null) { rootItem.draw(); } if (rolloverItem != null) { rolloverItem.drawTitle(); } if (taggedItem != null) { taggedItem.drawTag(); } } public void drawTimeLinePanel() { drawTimeLineLegend(); drawTimeLine(); if (playAnimation) drawTimeLinePlayButton(); else drawTimeLineStopButton(); drawTimeLineZoomOutButton(); drawTimeLineIntervalIndicator(); drawTimeLineStartIndicator(); drawTimeLineStopIndicator(); if(playAnimation) updatePlayLocation(); drawPlayLocation(); drawDateIndicator(); if(releasedtimelineStartIndicator && pressedtimelineStartIndicator) timelineStartIndicator = timelineStartIndicatorInitial; if(releasedtimelineStopIndicator && pressedtimelineStopIndicator) timelineStopIndicator = timelineStopIndicatorInitial; } public void drawBottomPanel() { drawZoomBar(); drawZoomLabels(); drawCountBars(); } public void drawFrameBorder() { fill(BACKGROUND_COLOR); rect(0, 0, width, treemap_coordinates.getY0()); rect(width, 0, treemap_coordinates.getWidth(), height); rect(0, treemap_coordinates.getY0()+treemap_coordinates.getHeight(), width, height); rect(0, 0, MARGIN_SIZE, height); // Panel Borders rectMode(CORNERS); strokeWeight(2); stroke(PANEL_BORDER_COLOR); fill(PANEL_BACKGROUND_COLOR); // TimeLine panel border rect(timeline_panel_coordinates.getX0(), timeline_panel_coordinates.getY0(), timeline_panel_coordinates.getX1(), timeline_panel_coordinates.getY1()); // Bottom panel border rect(bottom_panel_coordinates.getX0(), bottom_panel_coordinates.getY0(), bottom_panel_coordinates.getX1(), bottom_panel_coordinates.getY1()); // Treemap panel border noFill(); rect(treemap_panel_coordinates.getX0(), treemap_panel_coordinates.getY0(), treemap_panel_coordinates.getX1(), treemap_panel_coordinates.getY1()); stroke(BACKGROUND_COLOR); strokeWeight(1); } public void drawTimeLineLegend() { int timelineX0 = timeline_coordinates.getX0(); int timelineY0 = timeline_coordinates.getY0(); int timelineX1 = timeline_coordinates.getX1(); int timelineY1 = timeline_coordinates.getY1(); int timeline_height = (timelineY1 - timelineY0)/2; float legendX0 = timelineX0; float previous_legendX1 = 0; int legendY0 = timelineY0+timeline_height; int legend_interval = rootItem.timeLine.getLegendInterval(); int day_num; int tick_value = 0; int text_width; int text_height; String text = ""; Format formatter_month_year = new SimpleDateFormat("MMM-yy"); Format formatter_month_day_year = new SimpleDateFormat("MMM-dd-yyyy"); // timeline x-axis strokeWeight(2); stroke(LEGEND_STROKE_COLOR); fill(LEGEND_COLOR); line(timelineX0, timelineY0+timeline_height, timelineX1, timelineY0+timeline_height); textFont(font); text_height = (int)(textAscent() - textDescent()) + 3; textAlign(LEFT); if(legend_interval == 365) { for(day_num = 0; day_num < rootItem.timeLine.getTotalDaysInTimeLine(); day_num++) { if(getYear(rootItem.timeLine.getDate(day_num)) > tick_value) { legendX0 = map(day_num, 0, rootItem.timeLine.getTotalDaysInTimeLine(), timeline_coordinates.getX0(), timeline_coordinates.getX1()); stroke(LEGEND_STROKE_COLOR); line(legendX0, legendY0, legendX0, legendY0+4); tick_value = getYear(rootItem.timeLine.getDate(day_num)); if(day_num == 0) text = formatter_month_day_year.format(rootItem.timeLine.getDate(day_num)); else text = Integer.toString(tick_value); if(legendX0+textWidth(text) > timeline_coordinates.getX1()) break; if(previous_legendX1 > legendX0) continue; text(text, legendX0+1, legendY0+text_height*2+1); previous_legendX1 = legendX0 + textWidth(text); textAlign(CENTER); } //if(day_num-legend_interval != 0 && getYear(rootItem.timeLine.getDate(day_num)) > tick_value) // day_num++; } tick_value = getMonth(rootItem.timeLine.getDate(day_num)); text = formatter_month_day_year.format(rootItem.timeLine.getDate(day_num)); legendX0 = map(day_num, 0, rootItem.timeLine.getTotalDaysInTimeLine(), timeline_coordinates.getX0(), timeline_coordinates.getX1()); if(legendX0+textWidth(text) > timeline_coordinates.getX1()) { legendX0 = timeline_coordinates.getX1(); textAlign(RIGHT); } text(text, legendX0-1, legendY0+text_height*2+1); } // IF-STATEMENT : YEAR INTERVAL else if(legend_interval == 31) { for(day_num = 0; day_num < rootItem.timeLine.getTotalDaysInTimeLine()+2; day_num++) { if(getMonth(rootItem.timeLine.getDate(day_num)) != tick_value) { legendX0 = map(day_num, 0, rootItem.timeLine.getTotalDaysInTimeLine(), timeline_coordinates.getX0(), timeline_coordinates.getX1()); tick_value = getMonth(rootItem.timeLine.getDate(day_num)); if(day_num == 0) text = formatter_month_day_year.format(rootItem.timeLine.getDate(day_num)); else if (tick_value == 1) text = formatter_month_year.format(rootItem.timeLine.getDate(day_num)); else text = getMonthName(rootItem.timeLine.getDate(day_num)); if(legendX0+textWidth(text)*3 > timeline_coordinates.getX1()) break; if(previous_legendX1 > legendX0) continue; stroke(LEGEND_STROKE_COLOR); line(legendX0, legendY0, legendX0, legendY0+4); text(text, legendX0+1, legendY0+text_height*2+1); previous_legendX1 = legendX0 + textWidth(text) + 10; textAlign(CENTER); } //if(day_num-legend_interval != 0 && getYear(rootItem.timeLine.getDate(day_num)) > tick_value) // day_num++; } tick_value = getMonth(rootItem.timeLine.getDate(day_num)); text = formatter_month_day_year.format(rootItem.timeLine.getDate(day_num)); legendX0 = map(day_num, 0, rootItem.timeLine.getTotalDaysInTimeLine(), timeline_coordinates.getX0(), timeline_coordinates.getX1()); if(legendX0+textWidth(text) > timeline_coordinates.getX1()) { legendX0 = timeline_coordinates.getX1(); textAlign(RIGHT); } text(text, legendX0-1, legendY0+text_height*2+1); } // IF-STATEMENT : MONTH INTERVAL else if(legend_interval == 1) { for(day_num = 0; day_num < rootItem.timeLine.getTotalDaysInTimeLine(); day_num++) { legendX0 = map(day_num, 0, rootItem.timeLine.getTotalDaysInTimeLine(), timeline_coordinates.getX0(), timeline_coordinates.getX1()); text = formatter_month_day_year.format(rootItem.timeLine.getDate(day_num)); text_width = (int)textWidth(text); if(day_num != 0) text = Integer.toString(getDay(rootItem.timeLine.getDate(day_num))); if(legendX0+text_width+10 > timeline_coordinates.getX1()) break; if(previous_legendX1 > legendX0 || day_num %2 != 0) continue; text(text, legendX0+1, legendY0+text_height*2+1); previous_legendX1 = legendX0 + textWidth(text) + 10; textAlign(CENTER); } tick_value = getMonth(rootItem.timeLine.getDate(day_num)); text = formatter_month_day_year.format(rootItem.timeLine.getDate(day_num)); legendX0 = map(day_num, 0, rootItem.timeLine.getTotalDaysInTimeLine(), timeline_coordinates.getX0(), timeline_coordinates.getX1()); if(legendX0+textWidth(text) > timeline_coordinates.getX1()) { legendX0 = timeline_coordinates.getX1(); textAlign(RIGHT); } text(text, legendX0-1, legendY0+text_height*2+1); } // IF-STATEMENT : DAY INTERVAL } public void drawTimeLinePlayButton() { rectMode(CORNERS); noFill(); strokeWeight(2); stroke(ZOOMBAR_SHADOW_COLOR); rect(timelinePlayButton.getX0()+1, timelinePlayButton.getY0()+1, timelinePlayButton.getX1()+1, timelinePlayButton.getY1()+1); fill(ZOOMBAR_FACE_COLOR); rect(timelinePlayButton.getX0(), timelinePlayButton.getY0(), timelinePlayButton.getX1(), timelinePlayButton.getY1()); noTint(); fill(LEGEND_STROKE_COLOR); beginShape(); vertex(timelinePlayButton.getX0()+BUTTON_MARGIN_SIZE, timelinePlayButton.getY0()+BUTTON_MARGIN_SIZE); vertex(timelinePlayButton.getX1()-BUTTON_MARGIN_SIZE, timelinePlayButton.getY0()+timelinePlayButton.getHeight()/2); vertex(timelinePlayButton.getX0()+BUTTON_MARGIN_SIZE, timelinePlayButton.getY1()-BUTTON_MARGIN_SIZE); vertex(timelinePlayButton.getX0()+BUTTON_MARGIN_SIZE, timelinePlayButton.getY0()+BUTTON_MARGIN_SIZE); endShape(); } public void drawTimeLineStopButton() { // timelinePlayButton = new Coordinates(timeline_panel_coordinates.getX0()+MARGIN_SIZE, timeline_panel_coordinates.getY1()-timeline_panel_coordinates.getHeight()/4, timeline_panel_coordinates.getX0()+MARGIN_SIZE+TIMELINE_BUTTON_SIZE, timeline_panel_coordinates.getY1()-timeline_panel_coordinates.getHeight()/4+TIMELINE_BUTTON_SIZE); timelinePlayButton = new Coordinates(zoomBarPositions[ZOOM_PLUS].getX0()+zoomBarPositions[ZOOM_PLUS].getWidth()/2-TIMELINE_BUTTON_SIZE/2, timeline_panel_coordinates.getY1()-timeline_panel_coordinates.getHeight()/4, zoomBarPositions[ZOOM_PLUS].getX0()+zoomBarPositions[ZOOM_PLUS].getWidth()/2+TIMELINE_BUTTON_SIZE/2, timeline_panel_coordinates.getY1()-timeline_panel_coordinates.getHeight()/4+TIMELINE_BUTTON_SIZE); rectMode(CORNERS); noFill(); strokeWeight(2); stroke(ZOOMBAR_SHADOW_COLOR); rect(timelinePlayButton.getX0()+1, timelinePlayButton.getY0()+1, timelinePlayButton.getX1()+1, timelinePlayButton.getY1()+1); fill(ZOOMBAR_FACE_COLOR); rect(timelinePlayButton.getX0(), timelinePlayButton.getY0(), timelinePlayButton.getX1(), timelinePlayButton.getY1()); noTint(); fill(LEGEND_STROKE_COLOR); rect(timelinePlayButton.getX0()+BUTTON_MARGIN_SIZE, timelinePlayButton.getY0()+BUTTON_MARGIN_SIZE, timelinePlayButton.getX1()-BUTTON_MARGIN_SIZE, timelinePlayButton.getY1()-BUTTON_MARGIN_SIZE); } public void drawTimeLineZoomOutButton() { int text_width; String text = "Zoom Out"; textFont(timeline_zoomOut_font); text_width = (int)textWidth(text) + BUTTON_MARGIN_SIZE; timelineZoomOutButton = new Coordinates(timeline_coordinates.getX1() - text_width - MARGIN_SIZE, timeline_panel_coordinates.getY1()-timeline_panel_coordinates.getHeight()/4, timeline_coordinates.getX1() - MARGIN_SIZE, timeline_panel_coordinates.getY1()-timeline_panel_coordinates.getHeight()/4+TIMELINE_BUTTON_SIZE); rectMode(CORNERS); noFill(); strokeWeight(2); stroke(ZOOMBAR_SHADOW_COLOR); rect(timelineZoomOutButton.getX0()+1, timelineZoomOutButton.getY0()+1, timelineZoomOutButton.getX1()+1, timelineZoomOutButton.getY1()+1); if(zoomOutTimeLine) fill(ZOOMBAR_FACE_COLOR, 175); else fill(ZOOMBAR_FACE_COLOR); rect(timelineZoomOutButton.getX0(), timelineZoomOutButton.getY0(), timelineZoomOutButton.getX1(), timelineZoomOutButton.getY1()); noTint(); if(zoomOutTimeLine) fill(LEGEND_STROKE_HIGHLIGHT_COLOR); else fill(LEGEND_STROKE_COLOR); textAlign(CENTER, CENTER); text(text, timelineZoomOutButton.getX0()+timelineZoomOutButton.getWidth()/2, timelineZoomOutButton.getY0()+timelineZoomOutButton.getHeight()/2); } public void drawDateIndicator() { int x0, x1; int y0, y1; int text_height; Date date = rootItem.timeLine.getDate(playTime); int year = getYear(date); int month = getMonth(date); int day = getDay(date); dateIndicator = new Coordinates(timelinePlayButton.getX1()+MARGIN_SIZE*2, timelinePlayButton.getY0(), timelinePlayButton.getX1()+MARGIN_SIZE+MARGIN_SIZE+TIMELINE_BUTTON_SIZE*8, timelinePlayButton.getY1()); y0 = dateIndicator.getY0(); y1 = dateIndicator.getY1(); textAlign(CENTER, CENTER); textFont(date_indicator_font); text_height = (int)(textAscent() + textDescent()); rectMode(CORNERS); noFill(); strokeWeight(1); stroke(ZOOMBAR_SHADOW_COLOR); //rect(timelinePlayButton.getX0()+1, timelinePlayButton.getY0()+1, timelinePlayButton.getX1()+1, timelinePlayButton.getY1()+1); // month x0 = dateIndicator.getX0(); x1 = x0 + TIMELINE_BUTTON_SIZE; //fill(ZOOMBAR_SHADOW_COLOR); noFill(); rect(x0+1, y0+1, x1+1, y1+1); fill(ZOOMBAR_FACE_COLOR, 125); rect(x0, y0, x1, y1); fill(LEGEND_COLOR); text(month/10, (x1+x0)/2, y0+text_height/2); x0 = x1; x1 = x0 + TIMELINE_BUTTON_SIZE; //fill(ZOOMBAR_SHADOW_COLOR); noFill(); rect(x0+1, y0+1, x1+1, y1+1); fill(ZOOMBAR_FACE_COLOR, 125); rect(x0, y0, x1, y1); fill(LEGEND_COLOR); text(month%10, (x1+x0)/2, y0+text_height/2); // day x0 = x1 + MARGIN_SIZE/2; x1 = x0 + TIMELINE_BUTTON_SIZE; //fill(ZOOMBAR_SHADOW_COLOR); noFill(); rect(x0+1, y0+1, x1+1, y1+1); fill(ZOOMBAR_FACE_COLOR, 125); rect(x0, y0, x1, y1); fill(LEGEND_COLOR); text(day/10, (x1+x0)/2, y0+text_height/2); x0 = x1; x1 = x0 + TIMELINE_BUTTON_SIZE; //fill(ZOOMBAR_SHADOW_COLOR); noFill(); rect(x0+1, y0+1, x1+1, y1+1); fill(ZOOMBAR_FACE_COLOR, 125); rect(x0, y0, x1, y1); fill(LEGEND_COLOR); text(day%10, (x1+x0)/2, y0+text_height/2); // year x0 = x1 + MARGIN_SIZE/2; x1 = x0 + TIMELINE_BUTTON_SIZE; //fill(ZOOMBAR_SHADOW_COLOR); noFill(); rect(x0+1, y0+1, x1+1, y1+1); fill(ZOOMBAR_FACE_COLOR, 125); rect(x0, y0, x1, y1); fill(LEGEND_COLOR); text(year/1000, (x1+x0)/2, y0+text_height/2); x0 = x1; x1 = x0 + TIMELINE_BUTTON_SIZE; //fill(ZOOMBAR_SHADOW_COLOR); noFill(); rect(x0+1, y0+1, x1+1, y1+1); fill(ZOOMBAR_FACE_COLOR, 125); rect(x0, y0, x1, y1); fill(LEGEND_COLOR); text((year%1000)/100, (x1+x0)/2, y0+text_height/2); x0 = x1; x1 = x0 + TIMELINE_BUTTON_SIZE; //fill(ZOOMBAR_SHADOW_COLOR); noFill(); rect(x0+1, y0+1, x1+1, y1+1); fill(ZOOMBAR_FACE_COLOR, 125); rect(x0, y0, x1, y1); fill(LEGEND_COLOR); text(((year%1000)%100)/10, (x1+x0)/2, y0+text_height/2); x0 = x1; x1 = x0 + TIMELINE_BUTTON_SIZE; //fill(ZOOMBAR_SHADOW_COLOR); noFill(); rect(x0+1, y0+1, x1+1, y1+1); fill(ZOOMBAR_FACE_COLOR, 125); rect(x0, y0, x1, y1); fill(LEGEND_COLOR); text(((year%1000)%100)%10, (x1+x0)/2, y0+text_height/2); //noTint(); //fill(LEGEND_STROKE_COLOR); } public void drawTimeLineStartIndicator() { ellipseMode(CORNERS); noFill(); strokeWeight(1); stroke(ZOOMBAR_SHADOW_COLOR-10); ellipse(timelineStartIndicator.getX0()+1, timelineStartIndicator.getY0(), timelineStartIndicator.getX1()+1, timelineStartIndicator.getY1()); fill(255, 0, 0, 150); ellipse(timelineStartIndicator.getX0(), timelineStartIndicator.getY0(), timelineStartIndicator.getX1(), timelineStartIndicator.getY1()); } public void drawTimeLineStopIndicator() { ellipseMode(CORNERS); noFill(); strokeWeight(1); stroke(ZOOMBAR_SHADOW_COLOR-10); ellipse(timelineStopIndicator.getX0()+1, timelineStopIndicator.getY0(), timelineStopIndicator.getX1()+1, timelineStopIndicator.getY1()); fill(0, 0, 255, 150); ellipse(timelineStopIndicator.getX0(), timelineStopIndicator.getY0(), timelineStopIndicator.getX1(), timelineStopIndicator.getY1()); } public void drawTimeLineIntervalIndicator() { timelineZoomIntervalIndicator = new Coordinates(timelineStartIndicator.getX0(), timelinePlayButton.getY0()-BUTTON_MARGIN_SIZE-TIMELINE_INTERVAL_INDICATOR_SIZE/2, timelineStopIndicator.getX1(), timelinePlayButton.getY0()-BUTTON_MARGIN_SIZE-TIMELINE_INTERVAL_INDICATOR_SIZE/2); strokeWeight(10); strokeCap(ROUND); stroke(ZOOMBAR_SHADOW_COLOR + 60); line(timelineIntervalIndicator.getX0(), timelineIntervalIndicator.getY0(), timelineIntervalIndicator.getX1(), timelineIntervalIndicator.getY0()); strokeWeight(5); stroke(ZOOMBAR_SHADOW_COLOR + 20); line(timelineZoomIntervalIndicator.getX0()+3, timelineZoomIntervalIndicator.getY0(), timelineZoomIntervalIndicator.getX1()-3, timelineZoomIntervalIndicator.getY0()); } public void drawTimeLine() { stroke(LEGEND_STROKE_COLOR); strokeWeight(2); //noFill(); fill(TIMELINE_AREA_COLOR, 125); rootItem.drawTimeLine(); rootItem.updateFreqColors(); for(int i = 0; i < ZOOM_DEPTH; i++) { if(zoomedInSubClassLevels[i] == null) break; if(zoomedInSubClassLevels[i].timeLine != null) zoomedInSubClassLevels[i].drawSubclassTimeLine(); } } public void drawPlayLocation() { strokeWeight(1); stroke(255, 0, 0); line(timelinePlayLocation.getX0(), timelinePlayLocation.getY0(), timelinePlayLocation.getX1(), timelinePlayLocation.getY1()); } public boolean updatePlayLocation() { float x; if( playTime > rootItem.timeLine.getTotalDaysInTimeLine() ) return false; playTime++; x = map(playTime, 0, rootItem.timeLine.getTotalDaysInTimeLine(), timeline_coordinates.getX0(), timeline_coordinates.getX1()); if(x > timeline_coordinates.getX1()) x = timeline_coordinates.getX1(); timelinePlayLocation = new Coordinates((int)x, timeline_coordinates.getY0(), (int)x, timeline_coordinates.getY0() + timeline_coordinates.getHeight()/2); return true; } public void drawZoomBar() { PImage b; int plus_length = 8; int plus_thickness = 2; int zoomX0 = zoombar_coordinates.getX0() + IMAGE_BOOK_WIDTH/2; int zoomY0 = zoombar_coordinates.getY0() + (plus_length*3) + PANEL_BORDER_STROKE_WEIGHT*2; int zoomY1, zoomY1_saved; zoombar_section_height = (zoombar_coordinates.getHeight() - IMAGE_BOOK_HEIGHT - plus_length*3*2 - PANEL_BORDER_STROKE_WEIGHT*3) / (ZOOM_DEPTH+1); int label_width; int label_height; pushMatrix(); translate(zoomX0, zoomY0); noStroke(); // top control //fill(ZOOMBAR_COLOR); // minus sign strokeWeight(2); rectMode(CENTER); noFill(); stroke(ZOOMBAR_SHADOW_COLOR); rect(0+zoombar_section_width/2+1, -(plus_length*3)/2+1, plus_length*4, plus_length*3); fill(ZOOMBAR_FACE_COLOR); rect(0+zoombar_section_width/2, -(plus_length*3)/2, plus_length*4, plus_length*3); noTint(); fill(LEGEND_STROKE_COLOR); rect(0+zoombar_section_width/2, -(plus_length*3)/2, plus_length, plus_thickness); zoomBarPositions[ZOOM_MINUS] = new Coordinates(zoomX0+zoombar_section_width/2-(plus_length*4)/2, zoomY0-(plus_length*3), zoomX0+zoombar_section_width+(plus_length*4)/2, zoomY0+(plus_length*3)/2); // bottom control //fill(ZOOMBAR_COLOR); zoomY1 = (ZOOM_DEPTH+1) * zoombar_section_height + 1; // image imageMode(CENTER); b = loadImage("../images/book.png"); b.resize(IMAGE_BOOK_WIDTH, IMAGE_BOOK_HEIGHT); image(b, 0+zoombar_section_width/2, zoomY1+IMAGE_BOOK_HEIGHT/2+plus_length*3+3); // reference label textFont(reference_font); label_height = (int)(textAscent() - textDescent()); label_width = (int)textWidth(REFERENCE_LABEL); //reference_label_coordinates = new Coordinates(zoomX0+zoombar_section_width/2-label_width/2, zoomY0+zoomY1+IMAGE_BOOK_HEIGHT+plus_length*3+label_height, zoomX0+zoombar_section_width/2+label_width/2, zoomY0+zoomY1+IMAGE_BOOK_HEIGHT+plus_length*3+label_height*3); // bar zoomY1_saved = zoomY1; rectMode(CORNERS); strokeWeight(1); fill(ZOOMBAR_FACE_COLOR); rect(0, 1, zoombar_section_width, (ZOOM_DEPTH+1)*zoombar_section_height+1); zoomY1 = 0; stroke(ZOOMBAR_SHADOW_COLOR); line(0, zoomY1, zoombar_section_width, zoomY1); for(int i = 0; i < ZOOM_DEPTH; i++) { zoomY1 += zoombar_section_height; if(i != ZOOM_DEPTH) line(2, zoomY1, zoombar_section_width-2, zoomY1); zoomBarPositions[i] = new Coordinates(zoomX0-zoombar_section_width/2, zoomY0+zoomY1-zoombar_section_height*2, zoomX0+zoombar_section_width, zoomY0+zoomY1); } //zoomY1 += zoombar_section_height; //line(0, zoomY1, zoombar_section_width, zoomY1); // plus sign rectMode(CENTER); noFill(); strokeWeight(2); stroke(ZOOMBAR_SHADOW_COLOR); rect(0+zoombar_section_width/2+1, zoomY1_saved+(plus_length*3)/2+1, plus_length*4, plus_length*3); fill(ZOOMBAR_FACE_COLOR); rect(0+zoombar_section_width/2, zoomY1_saved+(plus_length*3)/2, plus_length*4, plus_length*3); noTint(); fill(LEGEND_STROKE_COLOR); rect(0+zoombar_section_width/2, zoomY1_saved+(plus_length*3)/2, plus_length, plus_thickness); rect(0+zoombar_section_width/2, zoomY1_saved+(plus_length*3)/2, plus_thickness, plus_length); zoomBarPositions[ZOOM_PLUS] = new Coordinates(zoomX0+zoombar_section_width/2-(plus_length*4)/2, zoomY0+zoomY1_saved, zoomX0+zoombar_section_width+(plus_length*4)/2, zoomY0+zoomY1_saved+plus_length*3); popMatrix(); noFill(); stroke(BACKGROUND_COLOR); } public void drawZoomBarPosition() { int arc_width = 16; int draw_X0 = zoomBarPositions[currentZoomDepth].getX0() + zoomBarPositions[currentZoomDepth].getWidth()/2; int zoom_divider_height = 4; //System.out.println(" drawZoomPosition() : currentZoomDepth = " + currentZoomDepth); rectMode(CENTER); stroke(ZOOMBAR_SHADOW_COLOR); fill(ZOOMBAR_FACE_COLOR); // NOTE: TRY USING ROUNDED RECTANGLE HERE INSTEAD... ellipseMode(RADIUS); ellipse(draw_X0+1+1, zoomBarPositions[currentZoomDepth].getY1()+1, arc_width, zoom_divider_height); ellipse(draw_X0+1, zoomBarPositions[currentZoomDepth].getY1(), arc_width, zoom_divider_height); line(zoomBarPositions[currentZoomDepth].getX0()+6, zoomBarPositions[currentZoomDepth].getY1(), zoomBarPositions[currentZoomDepth].getX1()-2, zoomBarPositions[currentZoomDepth].getY1()); } public void drawZoomLabels() { int max_label_width = zoomlabel_coordinates.getWidth(); int label_width, label_height; //int labelX0 = treemap_coordinates.getWidth() + max_label_width/2 + MARGIN_SIZE; int labelY1; textAlign(LEFT); textFont(font); label_height = (int)(textAscent() - textDescent()); //fill(LEGEND_COLOR); for(int i = 0; i < ZOOM_DEPTH; i++) { label_width = (int)textWidth(zoomBarLabels[i]); if(label_width > max_label_width) { labelY1 = zoomBarPositions[i].getY1() + label_height/2; drawMultiLineText(zoomBarLabels[i], font, zoomlabel_coordinates.getX0(), labelY1, max_label_width, LEGEND_COLOR); } else { fill(LEGEND_COLOR); text(zoomBarLabels[i], zoomlabel_coordinates.getX0()+1, zoomBarPositions[i].getY1()+1); fill(zoomBarColors[i]); text(zoomBarLabels[i], zoomlabel_coordinates.getX0(), zoomBarPositions[i].getY1()); } } } public void drawInvalidZoomInMessage() { int message_width; int message_height; String message; if(second() > invalidZoomInMessageStartTime+MAX_INVALID_ZOOMIN_MESSAGE_TIME) showZoomInMessage = false; if(showZoomInMessage) { textAlign(CENTER); textFont(invalid_action_font); message_height = (int)(textAscent() - textDescent()) + 3; message = " Choose a Dewey class "; message_width = (int)textWidth(message); fill(255, 0, 0); text(message, mouseX+message_width/2, mouseY); fill(ZOOMBAR_SHADOW_COLOR); text(message, mouseX+message_width/2+1, mouseY+1); message = " to zoom into."; fill(255, 0, 0); text(message, mouseX+message_width/2, mouseY+message_height); fill(ZOOMBAR_SHADOW_COLOR); text(message, mouseX+message_width/2+1, mouseY+message_height+1); } } public void drawCountBars() { int labelX0 = countbar_coordinates.getX0() + countbar_coordinates.getWidth()/2; int labelY0 = countbar_coordinates.getY0(); //int label_height = (int)(textAscent() + textDescent()); int label_margin = 4; int count_bar_height = zoombar_section_height-2;//label_height + label_margin*2; int count_bar_width = countbar_coordinates.getWidth(); double percentage = 1; double count; String label; strokeWeight(1); fill(LEGEND_COLOR); textFont(font); rectMode(CORNERS); textAlign(CENTER); label = "Transactions from 2005 to 2010:"; fill(LEGEND_COLOR); text(label, labelX0, labelY0); textAlign(LEFT); // special case, level 0 fill(ZOOMBAR_FACE_COLOR); stroke(ZOOMBAR_SHADOW_COLOR); rect(countbar_coordinates.getX0(), zoomBarPositions[0].getY1()-count_bar_height/2, countbar_coordinates.getX0()+count_bar_width, zoomBarPositions[0].getY1()+count_bar_height/2); label = String.format("%,.0f", rootItem.getSize()); fill(0); text(label, countbar_coordinates.getX0() + label_margin, zoomBarPositions[0].getY1()+label_margin); if(zoomItem.parent == null) return; for(int i = 1; i < currentZoomDepth+1; i++) { count = zoomBarCounts[i]; if(count == 0) break; percentage = zoomBarCounts[i] / zoomBarCounts[i-1]; stroke(ZOOMBAR_SHADOW_COLOR); fill(ZOOMBAR_SHADOW_COLOR); rect(countbar_coordinates.getX0(), zoomBarPositions[i].getY1()-count_bar_height/2, countbar_coordinates.getX0()+count_bar_width, zoomBarPositions[i].getY1()+count_bar_height/2); fill(ZOOMBAR_FACE_COLOR); rect(countbar_coordinates.getX0(), zoomBarPositions[i].getY1()-count_bar_height/2, countbar_coordinates.getX0()+(int)(count_bar_width*percentage), zoomBarPositions[i].getY1()+count_bar_height/2); fill(0); label = Double.toString(truncate(percentage*100)); text(label + " %", countbar_coordinates.getX0() + label_margin, zoomBarPositions[i].getY1() + label_margin); } } public void drawReferenceLabel() { boolean over = false; if(overReferenceLabel(mouseX, mouseY)) over = true; textFont(reference_font); if(over) fill(0, 0, 255); else fill(LEGEND_STROKE_COLOR); textAlign(RIGHT); pushMatrix(); rotate(-HALF_PI); text(REFERENCE_LABEL, -reference_label_coordinates.getY0(), reference_label_coordinates.getX0()); popMatrix(); } public void drawTitle() { textFont(title_font); fill(LEGEND_STROKE_COLOR); textAlign(CENTER); text(TITLE, title_coordinates.getX0()+title_coordinates.getWidth()/2, title_coordinates.getY0()+title_coordinates.getHeight()/2); } public void mousePressed() { // -1 nothing selected // 0 is no change (effectively similar to -1) // 1 zoom in // 2 zoom out int change_depth = selectZoomDepth(); pressedPlayLocation = false; pressedtimelineStartIndicator = false; pressedtimelineStopIndicator = false; if(change_depth > 0) { drawZoomBarPosition(); if(change_depth == 1) { if(highlightedItem == null) { invalidZoomInMessageStartTime = second(); showZoomInMessage = true; return; } zoomItem = highlightedItem; if(change_depth == 1) zoomItem.increaseZoomDepth(); highlightedItem = null; } else if(change_depth == 2) zoomItem.decreaseZoomDepth(); } else if (zoomItem != null) { zoomItem.mousePressed(); } if(overReferenceLabel(mouseX, mouseY)) { System.out.println("reference link = " + REFERENCE_LINK); link(REFERENCE_LINK, "_new"); } if(playButtonPressed(mouseX, mouseY)) { playAnimation = !playAnimation; } if(playLocationPressed(mouseX, mouseY)) { pressedPlayLocation = true; draggedToPoint[0] = mouseX - timelinePlayLocation.getX0(); } if(timelineStartIndicatorPressed(mouseX, mouseY)) { pressedtimelineStartIndicator = true; draggedToPoint[0] = mouseX - timelineStartIndicator.getX0(); } if(timelineStopIndicatorPressed(mouseX, mouseY)) { pressedtimelineStopIndicator = true; draggedToPoint[0] = mouseX - timelineStopIndicator.getX0(); } if(timelineZoomOutButtonPressed(mouseX, mouseY)) { zoomOutTimeLine = true; } } boolean playButtonPressed(int x, int y) { if(x >= timelinePlayButton.getX0() && x <= timelinePlayButton.getX1() && y >= timelinePlayButton.getY0() && y <= timelinePlayButton.getY1() ) return true; return false; } boolean playLocationPressed(int x, int y) { if(x >= (timelinePlayLocation.getX0() - 3) && x <= (timelinePlayLocation.getX1() + 3) && y >= (timelinePlayLocation.getY0() - 3) && y <= (timelinePlayLocation.getY1() + 3) ) return true; return false; } boolean timelineStartIndicatorPressed(int x, int y) { if(x > (timelineStartIndicator.getX0()) && x < (timelineStartIndicator.getX1()) && y > (timelineStartIndicator.getY0()) && y < (timelineStartIndicator.getY1()) ) return true; return false; } boolean timelineStopIndicatorPressed(int x, int y) { if(x > (timelineStopIndicator.getX0()) && x < (timelineStopIndicator.getX1()) && y > (timelineStopIndicator.getY0()) && y < (timelineStopIndicator.getY1()) ) return true; return false; } boolean timelineZoomOutButtonPressed(int x, int y) { if(x > (timelineZoomOutButton.getX0()) && x < (timelineZoomOutButton.getX1()) && y > (timelineZoomOutButton.getY0()) && y < (timelineZoomOutButton.getY1()) ) return true; return false; } public void mouseDragged() { int x0, y0; int day_num; if (pressedPlayLocation) { x0 = mouseX - draggedToPoint[0]; y0 = timelinePlayLocation.getY0(); if(x0 < timelineIntervalIndicatorInitial.getX0()) x0 = timelineIntervalIndicatorInitial.getX0(); if(x0 > timelineIntervalIndicatorInitial.getX1()) x0 = timelineIntervalIndicatorInitial.getX1(); timelinePlayLocation = new Coordinates(x0, y0, x0, y0 + timelinePlayLocation.getHeight()); day_num = (int)map((float)x0, (float)timeline_coordinates.getX0(), (float) timeline_coordinates.getX1(), 0, (float)rootItem.timeLine.getTotalDaysInTimeLine()); playTime = day_num; } if (pressedtimelineStartIndicator) { releasedtimelineStartIndicator = false; x0 = mouseX - draggedToPoint[0]; y0 = timelineStartIndicator.getY0(); if(x0 < (timelineIntervalIndicatorInitial.getX0() + BUTTON_MARGIN_SIZE)) x0 = timelineIntervalIndicatorInitial.getX0(); if(x0 > (timelineStopIndicator.getX0() - TIMELINE_INTERVAL_INDICATOR_SIZE - 2)) x0 = timelineStopIndicator.getX0() - TIMELINE_INTERVAL_INDICATOR_SIZE - 2; timelineStartIndicator = new Coordinates(x0, y0, x0+TIMELINE_INTERVAL_INDICATOR_SIZE, y0 + TIMELINE_INTERVAL_INDICATOR_SIZE); } if (pressedtimelineStopIndicator) { releasedtimelineStopIndicator = false; x0 = mouseX - draggedToPoint[0]; y0 = timelineStopIndicator.getY0(); if(x0 < (timelineStartIndicator.getX1() + TIMELINE_INTERVAL_INDICATOR_SIZE - 6)) x0 = timelineStartIndicator.getX1() + TIMELINE_INTERVAL_INDICATOR_SIZE - 6; if(x0 > (timelineIntervalIndicatorInitial.getX1() - TIMELINE_INTERVAL_INDICATOR_SIZE)) x0 = timelineIntervalIndicatorInitial.getX1() - TIMELINE_INTERVAL_INDICATOR_SIZE; timelineStopIndicator = new Coordinates(x0, y0, x0+TIMELINE_INTERVAL_INDICATOR_SIZE, y0 + TIMELINE_INTERVAL_INDICATOR_SIZE); } } public void mouseReleased() { int x0, x1; int day_num; Date start; Date end; if (zoomOutTimeLine) { rootItem.timeLine.zoomOut(); for(int i = 0; i < ZOOM_DEPTH; i++) { if(zoomedInSubClassLevels[i] == null) break; if(zoomedInSubClassLevels[i].timeLine != null) zoomedInSubClassLevels[i].timeLine.zoomOut(); } zoomOutTimeLine = false; } if(pressedtimelineStartIndicator) { releasedtimelineStartIndicator = true; x0 = timelineStartIndicator.getX0(); day_num = (int)map((float)x0, (float)timeline_coordinates.getX0(), (float) timeline_coordinates.getX1(), 0, (float)rootItem.timeLine.getTotalDaysInTimeLine()); start = rootItem.timeLine.getDate(day_num); end = rootItem.timeLine.zoomLevelRanges.get(rootItem.timeLine.getZoomLevel()).getEndDate(); rootItem.timeLine.zoomIn(start, end); for(int i = 0; i < ZOOM_DEPTH; i++) { if(zoomedInSubClassLevels[i] == null) break; if(zoomedInSubClassLevels[i].timeLine != null) zoomedInSubClassLevels[i].timeLine.zoomIn(start, end); } } if(pressedtimelineStopIndicator) { releasedtimelineStopIndicator = true; x1 = timelineStopIndicator.getX1(); start = rootItem.timeLine.zoomLevelRanges.get(rootItem.timeLine.getZoomLevel()).getStartDate(); day_num = (int)map((float)x1, (float)timeline_coordinates.getX0(), (float) timeline_coordinates.getX1(), 0, (float)rootItem.timeLine.getTotalDaysInTimeLine()); end = rootItem.timeLine.getDate(day_num); rootItem.timeLine.zoomIn(start, end); for(int i = 0; i < ZOOM_DEPTH; i++) { if(zoomedInSubClassLevels[i] == null) break; if(zoomedInSubClassLevels[i].timeLine != null) zoomedInSubClassLevels[i].timeLine.zoomIn(start, end); } } } public int selectZoomDepth() { if(this.mouseY > zoomBarPositions[ZOOM_PLUS].getY1() || this.mouseY < zoomBarPositions[ZOOM_MINUS].getY0()) return -1; if ((this.mouseY > zoomBarPositions[ZOOM_PLUS].getY0()) && (this.mouseY < zoomBarPositions[ZOOM_PLUS].getY1()) && (this.mouseX > zoomBarPositions[ZOOM_PLUS].getX0()) && (this.mouseX < zoomBarPositions[ZOOM_PLUS].getX1()) ) { if(currentZoomDepth < ZOOM_DEPTH-1) { if (highlightedItem != null) currentZoomDepth++; } else return -1; return 1; } if ( (this.mouseY > zoomBarPositions[ZOOM_MINUS].getY0()) && (this.mouseY < zoomBarPositions[ZOOM_MINUS].getY1()) && (this.mouseX > zoomBarPositions[ZOOM_MINUS].getX0()) && (this.mouseX < zoomBarPositions[ZOOM_MINUS].getX1()) ) { if(currentZoomDepth > 0) currentZoomDepth--; else return -1; return 2; } for(int i = 0; i < ZOOM_DEPTH; i++) { if ( (this.mouseY > zoomBarPositions[i].getY0()-4) && (this.mouseY < zoomBarPositions[i].getY1()+4) && (this.mouseX > zoomBarPositions[i].getX0()) && (this.mouseX < zoomBarPositions[i].getX1()) ) { if(i == currentZoomDepth) return 0; if (highlightedItem != null && i > currentZoomDepth) { currentZoomDepth = i; return 1; } else if (i < currentZoomDepth) { currentZoomDepth = i; return 2; } } } return -1; } boolean overReferenceLabel(int x, int y) { if(x >= reference_label_coordinates.getX0()-6 && x <= reference_label_coordinates.getX1()-2 && y >= reference_label_coordinates.getY0()-MARGIN_SIZE/2 && y <= reference_label_coordinates.getY1()) return true; return false; } static double truncate(double x) { if ( x > 0 ) return Math.floor(x * 100)/100; else return Math.ceil(x * 100)/100; } int getYear(Date date) { SimpleDateFormat simpleDateformat= new SimpleDateFormat("yyyy"); String str = simpleDateformat.format(date); return Integer.parseInt(str); } int getMonth(Date date) { SimpleDateFormat simpleDateformat=new SimpleDateFormat("M"); String str = simpleDateformat.format(date); return Integer.parseInt(str); } String getMonthName(Date date) { SimpleDateFormat simpleDateformat=new SimpleDateFormat("MMM"); return simpleDateformat.format(date); } int getDay(Date date) { SimpleDateFormat simpleDateformat=new SimpleDateFormat("dd"); String str = simpleDateformat.format(date); return Integer.parseInt(str); } int getMinClassSize() { return min_class_size; } int getMaxClassSize() { return max_class_size; } private int min_class_size = Integer.MAX_VALUE; int max_class_size = 0; }