Analog Clocks - programming hint

Posted on
  • It's said that the essence of good Software Engineering is reuse (plagiarism?) so in developing my own analog clock faces, I have been looking through the code of many of the clocks in the BangleApps repository. In trying to get clock faces to render as quickly as possible, I found that the use of the Espruino graphics operation transformVertices from the builtin Graphics class helped enormously. Using the Github search facility, I found only two apps using the operation in BangleApps - neither are Analog Clocks - hence I hope the following example may be of interest. The example uses the the transformVertices operation in implementing the drawRotRect function used in the Beeb Clock (reuse in action).The function places a rectangle rotated around the centre of the clock dial at a parameterised distance from the centre of the clock. I have used it for the following Bold Clock influenced face:

    The following are the functions to draw the dial and the hands of this clock.

        var cx = g.getWidth()/2;
        var cy = g.getHeight()/2
    
        Graphics.prototype.drawRotRect = function(w, r1, r2, angle) {
            var w2=w/2, h=r2-r1, theta=angle*Math.PI/180;
            return this.fillPoly(this.transformVertices([-w­2,0,-w2,-h,w2,-h,w2,0], 
              {x:cx+r1*Math.sin(theta),y:cy-r1*Math.co­s(theta),rotate:theta}));
        }
          
        function dial() {
            for (let a=0;a<360;a+=6)
            if (a % 90 == 0) 
                g.setColor(g.theme.fg).drawRotRect(8,105­,120,a);
            else if (a % 30 == 0)
                g.setColor(g.theme.fg).drawRotRect(4,105­,120,a);
            else 
                g.setColor(0.6,0.6,0.6).drawRotRect(2,11­0,120,a);
        }
    
    let hourHand = g.drawRotRect.bind(g,6,6,66);
     let minuteHand = g.drawRotRect.bind(g,3,6,100);
     let secondhand = g.drawRotRect.bind(g,2,3,100);
    

    This example uses a rectangle, however, the approach can just as easily be applied to polygons representing more complex hands.

  • looks very interesting - thank you very much!

    What always surprises me is the remark "Note: This is only available in !devices with low flash memory with !'Original' Espruino boards" at the end of many method descriptions - but the Bangle.js 2 is neither an original Espruino board nor has it low flash memory, right?

  • Thanks! This is really neat. Also I imagine a lot faster than recalculating vertices each time.

    Thanks for the note about the comment too. The next is created from some code, so the ! is actually a 'not'. It should have been handled (check out https://www.espruino.com/Reference#l_Gra­phics_setFontVector for instance) but it seems maybe the combination of two conditions didn't work. I'll try and get a fix in for that

  • Ah good, I was interpreting the ! correctly.

    This is a nice trick. Is there a good way to benchmark the difference things like this make?

  • thanks for sharing @jeffmer

  • Is there a good way to benchmark the difference things like this make?

    Best bet is to run something like var t=getTime();draw();print(getTime()-t) which will tell you how long (in seconds) the draw took

  • The time to draw the dial on a Bangle2 (with radius 88 rather that 120) with the code above took 376ms. The time using a version of drawRotRect that does not use transformVertices was 490ms - or 114ms slower. Timed using:

     var tt = Date.now(); 
    dial(); 
    console.log("Time: "+Math.ceil(Date.now()-tt)+"ms");
    
  • Nice. And thanks both for showing how you benchmarked it.

  • Any possibility of doing the square background idea? I love this watch.

  • @andiohn That's on my to-do list...

  • @andiohn what about Analog Dark?
    https://banglejs.com/apps/#analog


    1 Attachment

    • screenshot.png
  • Ya, that one's alright; it doesn't have the features of this one and I think this one looks better with the grey.

  • I had a go at a Braun face this afternoon and the result is below. The problem with using grey is that it can only be achieved by dithering on the Bangle2 and as a result looks terrible on narrow marks -so the marks are white.

    You can see the effect of dithering on the orange second hand which is a made up of red and green pixels - I think it looks better in solid red.

  • That looks great @jeffmer.

  • Oops - accidentally deleted the image in my previous post - now restored. I have added the Braun face to multiclock which you can load from here - in advance of submission to the offical BangleApps repository.

  • @jeffmer I thought I was blind I didn’t see any pictures or links, haha

    Will there be support for the first version of Bangle? My second one is still on the way :(

    You have made great apps! I mainly use Multi Clock watchface. Also launcher. Navigator is great! Thank you :)

    I also tested notifications for the iPhone and they worked, although not stable :)

  • As an idea: you can write bAngle.js in the place where it write brAun
    It would be great in the same font: in capital letters, but for A to be higher than the rest.

  • Thanks for the kind words. There is a version of the Braun face for the original Bangle:

    The nice thing about the brAun logo is that the A is the middle letter and can be centred in the watch. bAngle would look asymmetric.

    BTW: The Apple Notification app is now obsolete as Gordon has provided an IOS Integration app. It did work well with a fimware hack but was flaky without it:(
    @Gordon - should I do a PR to remove the ANCS app?

  • That's a good point - thanks! I've just removed it

  • Cool! But what's with the second hand? For some reason it blinks.


    1 Attachment

  • The blink is because the Bangle 1 screen is not buffered so you are seeing the delay between the second hand being deleted and then redrawn. It is noticeable because in this face, the second hands overlap the numbers so they have to be redrawn on every tick. There is now a new version (in the same place) which reduces the delay by only redrawing the 4 numbers that are actually overlapped by the second hand. A better approach would be to be to use an image buffer but with 4 colours this would need about 200*200*2/8 = 10K bytes which should fit but would take most of free memory.

  • And I thought why such a difference with other analog clocks (: Yes, it's better now!

  • Post a reply
    • Bold
    • Italics
    • Link
    • Image
    • List
    • Quote
    • code
    • Preview
About

Analog Clocks - programming hint

Posted by Avatar for jeffmer @jeffmer

Actions