Commits

Thejesh GN  committed 1cc7988

Added

  • Participants

Comments (0)

Files changed (8)

+TreeMap created using the XML. Inspired heavily from Ben Fry's example.

File src/libraries/treemap/library/treemap.jar

Binary file added.

File src/treemap/BoundsIntegrator.java

+// Code from Visualizing Data, First Edition, Copyright 2008 Ben Fry.
+
+
+public class BoundsIntegrator {
+
+  static final float ATTRACTION = 0.2f;
+  static final float DAMPING = 0.5f;
+
+  float valueX, velocityX, accelerationX;
+  float valueY, velocityY, accelerationY;
+  float valueW, velocityW, accelerationW;
+  float valueH, velocityH, accelerationH;
+
+  float damping;
+  float attraction;
+  
+  boolean targeting;
+  float targetX, targetY, targetW, targetH;
+
+
+  public BoundsIntegrator() {
+    this.valueX = 0;
+    this.valueY = 0;
+    this.valueW = 1;
+    this.valueH = 1;
+
+    this.damping = DAMPING;
+    this.attraction = ATTRACTION;
+  }
+
+
+  public BoundsIntegrator(float x, float y, float w, float h) {
+    this.valueX = x;
+    this.valueY = y;
+    this.valueW = w;
+    this.valueH = h;
+    
+    this.damping = DAMPING;
+    this.attraction = ATTRACTION;
+  }
+
+
+  public void set(float x, float y, float w, float h) {
+    this.valueX = x;
+    this.valueY = y;
+    this.valueW = w;
+    this.valueH = h;
+  }
+  
+  
+  public float getX() {
+    return valueX;
+  }
+  
+  
+  public float getY() {
+    return valueY;
+  }
+  
+  
+  public float getW() {
+    return valueW;
+  }
+  
+  
+  public float getH() {
+    return valueH;
+  }
+  
+  
+  public float spanX(float pointX, float start, float span) {
+    if (valueW != 0) {
+      //return (pointX - valueX) / valueW;
+      float n = (pointX - valueX) / valueW;
+      return start + n*span;
+    } else {
+      return Float.NaN;
+    }
+  }
+    
+  
+  public float spanY(float pointY, float start, float span) {
+    if (valueH != 0) {
+      //return (pointY - valueY) / valueH;
+      float n = (pointY - valueY) / valueH;
+      return start + n*span;
+    } else {
+      return Float.NaN;
+    }
+  }
+  
+  
+  public void setAttraction(float a) {
+    attraction = a;
+  }
+  
+  
+  public void setDamping(float d) {
+    damping = d;
+  }
+
+
+  public boolean update() {
+    if (targeting) {
+      accelerationX += attraction * (targetX - valueX);
+      velocityX = (velocityX + accelerationX) * damping;
+      valueX += velocityX;
+      accelerationX = 0;
+      boolean updated = (Math.abs(velocityX) > 0.0001f);
+      
+      accelerationY += attraction * (targetY - valueY);
+      velocityY = (velocityY + accelerationY) * damping;
+      valueY += velocityY;
+      accelerationY = 0;
+      updated |= (Math.abs(velocityY) > 0.0001f);
+
+      accelerationW += attraction * (targetW - valueW);
+      velocityW = (velocityW + accelerationW) * damping;
+      valueW += velocityW;
+      accelerationW = 0;
+      updated |= (Math.abs(velocityW) > 0.0001f);
+      
+      accelerationH += attraction * (targetH - valueH);
+      velocityH = (velocityH + accelerationH) * damping;
+      valueH += velocityH;
+      accelerationH = 0;
+      updated |= (Math.abs(velocityH) > 0.0001f);
+    }
+    return false;
+  }
+
+
+  public void target(float tx, float ty, float tw, float th) {
+    targeting = true;
+    targetX = tx;
+    targetY = ty; 
+    targetW = tw;
+    targetH = th;
+  }
+
+
+  public void targetLocation(float tx, float ty) {
+    targeting = true;
+    targetX = tx;
+    targetY = ty;
+  }
+  
+  
+  public void targetSize(float tw, float th) {
+    targeting = true;
+    targetW = tw;
+    targetH = th;
+  }
+  
+  
+  public void targetX(float tx) {
+    targeting = true;
+    targetX = tx;
+  }
+  
+  
+  public void targetY(float ty) {
+    targeting = true;
+    targetY = ty;
+  }
+
+  
+  public void targetW(float tw) {
+    targeting = true;
+    targetW = tw;
+  }
+
+  
+  public void targetH(float th) {
+    targeting = true;
+    targetH = th;
+  }
+}

File src/treemap/Node.pde

+/* Code heavily inspired/borrowed from Ben Fry's original code example */ 
+/* By Thejesh GN  */
+
+
+class Node extends NodeElement implements MapModel {
+  MapLayout algorithm = new PivotBySplitSize();
+  Mappable[] items;
+  boolean contentsVisible;
+  boolean layoutValid;
+  float darkness;
+
+
+  public Node(Node parent, XMLElement content, int level, int order) {
+    super(parent,content, order);
+    int kids = content.getChildCount();
+
+    println("Now working for"+content.getString("name")+"  Totoal children="+kids);
+    
+    if (kids > 0) {
+      items = new Mappable[kids];
+      int count = 0;
+      for (int i = 0; i < kids; i++) {
+        String colorString =  "";
+        NodeElement newItem = new Node(this, content.getChild(i), content.getChild(i).getInt("level"), count);
+        items[count++] = newItem;
+        size += newItem.getSize();
+      }
+      if (count != items.length) {
+        items = (Mappable[]) subset(items, 0, count);
+      }
+    } else {
+      // If no items found in this folder, create a dummy array so that 
+      // items will not be null, which will ensure that items.length will
+      // return 0 rather than causing a NullPointerException.
+      items = new Mappable[0];
+    }
+  }
+
+  void updateColors() {
+    super.updateColors();
+
+    for (int i = 0; i < items.length; i++) {
+      NodeElement fi = (NodeElement) items[i];
+      fi.updateColors();
+    }
+  }
+
+  void checkLayout() {
+    if (!layoutValid) {
+      if (getItemCount() != 0) {
+        algorithm.layout(this, bounds);
+      }
+      layoutValid = true;
+    }
+  }
+
+
+  boolean mousePressed() {
+    if (mouseInside()) {
+      if (contentsVisible) {
+        // Pass the mouse press to the child items
+        for (int i = 0; i < items.length; i++) {
+          NodeElement fi = (NodeElement) items[i];
+          if (fi.mousePressed()) {
+            return true;
+          }
+        }
+      } else {  // not opened
+        if (mouseButton == LEFT) {
+          if (parent == zoomItem) {
+            showContents();
+          } else {
+            parent.zoomIn();
+          }            
+        } else if (mouseButton == RIGHT) {
+          if (parent == zoomItem) {
+            parent.zoomOut();
+          } else {
+            parent.hideContents();
+          }
+        }
+        return true;
+      }
+    }
+    return false;
+  }
+
+
+  // Zoom to the parent's boundary, zooming out from this item
+  void zoomOut() {
+    if (parent != null) {
+      // Close contents of any opened children
+      for (int i = 0; i < items.length; i++) {
+        if (items[i] instanceof Node) {
+          ((Node)items[i]).hideContents();
+        }
+      }
+      parent.zoomIn();
+    }
+  }
+
+
+  void zoomIn() {
+    zoomItem = this;
+    zoomBounds.target(x, y, w, h); ///width, h/height);
+  }
+
+
+  void showContents() {
+    contentsVisible = true;
+  }
+
+
+  void hideContents() {
+    // Prevent the user from closing the root level
+    if (parent != null) {
+      contentsVisible = false;
+    }
+  }
+
+  
+  void draw() {
+    checkLayout();
+    calcBox();
+    
+    if (contentsVisible) {
+      for (int i = 0; i < items.length; i++) {
+        items[i].draw();
+      }
+    } else {
+      super.draw();
+    }
+
+    if (contentsVisible) {
+      if (mouseInside()) {
+        if (parent == zoomItem) {
+          taggedItem = this;
+        }
+      }
+    }
+    if (mouseInside()) {
+      darkness *= 0.05;
+    } else {
+      darkness += (150 - darkness) * 0.05;
+    }
+    if (parent == zoomItem) {
+      colorMode(RGB, 255);
+      fill(0, darkness);
+      rect(boxLeft, boxTop, boxRight, boxBottom);
+    }
+  }
+
+
+  void drawTitle() {
+    if (!contentsVisible) {
+      super.drawTitle();
+    }
+  }
+
+
+  void drawTag() {
+    float boxHeight = textAscent() + textPadding*2;
+
+    if (boxBottom - boxTop > boxHeight*2) {
+      // if the height of the box is at least twice the height of the tag,
+      // draw the tag inside the box itself
+      fill(0, 128);
+      rect(boxLeft, boxTop, boxRight, boxTop+boxHeight);
+      fill(255);
+      textAlign(LEFT, TOP);
+      text(name, boxLeft+textPadding, boxTop+textPadding);
+
+    } else if (boxTop > boxHeight) {
+      // if there's enough room to draw above, draw it there
+      fill(0, 128);
+      rect(boxLeft, boxTop-boxHeight, boxRight, boxTop);
+      fill(255);
+      text(name, boxLeft+textPadding, boxTop-textPadding);
+
+    } else if (boxBottom + boxHeight < height) {
+      // otherwise draw the tag below
+      fill(0, 128);
+      rect(boxLeft, boxBottom, boxRight, boxBottom+boxHeight);
+      fill(255);
+      textAlign(LEFT, TOP);
+      text(name, boxLeft+textPadding, boxBottom+textPadding);
+    }
+  }
+
+
+  Mappable[] getItems() {
+    return items;
+  }
+
+
+  int getItemCount() {
+    return items.length;
+  }
+}

File src/treemap/NodeElement.pde

+/* Code heavily inspired/borrowed from Ben Fry's original code example */ 
+/* By Thejesh GN  */
+
+class NodeElement extends SimpleMapItem {
+  Node parent;    
+  //File file;
+    String file;
+  String name;
+  int level;
+  
+  color c;
+  float hue;
+  float brightness;
+    
+  float textPadding = 8;
+    
+  float boxLeft, boxTop;
+  float boxRight, boxBottom;
+
+
+  NodeElement(Node parent, XMLElement content, int order) {
+    this.parent = parent;
+    this.file = content.getString("name");
+    this.order = order;
+    this.level = content.getInt("level");
+    String cString = content.getString("color");
+    String[] list = split(cString, ','); 
+    this.c = color(Integer.parseInt(list[0]),Integer.parseInt(list[1]),Integer.parseInt(list[2]));
+    println("color = "+c);
+      
+    name = file.toString();
+    size =  random(1, 150);
+
+   // modTimes.add(file.lastModified());
+   long a = int(random(10000,200000));
+    modTimes.add(a);
+  }
+
+  
+  void updateColors() {
+    if (parent != null) {
+      hue = map(order, 0, parent.getItemCount(), 0, 360);
+    }
+    //brightness = modTimes.percentile(file.lastModified()) * 100;
+     long a = int(random(100,200));
+    brightness = modTimes.percentile(a) * 100;
+
+    colorMode(HSB, 360, 100, 100);
+    if (parent == zoomItem) {
+     // c = color(hue, 80, 80);
+        c = color(int(random(0,255)),int(random(0,255)),int(random(0,255)));
+       // c = this.c;
+    } else if (parent != null) {
+        c = color(int(random(0,255)),int(random(0,255)),int(random(0,255)));
+     // c = color(parent.hue, 80, brightness);
+     //c = parent.c;
+    }
+    colorMode(RGB, 255);
+  }
+  
+  
+  void calcBox() {
+    boxLeft = zoomBounds.spanX(x, 0, width);
+    boxRight = zoomBounds.spanX(x+w, 0, width);
+    boxTop = zoomBounds.spanY(y, 0, height);
+    boxBottom = zoomBounds.spanY(y+h, 0, height);
+  }
+
+
+  void draw() {
+    calcBox();
+
+    fill(c);
+    rect(boxLeft, boxTop, boxRight, boxBottom);
+
+    if (textFits()) {
+      drawTitle();
+    } else if (mouseInside()) {
+      rolloverItem = this;
+    }
+   }
+    
+    
+  void drawTitle() {
+    fill(255, 200);
+    
+    float middleX = (boxLeft + boxRight) / 2;
+    float middleY = (boxTop + boxBottom) / 2;
+    if (middleX > 0 && middleX < width && middleY > 0 && middleY < height) {
+      if (boxLeft + textWidth(name) + textPadding*2 > width) {
+        textAlign(RIGHT);
+        text(name, width - textPadding, boxBottom - textPadding);
+      } else {
+        textAlign(LEFT);
+        text(name, boxLeft + textPadding, boxBottom - textPadding);
+      }
+    }
+  }
+
+
+  boolean textFits() {
+    float wide = textWidth(name) + textPadding*2;
+    float high = textAscent() + textDescent() + textPadding*2;
+    return (boxRight - boxLeft > wide) && (boxBottom - boxTop > high); 
+  }
+    
+ 
+  boolean mouseInside() {
+    return (mouseX > boxLeft && mouseX < boxRight && 
+            mouseY > boxTop && mouseY < boxBottom);    
+  }
+
+
+  boolean mousePressed() {
+    if (mouseInside()) {
+      if (mouseButton == LEFT) {
+        parent.zoomIn();
+        return true;
+
+      } else if (mouseButton == RIGHT) {
+        if (parent == zoomItem) {
+          parent.zoomOut();
+        } else {
+          parent.hideContents();
+        }
+        return true;
+      }
+    }
+    return false;
+  }
+}

File src/treemap/RankedLongArray.pde

+// Code from Visualizing Data, First Edition, Copyright 2008 Ben Fry.
+
+
+class RankedLongArray {
+  long[] values = new long[100];
+  int count;
+  boolean dirty;
+
+  public void add(long what) {
+    if (count == values.length) {
+      values = (long[]) expand(values);
+    }
+    values[count++] = what;
+    dirty = true;
+  }
+
+  public void remove(long what) {
+    int index = find(what, 0, count-1);
+    arraycopy(values, index+1, values, index, count-index-1);
+    count--;
+  }
+
+  private void update() {
+    Arrays.sort(values, 0, count);
+    dirty = false;
+  }
+
+  public float percentile(long what) {
+    int index = find(what);
+    return index / (float)count;
+  }
+
+  public int find(long what) {
+    return find(what, 0, count-1);
+  }
+
+  private int find(long num, int start, int stop) {
+    if (dirty) update();
+      
+    int middle = (start + stop) / 2;
+
+    // if this is the char, then return it
+    if (num == values[middle]) return middle;
+
+    // doesn't exist, otherwise would have been the middle
+    if (start >= stop) return -1;
+
+    // if it's in the lower half, continue searching that
+    if (num < values[middle]) {
+      return find(num, start, middle-1);
+    }
+    // otherwise continue in the upper half
+    return find(num, middle+1, stop);
+  }
+}

File src/treemap/data/tree.xml

+<tree name="BribePatterns" level="0" color="100,200,300">
+<node level="1" name="Bangalore" value="100" color="100,200,300" >
+	<node level="2" name="Police" value="10" color="100,200,300">
+	</node>
+	<node level="2" name="Revenue" value="20" color="150,240,300">
+	</node>
+</node>
+<node level="1" name="Mysore" value="20" color="140,210,300" >
+	<node level="2" name="Police" value="10" color="100,200,300">
+	</node>
+	<node level="2" name="Revenue" value="20" color="200,200,100">
+	</node>
+</node>
+
+</tree>

File src/treemap/treemap.pde

+/* Code heavily inspired/borrowed from Ben Fry's original code example */ 
+/* By Thejesh GN  */
+
+import treemap.*;
+
+Node rootItem;
+NodeElement rolloverItem;
+Node taggedItem;
+
+BoundsIntegrator zoomBounds;
+Node zoomItem;
+
+RankedLongArray modTimes = new RankedLongArray();
+
+PFont font;
+XMLElement xml;
+
+void setup() {
+    size(500, 500);
+    zoomBounds = new BoundsIntegrator(0, 0, width, height);
+    
+    cursor(CROSS);
+    rectMode(CORNERS);
+    smooth();
+    noStroke();
+  
+   font = createFont("SansSerif", 13);
+   xml = new XMLElement(this, "tree.xml");
+   String title =  xml.getString("name");
+   print(title);
+   setRoot(xml);
+}
+
+  
+void setRoot(XMLElement content) {
+  println("Root is set");
+  color c = #233456;
+  Node tm = new Node(null, content,  0, 0);
+  tm.setBounds(0, 0, width, height);
+  tm.contentsVisible = true;
+    
+  rootItem = tm;
+  rootItem.zoomIn();
+  rootItem.updateColors();
+}
+
+
+void draw() {
+      background(0);
+      textFont(font);
+      
+      frameRate(30);
+      zoomBounds.update();
+    
+      rolloverItem = null;
+      taggedItem = null;
+    
+      if (rootItem != null) {
+        rootItem.draw();
+      }
+      if (rolloverItem != null) {
+        rolloverItem.drawTitle();
+      }
+      if (taggedItem != null) {
+        taggedItem.drawTag();
+      }
+}
+
+
+void mousePressed() {
+    if (zoomItem != null) {
+      zoomItem.mousePressed();
+    }
+}
+