import java.lang.Math; import java.util.Date; import java.awt.Graphics; import java.lang.Number; import java.awt.Color; import java.awt.Image; import java.awt.Font; import java.awt.FontMetrics; //Class Definition: clock public class clock extends java.applet.Applet implements Runnable { //----------VARIABLES---------- Thread runthread; //Thread variable int htmlradius; //PARAM - radius of clock face String image; //PARAM - image file int horizoffset; //PARAM - horizontal number offset int vertoffset; //PARAM - vertical number offset double clockdiameter; //Diameter of the face of the clock double hour; //System hour, 0-23 double minute; //System minute, 0-59 double second; //System second, 0-59 double dotdiameter = 8; //Diameter of a dot on the clock double dx; //X coordinates of number on the clock double dy; //Y coordinates of number on the clock double xcenter; //X coordinate of the center of the clock double ycenter; //Y coordinate of the center of the clock double hradius; //Length of the hour hand double mradius; //Length of the minute hand double sradius; //Length of the second hand Font f = new Font("TimesRoman", Font.BOLD, 14); //Font of numbers FontMetrics fm = getFontMetrics(f); //Font details int[] sxpts = new int[5]; //X coordinates for each point of the second hand polygon int[] sypts = new int[5]; //Y coordinates for each point of the second hand polygon int[] mxpts = new int[5]; //X coordinates for each point of the minute hand polygon int[] mypts = new int[5]; //Y coordinates for each point of the minute hand polygon int[] hxpts = new int[5]; //X coordinates for each point of the hour hand polygon int[] hypts = new int[5]; //Y coordinates for each point of the hour hand polygon int pts = 5; double lastsecond = -1; //Last second drawn Image offscreenImage; //Used for double buffering Graphics offscreenGraphics; //Used for double buffering int iwidth; //Image width int iheight; //Image height double newheight; //Scaled image height double newwidth; //Scaled image width float scalefactor; //Scale factor double imageboxlength; //Size of image bounding box int imagex; //Image x coord int imagey; //Image y coord Image clockImage; //Image //----------FUNCTIONS---------- //============================= //Function: run() //Input: none //Output: none //============================= public void run() { while (true) { this.getDate(); if (second != lastsecond) { this.calculatePoints(); repaint(); } try { Thread.sleep(480); } catch (InterruptedException e) {} } } //============================= //Function: init() //Input: none //Output: none //============================= public void init() { //Get applet PARAM's clockdiameter = Integer.parseInt((getParameter("diameter"))); image = getParameter("image"); horizoffset = Integer.parseInt((getParameter("hoff"))); vertoffset = Integer.parseInt((getParameter("voff"))); //Calculate center & hand radius xcenter = clockdiameter/2; ycenter = clockdiameter/2; hradius = 0.5*(clockdiameter/2); mradius = 0.7*(clockdiameter/2); //Initializa image object offscreenImage = createImage(size().width, size().height); offscreenGraphics = offscreenImage.getGraphics(); clockImage = getImage(getCodeBase(), image); sradius = 0.7*(clockdiameter/2); } //============================= //Function: calculatePoints() //Input: none //Output: none // updates sxpts[], sypts, mxpts[], mypts[], // hxpts[], hypts[] //============================= public void calculatePoints() { //Calculates the points which make up each corner of the polygon (hand) based upon //the current time. //x endpoint = xcenter + radius*sin(2PI*time/60) for minutes and seconds //y endpoint = ycenter - radius*cos(2PI*time/60) for minutes and seconds //The other two midpoints are half the length of the hand offset by 0.1 radians sxpts[0] = sxpts[4] = (int) xcenter; sypts[0] = sypts[4] = (int) ycenter; sxpts[2] = (int)(xcenter + (sradius*(Math.sin(2*Math.PI*(second/60))))); sypts[2] = (int)(ycenter + (-1*sradius*(Math.cos(2*Math.PI*(second/60))))); sxpts[1] = (int)(xcenter + (0.3*sradius*(Math.sin(2*Math.PI*(second/60) - 0.1)))); sypts[1] = (int)(ycenter + (-0.3*sradius*(Math.cos(2*Math.PI*(second/60) - 0.1)))); sxpts[3] = (int)(xcenter + (0.3*sradius*(Math.sin(2*Math.PI*(second/60) + 0.1)))); sypts[3] = (int)(ycenter + (-0.3*sradius*(Math.cos(2*Math.PI*(second/60) + 0.1)))); mxpts[0] = mxpts[4] = (int) xcenter; mypts[0] = mypts[4] = (int) ycenter; mxpts[2] = (int)(xcenter + (mradius*(Math.sin(2*Math.PI*(minute/60))))); mypts[2] = (int)(ycenter + (-1*mradius*(Math.cos(2*Math.PI*(minute/60))))); mxpts[1] = (int)(xcenter + (0.5*mradius*(Math.sin(2*Math.PI*(minute/60) - 0.1)))); mypts[1] = (int)(ycenter + (-0.5*mradius*(Math.cos(2*Math.PI*(minute/60) - 0.1)))); mxpts[3] = (int)(xcenter + (0.5*mradius*(Math.sin(2*Math.PI*(minute/60) + 0.1)))); mypts[3] = (int)(ycenter + (-0.5*mradius*(Math.cos(2*Math.PI*(minute/60) + 0.1)))); //To gradually move the hour hand so that it's position reflects the //position of the minute hand, we need to calculate how many seconds //out of 12 hours (43,200s) have passed and substitute that value for //s/60. Otherwise, the hour hand would operate as a 'step' function //portraying a misleading time. double totalSeconds = calculateSeconds(); hxpts[0] = hxpts[4] = (int) xcenter; hypts[0] = hypts[4] = (int) ycenter; hxpts[2] = (int)(xcenter + (hradius*(Math.sin(2*Math.PI*totalSeconds)))); hypts[2] = (int)(ycenter + (-1*hradius*(Math.cos(2*Math.PI*totalSeconds)))); hxpts[1] = (int)(xcenter + (0.5*hradius*(Math.sin(2*Math.PI*totalSeconds - 0.1)))); hypts[1] = (int)(ycenter + (-0.5*hradius*(Math.cos(2*Math.PI*totalSeconds - 0.1)))); hxpts[3] = (int)(xcenter + (0.5*hradius*(Math.sin(2*Math.PI*totalSeconds + 0.1)))); hypts[3] = (int)(ycenter + (-0.5*hradius*(Math.cos(2*Math.PI*totalSeconds + 0.1)))); } //============================= //Function: calculateSeconds() //Input: none //Output: total # of elapsed seconds //============================= public double calculateSeconds() { //Get the total number of seconds elapsed in this 12-hour period return( ( (3600*hour + 60*minute + second) / 43200) ); } //============================= //Function: paint() //Input: graphics object //Output: none // updates drawing area //============================= public void paint(Graphics g) { //Set background color setBackground(Color.white); //Set font g.setFont(f); //Set draw color offscreenGraphics.setColor(Color.white); //Draw Oval face and background rectangle offscreenGraphics.fillOval(0,0,(int)clockdiameter, (int)clockdiameter); //Draw an oval offscreenGraphics.fillRect(0,0, (int)clockdiameter+1, (int)clockdiameter+1); offscreenGraphics.setColor(Color.black); offscreenGraphics.drawOval(0,0,(int)clockdiameter, (int)clockdiameter); //Each number is first calculated, then converted to a string. The string's height and //width are calculated using font metrics. The string can then be centered at it's //appropriate position using a formula similar to the one that determines where each hand //should be drawn. for (double i=0; i<60; i+=5) { double number; //hour number = i/5; if (number == 0) { number = 12; } //Convert to string and remove the ".0" String s = Double.toString(number); String t = s.substring(0, s.length() - 2); //dx = (int) (xcenter + (0.9*clockdiameter/2)*(Math.sin(2*Math.PI*(i/60))) - fm.stringWidth(Double.toString(number))/2 + horizoffset); //dy = (int) (ycenter - (0.9*clockdiameter/2)*(Math.cos(2*Math.PI*(i/60))) + (fm.getHeight())/2) + vertoffset; //offscreenGraphics.drawString(Double.toString(number), (int)dx, (int)dy); dx = (int) (xcenter + (0.9*clockdiameter/2)*(Math.sin(2*Math.PI*(i/60))) - fm.stringWidth(t)/2 + horizoffset); dy = (int) (ycenter - (0.9*clockdiameter/2)*(Math.cos(2*Math.PI*(i/60))) + (fm.getHeight())/2) + vertoffset; //Draw the face number offscreenGraphics.drawString(t, (int)dx, (int)dy); } //Get image size iwidth = clockImage.getWidth(this); iheight = clockImage.getHeight(this); //Get the size of the bounding box imageboxlength = (double)(clockdiameter*(Math.sin(Math.PI/4))*0.8); //Scale the image if (iwidth > iheight) { scalefactor = (float)(imageboxlength/iwidth); } else { scalefactor = (float)(imageboxlength/iheight); } newwidth = iwidth*scalefactor; newheight = iheight*scalefactor; imagex = (int)(xcenter - (newwidth/2)); imagey = (int)(ycenter - (newheight/2)); //Draw clock image offscreenGraphics.drawImage(clockImage, imagex, imagey, (int)newwidth, (int)newheight, this); //Draw each hand offscreenGraphics.setColor(Color.red); offscreenGraphics.fillPolygon(sxpts, sypts, pts); offscreenGraphics.setColor(Color.black); offscreenGraphics.fillPolygon(mxpts, mypts, pts); offscreenGraphics.setColor(Color.green); offscreenGraphics.fillPolygon(hxpts, hypts, pts); lastsecond = second; //Swap the offscreen image with the onscreen image g.drawImage(offscreenImage, 0, 0, this); } //============================= //Function: update() //Input: graphics object //Output: none //Note: Overrides update so that canvas isn't cleared //============================= public void update(Graphics g) { //Call the paint routine without clearing the canvas paint(g); } //============================= //Function: getDate() //Input: none //Output: none // updates hour, minute, second //============================= public void getDate() { //Get the current date/time Date theDate = new Date(); //Get current system time //Parse out the hour, minute and second hour = (double) theDate.getHours(); //Get hours minute = (double) theDate.getMinutes(); //Get minutes second = (double) theDate.getSeconds(); //Get seconds } //============================= //Function: start() //Input: none //Output: none // updates runthread //============================= public void start() { //Start as a thread if (runthread == null) { runthread = new Thread(this); runthread.start(); } } //============================= //Function: stop() //Input: none //Output: none // updates runthread //============================= public void stop() { //Stop the thread if (runthread != null) { runthread.stop(); runthread = null; } } }