DEV Community

Cover image for Beautiful Object Oriented Clock...
Eckehard
Eckehard

Posted on • Edited on

Beautiful Object Oriented Clock...

Inspired by a nice post Simple Analog Clock Using Html, CSS & Javascript, that shows how to build an analog clock the "traditional" way, I was curious to see, how much coding it would need with DML, the Document Makeup Library.

The original HTML-setup is very nice, but a bit lengthy. And it lacks some portability. So, here I show, how to set up a class with DML that gives you the same functionality. This can be used like any standard HTML element in DML or it can be provided as a WebComponent with minimal effort.

This is myclock.js:

// just a class wrapper for convenience
function myClock(size = 300, attrib) { return new _myClock(size, attrib) }

// the class
class _myClock  {
  constructor(size, attrib) {
    this.size = size
    const cx = size/2, cy = size/2;  // Radius
    const _clockstyle = "width: " + (size) + "px;  height: " + (size) + "px;"
      + "border: 7px solid #282828; background: #585858;"
      + "border-radius: 50%; margin: 50px;"
      + "box-shadow: -4px -4px 10px rgba(67,67,67,0.5), inset 4px 4px 10px rgba(0,0,0,0.5),"
      + "inset -4px -4px 10px rgba(67,67,67,0.5), 4px 4px 10px rgba(0,0,0,0.3);"

    this.base = sidiv("", _clockstyle+attrib)
    let c = this.canvas = canvas2D({ width: px(2 * cx), height: px(2 * cy) })

    c.ctx.lineCap = "round"
    unselectBase()

    // Paint anything radial
    function tick(color, width, angle, length, innerlength = 0) {
      function ls(length) { return length * Math.sin(angle / 180.0 * Math.PI) }
      function lc(length) { return -length * Math.cos(angle / 180.0 * Math.PI) }
      c.setLineType(width, color)
      c.line(cx + ls(innerlength), cy + lc(innerlength), cx + ls(length), cy + lc(length))
    }

    // Draw clock
    function drawClock() {
      c.clear()
      // Draw ticks
      for (let i = 0; i < 360; i += 30)
        if ((i % 90) == 0) tick("#1df52f", 5, i, size*0.45, size*0.40)
        else tick("#bdbdcb", 3, i,  size*0.45, size*0.43)

      // draw hands
      let t = new Date();  // get time
      tick("#61afff", 5, t.getHours() * 30, size*0.25)  // hour
      tick("#71afff", 2, t.getMinutes() * 6, size*0.35)  // min
      tick("#ee791a", 2, t.getSeconds() * 6, size*0.42)  // s

      // drwa center
      c.setFillStyle("#4d4b63")
      c.circle(cx, cy, 10, { fill: true })
    }
    drawClock()
    setInterval(drawClock, 1000)
  }
}
Enter fullscreen mode Exit fullscreen mode

This is the complete webpage to create a number of different sized clocks:

<!DOCTYPE html>
<html lang="de">

<head>
  <meta charset="utf-8">
  <title>title</title>
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <script src="https://efpage.de/DML/DML_homepage/lib/DML-min.js"></script>
  <script src="myclock.js"></script>
</head>

<body>
  <script>  "use strict";
    for (let i = 200; i>30; i*=0.75)
    myClock(i, "background-color: teal; margin: 10px;")
  </script>
</body>

</html>
Enter fullscreen mode Exit fullscreen mode

The result should look like this:
Clock sized
You can add different styles too:

  <script>  "use strict";
    let c = ["red", "green", "blue", "yellow", "orange"]
    let k=0
    for (let i = 200; i>30; i*=0.75)
    myClock(i, "background-color: "+c[k++]+"; margin: 10px; border-radius: 25%;")
  </script>
Enter fullscreen mode Exit fullscreen mode

Clocks with decorations

Making a WebComponent...

If you like the more traditional way, it is easy to convert the DML-class to act as a web-component. In fact, it is still usable in DML without changes.

You need just two small changes in the source:

a) derive the class from HTMLElement

class _myClock extends HTMLElement {....
Enter fullscreen mode Exit fullscreen mode

b) add the HTML-element-definition below the class definition

window.customElements.define('my-clock', _myClock);
Enter fullscreen mode Exit fullscreen mode

The class still works as a DML-class, but now can be used as a new html-tag too:

<body>
  <my-clock></my-clock>
</body>
Enter fullscreen mode Exit fullscreen mode

The class was just quickly converted for demonstration purpose, so it might lack some functionallity. Just, it works...

Top comments (0)