static final int CODE = 0; static final int X = 1; static final int Y = 2; static final int NAME = 3; int totalCount; int placeCount; Place[] places; float minX,maxX; float minY,maxY; float mapX1,mapY1; float mapX2,mapY2; color backgroundColor = #333333; color dormantColor = #999966; color highlightColor = #CBCBCB; color unhighlightColor = #66664C; color badColor = #FFFF66; PFont font; String typedString = ""; char typedChars[] = new char[5]; int typedCount; int typedPartials[] = new int[6]; float messageX,messageY; int foundCount; Place chosen; ColorIntegrator faders[]; //Zoom boolean zoomEnabled = false; Integrator zoomDepth = new Integrator(); Integrator zoomX1; Integrator zoomY1; Integrator zoomX2; Integrator zoomY2; float targetX1[] = new float[6]; float targetY1[] = new float[6]; float targetX2[] = new float[6]; float targetY2[] = new float[6]; float boundsX1, boundsY1; float boundsX2, boundsY2; public void setup() { size(720,453,P3D); rectMode(CENTER); ellipseMode(CENTER); mapX1 = 30; mapY1 = 20; mapX2 = width - mapX1; mapY2 = height - mapY1; readData(); font = loadFont("Silom-14.vlw"); textFont(font); textMode(SCREEN); messageX = 40; messageY = height - messageX; faders = new ColorIntegrator[6]; faders[0] = new ColorIntegrator(unhighlightColor); faders[0].setAttraction(0.5); faders[0].target(dormantColor); for (int i = 1;i<6;i++) { faders[i] = new ColorIntegrator(unhighlightColor); faders[i].setAttraction(0.5); faders[i].target(highlightColor); } zoomX1 = new Integrator(minX); zoomY1 = new Integrator(minY); zoomX2 = new Integrator(maxX); zoomY2 = new Integrator(maxY); targetX1[0] = minX; targetY1[0] = minY; targetX2[0] = maxX; targetY2[0] = maxY; frameRate(15); } void updateAnimation() { for (int i = 0;i<6;i++) { faders[i].update(); } if (foundCount > 0) { zoomDepth.target(typedCount); } else { zoomDepth.target(typedCount - 1); } zoomDepth.update(); zoomX1.update(); zoomY1.update(); zoomX2.update(); zoomY2.update(); } void parseInfo(String line) { String infoString = line.substring(2); //remove the "#" String[] infoPieces = split(infoString,','); totalCount = int(infoPieces[0]); minX = float(infoPieces[1]); maxX = float(infoPieces[2]); minY = float(infoPieces[3]); maxY = float(infoPieces[4]); } Place parsePlace(String line) { String[] pieces = split(line, TAB); int zip = int(pieces[CODE]); float x = float(pieces[X]); float y = float(pieces[Y]); String name = pieces[NAME]; return new Place(zip, name, x, y); } void readData() { String[] lines = loadStrings("zips.tsv"); parseInfo(lines[0]); places = new Place[totalCount]; for (int i = 1 ; i < lines.length; i++) { places[placeCount] = parsePlace(lines[i]); placeCount++; } } public void draw() { updateAnimation(); background(backgroundColor); for(int i = 0;i 0) { if (!zoomEnabled && typedCount == 4) { for (int i = 0; i< placeCount;i++) { if (places[i].matchDepth == typedCount) { places[i].draw(); } } } if (chosen != null) { chosen.drawChosen(); } fill(highlightColor); textAlign(LEFT); text(typedString, messageX,messageY); } else { fill(badColor); text(typedString, messageX,messageY); } } //zoom textAlign(RIGHT); fill(zoomEnabled ? highlightColor : unhighlightColor); text("zoom", width - 40 , height - 40); textAlign(LEFT); } float TX(float x) { return zoomEnabled ? map(x, zoomX1.value, zoomX2.value, mapX1, mapX2) : map(x,minX,maxX,mapX1,mapX2); } float TY(float y) { return zoomEnabled ? map(y, zoomY1.value, zoomY2.value, mapY2, mapY1) : map(y,minY,maxY,mapY2,mapY1); } void keyPressed() { if ((key == BACKSPACE) || (key == DELETE)) { if (typedCount > 0) { typedCount--; } updateTyped(); } else if ((key >= '0') && (key <= '9')) { if (typedCount != 5) { if (foundCount > 0) { typedChars[typedCount++] = key; } } } updateTyped(); } void updateTyped() { typedString = new String(typedChars,0,typedCount); if (typedCount == 0) { faders[0].target(dormantColor); } else { for (int i = 0; i < typedCount; i++) { faders[i].target(unhighlightColor); } for (int i = typedCount; i < 6; i++) { faders[i].target(highlightColor); } } typedPartials[typedCount] = int(typedString); for (int j = typedCount - 1;j>0;j--) { typedPartials[j] = typedPartials[j+1] / 10; } foundCount = 0; chosen = null; //zoom boundsX1 = maxX; boundsY1 = maxY; boundsX2 = minX; boundsY2 = minY; for (int i = 0; i < placeCount; i++) { places[i].check(); } calcZoom(); } void mousePressed() { if ((mouseX > width - 100) && (mouseY > height - 50)) { zoomEnabled = !zoomEnabled; } } void calcZoom() { if (foundCount != 0) { float spanX = boundsX2 - boundsX1; float spanY = boundsY2 - boundsY1; float midX = (boundsX1 + boundsX2) / 2; float midY = (boundsY1 + boundsY2) / 2; if ((spanX != 0) && (spanY != 0)) { float screenAspect = width / float(height); float spanAspect = spanX / spanY; if (spanAspect > screenAspect) { spanY = (spanX / width) * height; } else { spanX = (spanY / height) * width; } } else //if span is zero { spanX = targetX2[typedCount - 1] - targetX1[typedCount - 1]; spanY = targetY2[typedCount - 1] - targetY1[typedCount - 1]; } targetX1[typedCount] = midX - spanX/2; targetY1[typedCount] = midY - spanY/2; targetX2[typedCount] = midX + spanX/2; targetY2[typedCount] = midY + spanY/2; } else if (typedCount != 0) //no found at this level, zoom to previous level { targetX1[typedCount] = targetX1[typedCount - 1]; targetY1[typedCount] = targetY1[typedCount - 1]; targetX2[typedCount] = targetX2[typedCount - 1]; targetY2[typedCount] = targetY2[typedCount - 1]; } zoomX1.target(targetX1[typedCount]); zoomY1.target(targetY1[typedCount]); zoomX2.target(targetX2[typedCount]); zoomY2.target(targetY2[typedCount]); if (!zoomEnabled) { zoomX1.set(zoomX1.target); zoomY1.set(zoomY1.target); zoomX2.set(zoomX2.target); zoomY2.set(zoomY2.target); } }