Assignment 2

The goal is to make your visualization of French towns interactive by letting users filter cities and display city names.

You will first do a 40 min lab work where you will start going through the steps below and will have the opportunity to ask questions.

Prerequisites

At this point, you should normally have a visualization of French cities, where every city is represented as a dot, circle or any other shape. The storage of city information (name, population, etc.) and the city drawing code should normally be handled by a different class (named, e.g., Place), declared in a separate Processing file. See slides from the previous lab work.

Now just follow the steps below. Test your application after each step. If you feel confident with Processing, you can skip the detailed instructions and try to directly implement the Effect to achieve.

Step 1: filtering out small cities

Effect to achieve: only the largest cities are displayed, according to a population cutoff value defined in the code and displayed on the screen.

  • In your main program file, declare a new variable minPopulationToDisplay and set it to a value like 10000.
  • Modify the drawing code so that all cities below that value are not displayed.
  • Use the text() function to display the following text: "Displaying populations above X" on the top of the app window, where X is the population cutoff.

Step 2: making filtering interactive

Effect to achieve: users can interactively change the population cut-off using the keyboard.

  • Declare the function keyPressed() in your main program file
  • Read the variables key or keyCode to figure out which key has been pressed and update the population cutoff accordingly.
    • Tip: change the population cutoff by multiplying/dividing it by a constant rather than incrementing/decrementing it.
  • Call redraw() at the end of the function.

Step 3: listening to mouse motion

Effect to achieve: as the user moves the mouse, its x, y coordinates are displayed in the console.

  • In your main program file, declare the function mouseMoved().
  • Print the coordinates of the mouse (variables mouseX and mouseY) in the Processing console using println().

Step 4: implementing geometric picking

Effect to achieve: as the user moves the mouse, the name of the city under the mouse cursor is displayed in the console.

  • Add a method boolean contains(int px, int py) to the class Place that returns whether a point expressed in window coordinates is contained in the displayed shape. You will have to be consistent with the draw() method:
class Place {

  ...

  // Let's assume this is the drawing function you already have
  void draw() {    
    ...    
    // Draws the city as a circle, assuming its radius has been already computed.
    ellipse(mapX(x), mapY(y), radius*2, radius*2);
    ...
  }

  // This is the corresponding hit test function
  boolean contains(int px, int py) {
    // Since we draw a circle, we use here the distance between (px, py) and the circle's center.
    // We add an extra pixel to facilitate mouse picking.
    return dist(mapX(x), mapY(y), px, py) <= radius + 1;
  }
}
  • In your main program file, add a method Place pick(int px, int py) that returns the Place object below the given point. In case of multiple overlapping places, return the one which is drawn last. If there is no place, return null.
    • Tip: iterate over cities in reverse order to get the place that is drawn last.
  • In the mouseMoved() function, display in the Processing console the name of the city located below the mouse cursor.
  • Test the program, then modify the code such that the name of cities hovered by the mouse cursor are printed only once. For this, use a global variable to remember the last picked city.

Step 5: adding mouse-over highlighting

Effect to achieve: as the user moves the mouse, the city under the mouse cursor is visually highlighted.

  • Add a boolean variable highlighted to your Place class.
  • Modify its draw() function such that the color of the city is different when this variable is true. If you already use color as a visual variable, try a different highlighting effect (e.g., displaying an additional circle, changing the alpha value of the color or using darker colors. See here about transparency and there there on mixing colors).
  • In the mouseMoved() function of the main program, update the highlighted status of the place under the mouse cursor and of the previously picked place. Don't forget to call the redraw() method.

Step 6: revealing city names

Effect to achieve: as the user moves the mouse, the name of the city under the mouse cursor is displayed.

  • Modify the draw() function of your class Place such that the name of the city is displayed to the right of the city when highlighted is true. Test the program multiple times until the text is properly aligned.
  • Display a translucent rectangle below the text to make it easier to read.
    • Tip: You can set the rectangle's height manually and use textWidth() to compute its width.

Further (optional) steps

  • Add a selected boolean flag to the class Place that is toggled on mouse press and displays the city name with a different color.
  • Add a widget to the top of the window that shows the population range like an inverted progress bar.
    • Tip: use a log scale or a power scale.
  • Make this widget responsive to mouse drags.

For Processing gurus

  • Turn the population widget above into a range slider.
  • Show the distribution of cities inside the range slider, using either a histogram or a color map.
  • Use excentric labelling to show labels of overlapping cities.
  • Add support for pan and zoom.

Last step: sharing your application

Remember you will have to put your application on the Web. See instructions in the assignments page.

License

You can reuse this content for your class if you acknowledge us (Petra Isenberg, Jean-Daniel Fekete, Pierre Dragicevic and Frédéric Vernier):