Building an Analog Clock with Timelines
With the JavaFX technology it is easy to build your own customized analog clock with a simple graphics operation and binding.
Understanding the Code
The code shown in Figure 1 creates an analog clock. Most of the drawing is based on public attributes, enabling you to easily customize the look by changing a few settings.
Source Code
package analogclock; import javafx.stage.*; import javafx.scene.*; import javafx.geometry.*; import javafx.scene.paint.*; import javafx.scene.text.*; import javafx.scene.transform.*; import javafx.animation.*; import javafx.scene.image.*; import javafx.scene.shape.*; // Java Legacy import java.util.*; import java.lang.Math; import java.lang.System; var months:String[] = ["JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"]; public class AnalogClock extends CustomNode { var radius: Number = 80; // Decides the main size of the clock. var centerX: Number = 115 ; // shifting the X center var centerY: Number = 144 ; // shifting the Y center var hours:Number; var minutes:Number; var seconds:Number; var date:String; var month:String; var year:String; var combination: String; // intializing the watch init { var timeline = Timeline { repeatCount: Timeline.INDEFINITE keyFrames : [ KeyFrame { time : 1s action: function() { actionOnTick(); } } ] } timeline.play(); } function createCalendar() { def calendar = Calendar.getInstance(); calendar.setTime(new Date()); // fix for mobile calendar } // action taken on one tick public function actionOnTick () { var calendar = createCalendar(); seconds = calendar.get(Calendar.SECOND); minutes = calendar.get(Calendar.MINUTE); hours = calendar.get(Calendar.HOUR); date = String.valueOf(calendar.get(Calendar.DATE)); if(date.length()!=2) { date = "0{date}"; } month = months[(calendar.get(Calendar.MONTH))]; year = String.valueOf((calendar.get(Calendar.YEAR))); // 1900 offset combination = "{date}-{month}-{year}"; } // overriding the method create() public override function create(): Node { return Group { transforms: [ Transform.translate(centerX, centerY) ] content: [ Circle { radius: radius + 20 fill: RadialGradient { centerX: 0 centerY: 0 radius: radius + 20 proportional: false stops: [ Stop { offset: 0.9 color: Color.SILVER }, Stop { offset: 1.0 color: Color.BLACK } ] } }, Circle { radius: radius + 10 stroke: Color.BLACK fill: RadialGradient { centerX: 0 centerY: 0 radius: 90 proportional: false stops: [ Stop { offset: 0.0 color: Color.WHITE }, Stop { offset: 1.0 color: Color.CADETBLUE } ] } }, Rectangle { x: -35, y: 2*radius/3 - 15 width: 71 height: 20 fill: Color.GRAY opacity:0.4 strokeWidth: 2 stroke: Color.BLACK arcHeight:10 arcWidth:10 }, Text { font: Font { size: 11 name: "Arial" } x: -31 , y: 2 * radius / 3 content: bind combination }, //setting the main digits 3,6,9,12 for (i in [3, 6, 9, 12]) Text { transforms:bind [ Transform.translate(-5, 5) ] x: radius * (( i + 0 ) mod 2 * ( 2 - i / 3)) y: radius * (( i + 1 ) mod 2 * ( 3 - i / 3)) content: "{i}" font: Font { size: 11 name: "Arial" } }, // making dots on rest of the place for (i in [1..12]) if (i mod 3 != 0 ) then Circle { transforms:Rotate { angle: 30 * i } centerX: radius radius: 3 fill: Color.BLACK } else [ ], // circle at the core center Circle { radius: 5 fill: Color.BLACK }, // one more circle inside the above circle Circle { radius: 3 fill: Color.GRAY }, // second arm Line { transforms: Rotate { angle: bind seconds * 6 } endY: -radius - 3 strokeWidth: 2 stroke: Color.RED }, // hour arm Path { transforms: Rotate { angle: bind (hours + minutes / 60) * 30 - 90 } fill: Color.BLACK elements: [ MoveTo {x: 4, y: 4}, ArcTo {x: 4 y: -4 radiusX: 1 radiusY: 1}, LineTo{ x: radius - 15 y: 0}, ] }, // minute arm Path { transforms: Rotate { angle: bind minutes * 6 - 90 } fill: Color.BLACK elements: [ MoveTo {x: 4, y: 4}, ArcTo {x: 4 y: -4 radiusX: 1 radiusY: 1}, LineTo{ x: radius y: 0}, ] } ] }; } }
Figure 1: AnalogClock.fx Class
Changing the data member radius, enables you to make the clock bigger or smaller.
Source Code
var radius: Number = 80; // Decides the main size of the clock.
Figure 2: Data Member radius
Customizing the Code
To further customize the clock, change a few of the attributes and use a gradient for the clock fill.
Source Code
Circle {
radius: radius + 10
stroke: Color.BLACK
fill: RadialGradient {
centerX: 0
centerY: 0
radius: 90
proportional: false
stops: [
Stop { offset: 0.0 color: Color.WHITE },
Stop { offset: 1.0 color: Color.YELLOWGREEN }
]
}
},
Figure 3: Change Colors and Gradient
Figure 4: Clock With a Different Shade
Vaibhav Choudhary
