cs106a – Assignment #6 – Extra Task #3

The complete specification of assignment #6 can be found as part of the stream at iTunes.

Try to minimize the overprinting problem

If the popularity of a name is improving slowly, the graph for that name will cross the label for that point making it harder to read. You could reduce this problem by positioning the label more intelligently. If a name were increasing in popularity, you could display the label below the point; conversely, for names that are falling in popularity, you could place the label above the point. An even more challenging task is to try to reduce the problem of having labels for different names collide, as they do for Sam and Samantha.

For the first task – moving the label below the graph if is ascending – the label drawing class needs more information about the graph thus it is better to provide the complete entry instead of the name and rank only:

	private void drawEntry(NameSurferEntry entry) {
		...
		drawLabel(entry, 0, x0, y0);
		...
		for (int i = 1; i < NDECADES; i++) {
		...
			drawLabel(entry, i, x0, y0);
		...
		}
	}

After creating the label check if the next rank is higher or lower as the current one, and move the label accordingly:

	private void drawLabel(NameSurferEntry entry, int index, double x, double y) {
		String name = entry.getName();
		int rank = entry.getRank(index);
		...
		GLabel label = new GLabel(text, x + LABEL_OFFSET, y - LABEL_OFFSET);
		int nextRank = entry.getRank(index + 1); 
		double labelHeight = label.getHeight() + LABEL_OFFSET;
		if ((rank > nextRank) && (nextRank != 0)) {
			label.move(0, labelHeight + LABEL_OFFSET);
		}
		...
	}

To check if the label collides with another one, check the upper and lower corners of the new label, there is no other label, do nothing (0). If the bottom is blocked move it up (-1), otherwise move it down (1):

	private int labelCollission(GLabel label) {
		double x = label.getX();
		double y = label.getY();
		GObject object;
		boolean bottomBlocked = false;
		boolean topBlocked = false;

		object = getElementAt(x, y);
		if ((object != null) && (object instanceof GLabel)) bottomBlocked = true;
		object = getElementAt(x, y - label.getAscent());
		if ((object != null) && (object instanceof GLabel)) topBlocked = true;
		if (!topBlocked) {
			if (!bottomBlocked) return 0;
			return -1;
		}
		if (!bottomBlocked) return 1;
		return -1; 
	}

If there are too many labels on screen, or if fewer are in “unlucky” positions, this simple algorithm might go haywire. Thus its necessary to limit the number of trials:

	private void drawLabel(NameSurferEntry entry, int index, double x, double y) {
		...
		for (int i = 0; i < MAX_LABEL_SHIFTS; i++) {
			int dy = labelCollission(label);
			if (dy == 0) break;
			label.move(0, dy * labelHeight);
		}		
		...
	}

The code for this assignment is available on github.

FacebooktwitterredditpinterestlinkedintumblrmailFacebooktwitterredditpinterestlinkedintumblrmail

Leave a Reply

Your email address will not be published.