// // pollcalc.java // // Created by Drew Thaler on Sat Oct 09 2004. // This source code is released into the public domain. // import java.awt.*; import java.awt.event.*; import java.awt.font.*; import java.awt.geom.*; import java.applet.*; import java.io.*; import java.lang.reflect.*; import java.net.*; import java.util.*; class GraphicsShim { private Graphics g; public GraphicsShim(Graphics inGraphics) { g = inGraphics; } public void enableAntialiasing() { Graphics2D g2d = (Graphics2D)g; g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); } public void setStrokeWidth(float width) { Graphics2D g2d = (Graphics2D)g; g2d.setStroke(new BasicStroke(width)); } } class StateInfo extends Object { public String name; public String abbr; public int EV; public int[] positions; public double[] confidence; public Polygon poly; public int labelx; public int labely; public StateInfo(String inName, String inAbbr, int inEV, int inPos, int[] xcoords, int[] ycoords, int[] inLabelCoords) { name = inName; abbr = inAbbr; EV = inEV; positions = new int[3]; confidence = new double[3]; positions[0] = positions[1] = positions[2] = inPos; confidence[0] = confidence[1] = confidence[2] = 1.0; poly = new Polygon(xcoords,ycoords,xcoords.length); labelx = inLabelCoords[0]; labely = inLabelCoords[1]; } } public class pollcalc extends Applet implements ItemListener { // We have three different display modes. private static final int DISPLAY_POLLS = 0, DISPLAY_LAST_ELECTION = 1, DISPLAY_CUSTOM = 2; private int mode = DISPLAY_POLLS; // Candidate names final String demCandidate = "Kerry"; final String gopCandidate = "Bush"; // Popup menu to switch between modes. private PopupMenu appletMenu; private CheckboxMenuItem[] menuItems = { new CheckboxMenuItem("Current projection", false), new CheckboxMenuItem("Results from 2000", false), new CheckboxMenuItem("Custom view", false) }; // Numbers indicating positions private static final int DEM = 0, TOSSUP = 1, GOP = 2, TOTAL_POSITIONS = 3; // Colors for each of the positions private Color[] colors = { new Color(0x3030FF), new Color(0xFFFFFF), new Color(0xFF3030) }; // Preferred applet width and height private static final int HEIGHT = 420, WIDTH = 550; // Double-buffer for cleaner updates private Image offscreen; private boolean updateOffscreenImage; // Mouse tracking private boolean mouseInside; private int mouseOverState; private Component stateDetail; // X,Y coordinates of the 50 states + DC final int[] xAL={299,310,310,336,328,299}; final int[] yAL={300,300,297,297,257,257}; final int[] xAK={ 68, 76, 92, 89, 71}; final int[] yAK={320,323,317,299,299}; final int[] xAZ={114,142,142,117,114}; final int[] yAZ={232,242,196,191,195}; final int[] xAR={243,269,272,275,265,235,241}; final int[] yAR={260,261,254,240,232,232,252}; final int[] xCA={ 39,114,114, 96, 98, 23, 9, 19}; final int[] yCA={236,232,195,168,154,132,176,213}; final int[] xCO={142,163,180,180,180,144}; final int[] yCO={196,198,200,179,165,165}; final int[] xCT={465,499,491,459}; final int[] yCT={148,127, 99,107}; final int[] xDE={439,456,458,439,427}; final int[] yDE={219,219,211,192,173}; final int[] xDC={386,402,417,402}; final int[] yDC={198,213,198,183}; final int[] xFL={310,335,353,365,372,421,427,394,336,310}; final int[] yFL={300,306,303,306,357,405,363,300,297,297}; final int[] xGA={336,394,395,360,337,328}; final int[] yGA={297,300,294,257,257,257}; final int[] xHI={179,199,180,168}; final int[] yHI={352,333,312,320}; final int[] xID={110,120,135,137,130,128,118,114}; final int[] yID={157,159,162,146,144,130,128,139}; final int[] xIL={278,288,292,290,285,255,237}; final int[] yIL={237,228,205,149,143,145,174}; final int[] xIN={288,308,320,309,293,290,292}; final int[] yIN={228,221,206,146,148,149,205}; final int[] xIA={209,237,255,252,202,202}; final int[] yIA={174,174,145,143,152,157}; final int[] xKS={180,230,230,211,180}; final int[] yKS={200,202,196,179,179}; final int[] xKY={278,339,351,345,320,308,288}; final int[] yKY={237,233,218,209,206,221,228}; final int[] xLA={245,281,292,287,265,271,269,243}; final int[] yLA={297,309,302,287,287,271,261,260}; final int[] xME={483,495,482,474,471}; final int[] yME={ 65, 40, 19, 20, 33}; final int[] xMD={375,385,402,417,402,434,456,439,427,372}; final int[] yMD={189,180,183,198,213,233,219,219,173,177}; final int[] xMA={459,491,515,523,539,483,458,450}; final int[] yMA={107, 99, 98,112,111, 65, 75, 75}; final int[] xMI={293,309,339,348,344,336,337,309,245,281,309,292,297}; final int[] yMI={148,146,140,130,115,119,100, 87,100,106, 87,114,135}; final int[] xMN={202,252,240,245,196,201}; final int[] yMN={152,143,130,100,129,143}; final int[] xMS={265,287,292,299,299,272,269,271}; final int[] yMS={287,287,302,300,257,254,261,271}; final int[] xMO={235,265,275,278,237,209,211,230,230}; final int[] yMO={232,232,240,237,174,174,179,196,202}; final int[] xMT={130,137,161,163,163,128}; final int[] yMT={144,146,147,145,135,130}; final int[] xNE={161,180,180,211,209,202,161}; final int[] yNE={165,165,179,179,174,157,157}; final int[] xNV={114,117,120,110, 98, 96}; final int[] yNV={195,191,159,157,154,168}; final int[] xNH={458,483,471,462}; final int[] yNH={ 75, 65, 33, 40}; final int[] xNJ={427,439,458,470,465,427,427,435}; final int[] yNJ={173,192,211,185,148,131,152,163}; final int[] xNM={142,149,160,163,163,142}; final int[] yNM={242,235,235,202,198,196}; final int[] xNY={360,415,427,465,459,450,442,410,401,377}; final int[] yNY={127,117,131,148,107, 75, 46, 56, 90, 98}; final int[] xNC={337,360,387,420,437,434,366}; final int[] yNC={257,257,252,268,253,233,233}; final int[] xND={163,201,196,163}; final int[] yND={145,143,129,135}; final int[] xOH={320,345,368,360,339,309}; final int[] yOH={206,209,177,127,140,146}; final int[] xOK={163,209,209,241,235,230,180,163}; final int[] yOK={202,206,246,252,232,202,200,198}; final int[] xOR={ 23, 98,110,114, 25}; final int[] yOR={132,154,157,139,127}; final int[] xPA={368,372,427,435,427,427,415,360}; final int[] yPA={177,177,173,163,152,131,117,127}; final int[] xRI={499,523,515,491}; final int[] yRI={127,112, 98, 99}; final int[] xSC={395,420,387,360}; final int[] ySC={294,268,252,257}; final int[] xSD={161,202,202,201,163,161}; final int[] ySD={157,157,152,143,145,147}; final int[] xTN={272,299,328,337,366,339,278,275}; final int[] yTN={254,257,257,257,233,233,237,240}; final int[] xTX={149,182,198,232,236,245,243,241,209,209,163,160}; final int[] yTX={235,276,263,312,302,297,260,252,246,206,202,235}; final int[] xUT={117,142,144,135,135,120}; final int[] yUT={191,196,165,165,162,159}; final int[] xVT={450,458,462,442}; final int[] yVT={ 75, 75, 40, 46}; final int[] xVA={339,366,434,402,386,402,385,369,351}; final int[] yVA={233,233,233,213,198,183,180,210,218}; final int[] xWA={ 25,114,118, 51, 50, 32, 29}; final int[] yWA={127,139,128,106,112,102,102}; final int[] xWV={351,369,385,375,372,368,345}; final int[] yWV={218,210,180,189,177,177,209}; final int[] xWI={252,255,285,287,281,245,240}; final int[] yWI={143,145,143,116,106,100,130}; final int[] xWY={135,143,161,161,161,137,135}; final int[] yWY={165,165,165,157,147,146,162}; // Label locations of all the states final int[][] labels = { { 309, 283 }, { 73, 315 }, { 120, 220 }, { 249, 253 }, { 50, 195 }, { 153, 187 }, { 470, 129 }, { 440, 216 }, { 394, 203 }, { 385, 350 }, { 346, 285 }, { 178, 334 }, { 117, 152 }, { 263, 185 }, { 298, 190 }, { 218, 167 }, { 195, 195 }, { 320, 225 }, { 250, 280 }, { 476, 44 }, { 415, 215 }, { 470, 90 }, { 312, 123 }, { 215, 136 }, { 277, 277 }, { 237, 213 }, { 139, 143 }, { 186, 174 }, { 102, 173 }, { 461, 62 }, { 445, 175 }, { 145, 220 }, { 422, 102 }, { 396, 251 }, { 177, 142 }, { 332, 175 }, { 214, 232 }, { 82, 148 }, { 389, 153 }, { 501, 116 }, { 386, 276 }, { 178, 155 }, { 308, 252 }, { 179, 242 }, { 123, 185 }, { 446, 57 }, { 377, 223 }, { 62, 127 }, { 357, 203 }, { 260, 130 }, { 142, 160 } }; // State information private StateInfo[] states = { new StateInfo("Alabama" ,"AL", 9, GOP, xAL, yAL, labels[ 0]), new StateInfo("Alaska" ,"AK", 3, GOP, xAK, yAK, labels[ 1]), new StateInfo("Arizona" ,"AZ", 10, GOP, xAZ, yAZ, labels[ 2]), new StateInfo("Arkansas" ,"AR", 6, GOP, xAR, yAR, labels[ 3]), new StateInfo("California" ,"CA", 55, DEM, xCA, yCA, labels[ 4]), new StateInfo("Colorado" ,"CO", 9, GOP, xCO, yCO, labels[ 5]), new StateInfo("Connecticut" ,"CT", 7, DEM, xCT, yCT, labels[ 6]), new StateInfo("Delaware" ,"DE", 3, DEM, xDE, yDE, labels[ 7]), new StateInfo("District of Columbia","DC", 3, DEM, xDC, yDC, labels[ 8]), new StateInfo("Florida" ,"FL", 27, GOP, xFL, yFL, labels[ 9]), new StateInfo("Georgia" ,"GA", 15, GOP, xGA, yGA, labels[10]), new StateInfo("Hawaii" ,"HI", 4, DEM, xHI, yHI, labels[11]), new StateInfo("Idaho" ,"ID", 4, GOP, xID, yID, labels[12]), new StateInfo("Illinois" ,"IL", 21, DEM, xIL, yIL, labels[13]), new StateInfo("Indiana" ,"IN", 11, GOP, xIN, yIN, labels[14]), new StateInfo("Iowa" ,"IA", 7, DEM, xIA, yIA, labels[15]), new StateInfo("Kansas" ,"KS", 6, GOP, xKS, yKS, labels[16]), new StateInfo("Kentucky" ,"KY", 8, GOP, xKY, yKY, labels[17]), new StateInfo("Louisiana" ,"LA", 9, GOP, xLA, yLA, labels[18]), new StateInfo("Maine" ,"ME", 4, DEM, xME, yME, labels[19]), new StateInfo("Maryland" ,"MD", 10, DEM, xMD, yMD, labels[20]), new StateInfo("Massachusetts" ,"MA", 12, DEM, xMA, yMA, labels[21]), new StateInfo("Michigan" ,"MI", 17, DEM, xMI, yMI, labels[22]), new StateInfo("Minnesota" ,"MN", 10, DEM, xMN, yMN, labels[23]), new StateInfo("Mississippi" ,"MS", 6, GOP, xMS, yMS, labels[24]), new StateInfo("Missouri" ,"MO", 11, GOP, xMO, yMO, labels[25]), new StateInfo("Montana" ,"MT", 3, GOP, xMT, yMT, labels[26]), new StateInfo("Nebraska" ,"NE", 5, GOP, xNE, yNE, labels[27]), new StateInfo("Nevada" ,"NV", 5, GOP, xNV, yNV, labels[28]), new StateInfo("New Hampshire" ,"NH", 4, GOP, xNH, yNH, labels[29]), new StateInfo("New Jersey" ,"NJ", 15, DEM, xNJ, yNJ, labels[30]), new StateInfo("New Mexico" ,"NM", 5, DEM, xNM, yNM, labels[31]), new StateInfo("New York" ,"NY", 31, DEM, xNY, yNY, labels[32]), new StateInfo("North Carolina" ,"NC", 15, GOP, xNC, yNC, labels[33]), new StateInfo("North Dakota" ,"ND", 3, GOP, xND, yND, labels[34]), new StateInfo("Ohio" ,"OH", 20, GOP, xOH, yOH, labels[35]), new StateInfo("Oklahoma" ,"OK", 7, GOP, xOK, yOK, labels[36]), new StateInfo("Oregon" ,"OR", 7, DEM, xOR, yOR, labels[37]), new StateInfo("Pennsylvania" ,"PA", 21, DEM, xPA, yPA, labels[38]), new StateInfo("Rhode Island" ,"RI", 4, DEM, xRI, yRI, labels[39]), new StateInfo("South Carolina" ,"SC", 8, GOP, xSC, ySC, labels[40]), new StateInfo("South Dakota" ,"SD", 3, GOP, xSD, ySD, labels[41]), new StateInfo("Tennessee" ,"TN", 11, GOP, xTN, yTN, labels[42]), new StateInfo("Texas" ,"TX", 34, GOP, xTX, yTX, labels[43]), new StateInfo("Utah" ,"UT", 5, GOP, xUT, yUT, labels[44]), new StateInfo("Vermont" ,"VT", 3, DEM, xVT, yVT, labels[45]), new StateInfo("Virginia" ,"VA", 13, GOP, xVA, yVA, labels[46]), new StateInfo("Washington" ,"WA", 11, DEM, xWA, yWA, labels[47]), new StateInfo("West Virginia" ,"WV", 5, GOP, xWV, yWV, labels[48]), new StateInfo("Wisconsin" ,"WI", 10, DEM, xWI, yWI, labels[49]), new StateInfo("Wyoming" ,"WY", 3, GOP, xWY, yWY, labels[50]) }; // Fonts private Font headlineFont = new Font("sans-serif", Font.BOLD, 18); private Font subheadFont = new Font("sans-serif", Font.PLAIN, 12); private Font labelFont = new Font("sans-serif", Font.PLAIN, 9); private Font evFont = new Font("sans-serif", Font.PLAIN, 14); private Font evWinnerFont = new Font("sans-serif", Font.BOLD, 14); // Strings for the interface final String headline = "Electoral College Map"; final String subhead = "The size of each state is distorted to emphasize"; final String subhead2 = "its share of electoral votes."; public void init() { setLayout (null); enableEvents(AWTEvent.MOUSE_EVENT_MASK | AWTEvent.MOUSE_MOTION_EVENT_MASK | AWTEvent.ACTION_EVENT_MASK); // Create a popup menu appletMenu = new PopupMenu("mode"); for (int i=0; i 50) states[i].positions[DISPLAY_POLLS] = DEM; else states[i].positions[DISPLAY_POLLS] = TOSSUP; // Copy it into the custom view. states[i].positions[DISPLAY_CUSTOM] = states[i].positions[DISPLAY_POLLS]; // Compute the confidence in that position as a fraction from 0 to 1 int delta = Math.abs(50 - percentDem); states[i].confidence[DISPLAY_POLLS] = (delta / 50.0); } catch (Exception e) { System.out.println("Invalid value for applet parameter " + states[i].abbr + ": " + s); } } } // Colors may also be passed as applet parameters. String colorKeys[] = { "Color.DEM", "Color.TOSSUP", "Color.GOP" }; for (int i=0; i totalEV) ? evWinnerFont:evFont); g.setColor(getStateColor(GOP,0.6)); g.fillRect(3, y+3, gopEV, g.getFont().getSize() + 3); //g.setColor(getBackground()); //g.fillRect(gopEV+4, y+3, totalEV-gopEV, g.getFont().getSize() + 3); g.setColor(Color.black); y += g.getFont().getSize() + 3; g.drawString(gopCandidate + ": " + gopEV + " EV", 5, y); g.setFont((demEV*2 > totalEV) ? evWinnerFont:evFont); g.setColor(getStateColor(DEM,0.6)); g.fillRect(3, y+3, demEV, g.getFont().getSize() + 3); //g.setColor(getBackground()); //g.fillRect(demEV+4, y+3, totalEV-demEV, g.getFont().getSize() + 3); g.setColor(Color.black); y += g.getFont().getSize() + 4; g.drawString(demCandidate + ": " + demEV + " EV", 5, y); g.setFont(evFont); g.setColor(Color.black); y += g.getFont().getSize() + 4; g.drawString("" + ((totalEV/2)+1) + " EV are required to win.", 5, y); } public void paintState(Graphics g, int i) { try { // Fill the state with the right color. g.setColor(getStateColor(states[i].positions[mode], states[i].confidence[mode])); g.fillPolygon(states[i].poly); // Outline the state. g.setColor(Color.black); g.drawPolygon(states[i].poly); // Draw the label. g.setColor(Color.black); g.setFont(labelFont); g.drawString(states[i].abbr, states[i].labelx, states[i].labely); } catch (Exception e) { System.out.println(e); } } public Color getStateColor(int position, double confidence) { // Get the base color. If we're over 90% confident in this // outcome or the state is already a tossup, use the base. Color base = colors[position]; if (confidence > 0.90 || position == TOSSUP) return base; // Otherwise we're going to find a color between the base and // the tossup color. Extract both components. Color tossup = colors[TOSSUP]; int baseRGB = base.getRGB(); int tossupRGB = tossup.getRGB(); int newRGB = 0; // Adjust the color toward the tossup color based on the confidence. for (int j=0; j<3; ++j) { int baseComponent = (baseRGB >> (8*j)) & 0xFF; int tossupComponent = (tossupRGB >> (8*j)) & 0xFF; int newComponent = baseComponent + (int)((tossupComponent - baseComponent) * (float)(0.1 + 0.6*(1.0 - confidence/0.9))); newComponent = Math.max(0,Math.min(newComponent,0xFF)); newRGB |= (newComponent << (8*j)); } return new Color(newRGB); } public void setMode(int newMode) { if (mode != newMode) { mode = newMode; repaint(); } } public void processMouseEvent(MouseEvent e) { int modifiers = e.getModifiers(); boolean button1 = (modifiers & java.awt.event.InputEvent.BUTTON1_MASK) != 0; boolean button2 = (modifiers & java.awt.event.InputEvent.BUTTON2_MASK) != 0; boolean button3 = (modifiers & java.awt.event.InputEvent.BUTTON3_MASK) != 0; boolean ctrl = e.isControlDown(); boolean shift = e.isShiftDown(); // Handle showing the popup menu. if (e.isPopupTrigger() || (e.getID() == MouseEvent.MOUSE_CLICKED && button1 && (ctrl || shift))) { // Update the checkboxes in the menu before we bring it up. for (int i=0; i= TOTAL_POSITIONS) states[i].positions[mode] = 0; // Redraw next chance we get. repaint(); } public void itemStateChanged( ItemEvent e ) { String label = (String)e.getItem(); for (int i=0; i