Assignment 4: The Bigger Picture

Now for our last iteration of our Real Estate Manageement system: an improved implementation of our project from Assignment 3, focusing on a visual representation of output rather than text based. This is important, as it allows us to display that same information more succinctly, and in a fashion that should allow more users to readily understand the context of their search results. In this assignment, we're going to be focusing on mouse and keyboard events, to allow for more dynamic means of user interaction. We're also going to be doing quite a bit of work with graphics. Additionally, I won't be sharing screenshots from my solution, in an effort to get everyone to flex their creativity with tackling the design approach of this project as well.

Google Maps or other online map software, will be an excellent guideline for our design requirements. We will ignore some features, such as green/blue "blobs" denoting nature/water areas, width of roads that reflects the number of lanes available, exit/enter ramp connectors, and obviously, street view. Instead, we are going to focus on creating a map representation of our DeKalb/Sycamore Communities, complete with lines drawn for our streets, street names laid atop those lines, markers for our various schools and businesses, and mouse hover functionality to display additional information. Our map will not be statically drawn, either, but instead allow for the users to zoom in/out, and drag the map view around — not too dissimilar from how we expect to be able to interact with maps ourselves. Because of the zoom functionality, we will need to always ensure a scale is displayed that helps the user understand the truth of the distances being represented.

From Assignment 3, we're only going to omit Query 5. The other four will see carry over into what we're intending on doing with this assignment. I'm also going to complicate this part of the assignment by limiting us to exactly one "Query" or "Search" button ("Search" would be the better label to choose, if we're intending on this being used by the general public), which can also be triggered by the user hitting the Enter key. This means that:

  1. Using Query 1 by itself will filter results exactly as we did before.
  2. Adding Query 2 will limit those results above by those residences only within distance of a school.
  3. Query 3's "For-Sale Residence" ComboBox can now include (1) all for-sale residences by default (as was done before) but now also (2) only list the for-sale residences selected by the previous query/queries. Adding this query will display those resulting business within range of the specified for-sale residence, without substracting from previously displayed results.
  4. Query 4 simply adds another layer of filtering.
While this may seem excessive to implement, it's important to note that the from clause we've been using on data sources like allProperties or allPeople can be applied to the data source returned from LINQ queries. For example:

var Result1 = /* stuff and things */ select N;
var Result2 = from N in Result1 /* stuff and things */ select N;

Would effectively "chain" your LINQ queries together, as necessary.

So let's talk about the map. For simplicities' sake, you'll want your map to be drawn to a minimum 500x250 "canvas", since DeKalb and Sycamore have been previously established to be horizontally adjacent to each other. With DeKalb at X = 0 and Sycamore at X = 250. You're welcome to use different dimensions as you feel would better enhance the user experience, such as a 250x250 map (wherein you divide the X-coordinate value of each Property by 2), or some (500 * a)x(250 * b) dimension, with the mathematically necessary scaling done to correctly place your properties relative to each other.

The list of Properties will give us hints as to where to draw streets and in more than once instance, how to draw them. For example, if every Property on Slacker Rd. has an X-coordinate of 13, we would draw a vertical line from (13, 0) to (13, CANVAS_HEIGHT), and slap a Slacker Rd. label on there. There's a method from the Graphics class that lets you draw strings in arbitarily defined locations — even a way to display them going left-to-right (default) or bottom-to-top, for our vertically drawn streets. Oh, and for horizontally-orientated streets, don't just go from (0, Y) to (CANVAS_WIDTH, Y). Instead, don't cross over the X = 250 divide that separates the two Communities.

Sometimes, though, Properties from a single street won't all share a single X- or Y-coordinate, indicating some curve (hint hint) that must be drawn to represent this street. When it comes to putting labels on these streets, don't stress too much about curving the label — I wouldn't even know how to do this myself — or where exactly to place the horizontal/vertical label. As long as it appears reasonably close to the steet being drawn, you'll be golden.

For map markers, there are two approaches you can take to this: you can use an established set of rules to define markers that are Residences, Businesses or Schools — easiest to define these rules using a Map Legend. You could also consider using more informative icons for your markers, that have their definition more-or-less built into their image. Such as the Home icon and Graduation icon. In either case, you want to add text labels for each School and Business, ideally in different (yet both distinguishable against your desired background) colors. Finally, you will need to address the functionality of detecting when the mouse hovers over any of the displayed Properties (of any type) and displays more information, similar to the text output we would see from Assignment 3. Ideally, doing this doesn't intrude on the main Form's focus (i.e. don't use a MessageBox), so you might look into how to utilize ToolTips to achieve this functionality. You could simply dump this output to a statically defined text box on your Form, but this would occupy valuable real estate, as well as distract from the map.

Additionally, some Schools and Businesses are located on their own streets, without sharing the street with any other Property. In instances such as these, simply ignore drawing a street altogether. We'll still be able to view the address of the Property by the map marker it will occupy.

Let's go back to the map now. The first functionality to address is zooming in/out. At a minimum, you should be able to do a 100%/125%/150%/175% view of the map, although you may have (1) more levels of zoom for smoother gradients or (2) slightly different values of zoom, depending on what you feel makes the map functionality most useful. This should be activated by two differet user inputs (because more is usually better): a TrackBar of sorts (only because it would be best to see the -/+ symbols on either end, to help represent zoom direction), and by detecting notches on the mouse (known as Delta (second to last paragraph) in C#). When responding to Delta, you obviously should not allow more/less zoom than the maximum/minimum values you define. Additionally, you should have a distance scale in the bottom-left corner of the map that indicates how many units of distance is covered by some appreciable amount. Something like |----|----|, with 5 and 10 labels underneath the second and third ticks, and where the scale stretches the more you zoom in.

The second functionality to address is moving the map. First and foremost: this should be disabled or have no noticable affect when the map is at 100% or less zoom. Since at these levels, you should be able to see everything at once. As you should expect, this functionality is achieved by holding down the mouse in one location, dragging it in the intended direction you'd like to move the focus, then releasing the mouse to re-draw the map. The magnitude of the map's movement should be proportionate to the distance the mouse travelled between being held down and released. So if my canvas is 500x250 and my zoom is 200%, a mouse distance of 10 should move the map by 20. Now, the user may never move the mouse in perfectly straight lines — obviously. So you'll need to calculate both the X and Y coordinate displacement for the map focus. (I keep using this term "map focus" without formally explaining it: it's the center of your canvas) Additionally, you'll want to avoid adjustments of your map focus that would cause the edges of your canvas to be "blank" — to phrase this differently, you'll want to avoid situations where the corner of your map is in the middle of the canvas, leaving an undefined area covering 3/4 of the canvas.

Input Files

I simply added some more residences to help flesh out your maps, as well as introduce streets that now curve.

DeKalb
Sycamore