Build an analog clock in Ring
A real clock — round face, three hands, ticking once a second — with every decision made by Ring. It assumes you have never built a web page. About ten minutes.
clock.html.Why not just run the desktop clock? A desktop clock program opens a window and draws into it through Qt. A browser tab has no Qt and no window to draw into, so that program cannot run here — see the Q&A.
But almost none of that program is about Qt. Working out where an hour hand points at 23:10 is arithmetic, and arithmetic is what Ring is for. That part carries over untouched. Only the drawing changes.
1 Get a folder that already runs
Download the starter kit, unzip it, and double-click
start-windows.bat or start-mac-linux.sh. A small server
window opens and your browser lands on a working page.
Everything below happens in that folder. Create two new files there —
myclock.html and myclock.ring — and visit
localhost:8377/myclock.html as you go.
2 Draw a face that never changes
The face is just a picture: a circle, twelve marks, three lines. It is written in SVG — shapes described as text, so nothing needs to be drawn by hand or loaded as an image. Ring never touches any of it.
The coordinates run 0 to 200 across and down, so the middle is
100,100. A line from 100,100 up to 100,58
points at twelve o'clock.
<svg viewBox="0 0 200 200"> <circle cx="100" cy="100" r="96" fill="white" stroke="black"/> <!-- one mark, then the same line turned 30 degrees at a time --> <line x1="100" y1="10" x2="100" y2="22" transform="rotate(0 100 100)"/> <line x1="100" y1="10" x2="100" y2="22" transform="rotate(30 100 100)"/> <!-- ...ten more, up to rotate(330 100 100) --> <!-- the three hands. Each has an id so Ring can find it. --> <line id="hour-hand" x1="100" y1="100" x2="100" y2="58"/> <line id="minute-hand" x1="100" y1="100" x2="100" y2="40"/> <line id="second-hand" x1="100" y1="100" x2="100" y2="32"/> </svg>
An id is a name you give one spot on the page. It is the only thing
Ring needs in order to reach it — exactly like naming a control on a desktop form.
3 Turn about the middle, not the end
One line of styling, and it matters: by default a shape turns about its own centre, which would swing the hands around their midpoints. Both lines below say turn about the middle of the face.
<style> line { transform-box: view-box; transform-origin: 100px 100px; } </style>
4 Work out the angles — this part is pure Ring
A full turn is 360 degrees, and this is the whole idea of the clock:
| Hand | Because | Degrees |
|---|---|---|
| Second | 60 seconds in a turn | seconds × 6 |
| Minute | 60 minutes in a turn | minutes × 6 |
| Hour | 12 hours in a turn | hours × 30 |
One refinement makes it look real: at half past, a proper hour hand sits
between six and seven. So the minutes nudge the hour hand along
(+ minutes × 0.5), and the seconds nudge the minute hand
(+ seconds × 0.1).
In myclock.ring:
func Tick aData cNow = time() # "23:10:12" nHour = number(substr(cNow, 1, 2)) nMinute = number(substr(cNow, 4, 2)) nSecond = number(substr(cNow, 7, 2)) nSecondAngle = nSecond * 6 nMinuteAngle = nMinute * 6 + nSecond * 0.1 nHourAngle = (nHour % 12) * 30 + nMinute * 0.5 Page(:rotate, [ :id = "hour-hand", :deg = nHourAngle ]) Page(:rotate, [ :id = "minute-hand", :deg = nMinuteAngle ]) Page(:rotate, [ :id = "second-hand", :deg = nSecondAngle ]) Page(:settext, [ :id = "digital", :text = cNow ])
That is ordinary Ring: time(), substr(),
number(), arithmetic. Nothing about it is web-specific except the two
Page(...) lines that hand the answer to the screen.
Why aData? Every Ring function called from the page
receives one value — whatever was sent with the call. This one sends nothing, so it
arrives empty. Declare it and ignore it; leaving it out is an error.
5 Teach the page one new word
A page understands three requests from Ring out of the box:
settext, gettext and getvalue. Turning a shape
is a fourth, so you add it — four lines, once:
<script src="ringscript.js"></script> <script type="text/ring" src="myclock.ring"></script> <script> RingScript.boot().then(function (ring) { ring.on("rotate", function (data) { document.getElementById(data.id).style.transform = "rotate(" + data.deg + "deg)"; return 1; }); ring.call("Tick"); // draw it now setInterval(function () { ring.call("Tick"); }, 1000); // and every second }); </script>
This is the only JavaScript in the whole clock, and it is the general pattern: when the page cannot yet do something you need, you teach it that one word, and from then on Ring asks for it by name like any other.
6 Open it, then change it
Go to localhost:8377/myclock.html. The hands should be showing the
right time.
Now make it yours — edit myclock.ring, save, press Refresh:
- Make the second hand move in fives: replace
nSecond * 6withfloor(nSecond / 5) * 30. - Show the date as well, with
date(). - Turn it into a countdown: keep a number in a variable,
subtract one each tick, and write it out with
Page(:settext, ...).
None of that needs a build step, a compiler, or anything installed. Edit, save, refresh.
What this showed
The clock is about sixty lines, and the part that decides anything is Ring. The page holds the shapes; Ring holds the reasoning. That division is the whole method, and it scales: a form, an invoice, a rules engine — the page shows, Ring decides.