// Copyright 1997-2015 Christian d'Heureuse, Inventec Informatik AG, Zurich, Switzerland
// www.source-code.biz, www.inventec.ch/chdh
//
// This module is multi-licensed and may be used under the terms of any of the following licenses:
//
// LGPL, GNU Lesser General Public License, V2.1 or later, http://www.gnu.org/licenses/lgpl.html
// EPL, Eclipse Public License, V1.0 or later, http://www.eclipse.org/legal
//
// Please contact the author if you need another license.
// This module is provided "as is", without warranties of any kind.
//
// Home page: http://www.source-code.biz/snippets/java/1.htm
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Image;
import java.awt.image.ImageProducer;
import java.awt.image.FilteredImageSource;
import java.applet.Applet;
import java.util.GregorianCalendar;
/**
* A station clock applet, drawn with anti-aliased graphics.
* This applet uses the AntiAliasingFilter class to draw a clock.
*/
public class ClockApplet extends Applet implements Runnable {
private String clockLabel = "source-code.biz";
private Color bgColor;
private int aaScalingFactor; // the anti-aliasing scaling factor
private Color secPtrColor = new Color(0xCC, 0x00, 0x00);
private Color borderColor = new Color(0xC0, 0xC0, 0xC0);
private Thread thread;
private Image staticImg;
private Image dynImg;
private int r;
private int centerX;
private int centerY;
private void drawRadial (Graphics g, double alpha, int r1, int r2, int width1, int width2) {
double sin = Math.sin(alpha);
double cos = Math.cos(alpha);
double pm1X = sin * r1;
double pm1Y = cos * r1;
double pm2X = sin * r2;
double pm2Y = cos * r2;
double pxr[] = new double[4];
double pyr[] = new double[4];
pxr[0] = pm1X - cos * width1 / 2;
pyr[0] = pm1Y + sin * width1 / 2;
pxr[3] = pm1X + cos * width1 / 2;
pyr[3] = pm1Y - sin * width1 / 2;
pxr[1] = pm2X - cos * width2 / 2;
pyr[1] = pm2Y + sin * width2 / 2;
pxr[2] = pm2X + cos * width2 / 2;
pyr[2] = pm2Y - sin * width2 / 2;
int pxi[] = new int[4];
int pyi[] = new int[4];
for (int i = 0; i < 4; i++) {
pxi[i] = centerX + (int)Math.round(pxr[i]);
pyi[i] = centerY - (int)Math.round(pyr[i]); }
g.fillPolygon(pxi, pyi, 4); }
private void drawRadialFilledCircle (Graphics g, double alpha, int r1, int circR) {
int p0X = (int)Math.round( centerX + Math.sin(alpha) * r1 );
int p0Y = (int)Math.round( centerY - Math.cos(alpha) * r1 );
g.fillOval(p0X - circR, p0Y - circR, 2 * circR, 2 * circR); }
private void drawClockLabel (Graphics g) {
g.setColor(borderColor);
int fontSize = r * 20 / 200;
Font f = new Font("Helvetica", Font.PLAIN, fontSize);
g.setFont(f);
FontMetrics fm = g.getFontMetrics();
g.drawString(clockLabel, centerX - fm.stringWidth(clockLabel) / 2, centerY + r / 2); }
private void drawFilledCircle (Graphics g, int r, Color c) {
g.setColor(c);
g.fillOval(centerX - r, centerY - r, 2 * r, 2 * r); }
private void drawStaticImage (Graphics g, int width, int height) {
r = Math.min(width, height) * 7 / 16;
centerX = width / 2;
centerY = height / 2;
g.setColor(bgColor);
g.fillRect(0, 0, width, height);
int borderWidth = r / 54;
// drawFilledCircle(g, r + borderWidth + borderWidth, new Color(0xf0, 0xf0, 0xf0));
drawFilledCircle(g, r + borderWidth, borderColor);
drawFilledCircle(g, r, Color.white);
g.setColor(Color.black);
for (int i = 0; i < 60; i++) {
boolean big = i % 5 == 0;
int rlength = big ? r * 10 / 44 : r * 3 / 44;
rlength = Math.max(1, rlength);
int rwidth = big ? r * 3 / 44 : r / 44;
rwidth = Math.max(1, rwidth);
int r2 = r * 42 / 44;
drawRadial(g, 2 * Math.PI / 60 * i, r2 - rlength, r2, rwidth, rwidth); }
drawClockLabel(g); }
private void generateStaticImage (int width, int height) {
staticImg = createImage(width, height);
Graphics g = staticImg.getGraphics();
drawStaticImage(g, width, height);
g.dispose(); }
private void drawDynamicImage (Graphics g, int hour, int min, int sec) {
g.setColor(Color.black);
drawRadial(g, 2 * Math.PI * ( (hour % 12) * 60 + min) / (12 * 60), -r * 10 / 44, r * 27 / 44, r * 5 / 44, r * 4 / 44);
drawRadial(g, 2 * Math.PI * min / 60, -r * 10 / 44, r * 40 / 44, r * 9 / 88, r * 3 / 44);
g.setColor(secPtrColor);
int r_1_44 = Math.max(1, r * 1 / 44);
drawRadial(g, 2 * Math.PI * sec / 60, -r * 14 / 44, r * 27 / 44, r_1_44, r_1_44);
drawRadialFilledCircle(g, 2 * Math.PI / 60 * sec, r * 27 / 44, r * 9 / 88); }
private Image genImg (int width, int height, int hour, int min, int sec) {
int aaWidth = width * aaScalingFactor;
int aaHeight = height * aaScalingFactor;
if (staticImg == null || staticImg.getWidth(null)!=aaWidth || staticImg.getHeight(null)!=aaHeight) {
generateStaticImage(aaWidth, aaHeight);
dynImg = createImage(aaWidth, aaHeight); }
Graphics g = dynImg.getGraphics();
g.drawImage(staticImg, 0, 0, null);
drawDynamicImage(g, hour, min, sec);
g.dispose();
if (aaScalingFactor <= 1) {
return dynImg; }
// AreaAveragingScaleFilter aaFilter = new AreaAveragingScaleFilter(width, height);
// ReplicateScaleFilter aaFilter = new ReplicateScaleFilter(width, height);
AntiAliasingFilter aaFilter = new AntiAliasingFilter(aaScalingFactor);
ImageProducer aaProd = new FilteredImageSource(dynImg.getSource(), aaFilter);
Image outImg = createImage(aaProd);
return outImg; }
private void getTimeNew (int[] time) {
GregorianCalendar cal = new GregorianCalendar();
time[0] = cal.get(GregorianCalendar.HOUR_OF_DAY);
time[1] = cal.get(GregorianCalendar.MINUTE);
time[2] = cal.get(GregorianCalendar.SECOND); }
public void paint (Graphics g) {
int time[] = new int[3];
getTimeNew(time);
Image img = genImg(getSize().width, getSize().height, time[0], time[1], time[2]);
g.drawImage(img, 0, 0, null); }
public void update (Graphics g) {
paint(g); }
public void run() {
while (true) {
int secOffs = (int)(System.currentTimeMillis() % 1000);
int delayT = 1000 - secOffs;
try {
Thread.sleep(delayT); }
catch (Exception e) {
throw new RuntimeException(e.getMessage()); }
if (thread != Thread.currentThread()) {
break; }
repaint(); }}
public void start() {
if (thread == null) {
thread = new Thread(this);
thread.start(); }}
public void stop() {
thread = null; }
public String getAppletInfo() {
return "ClockApplet version 2015-02-07 by Christian d'Heureuse (www.source-code.biz)"; }
public void setBgColor (String s) {
try {
bgColor = new Color(Integer.parseInt(s, 16)); }
catch (Exception e) {
throw new IllegalArgumentException("Invalid bgColor parameter.", e); }
repaint(); }
public void setAaScalingFactor (String s) {
try {
aaScalingFactor = Integer.parseInt(s); }
catch (Exception e) {
throw new IllegalArgumentException("Invalid aaScalingFactor parameter.", e); }
repaint(); }
private void getParms() {
bgColor = Color.white;
String s = getParameter("bgColor");
if (s != null) {
setBgColor(s); }
aaScalingFactor = 1;
s = getParameter("aaScalingFactor");
if (s != null) {
setAaScalingFactor(s); }}
public void init() {
getParms();
setBackground(bgColor); }
}