Better code needed for hands on watchface

Former Member
Former Member
Hi,

I'm having trouble making sharp, readable hands on a watchface.
Can anyone send me a better version, maybe with polygons if that is better. I really cannot get the hang of polygons as I don't understand the command.
Or perhaps steer me in the right direction ?
Thank you in advance

I've been using this code :

// Define variables
var center_x;
var center_y;
var minute_radius;
var hour_radius;
var seconds_radius;
var TWO_PI = Math.PI * 2;
var ANGLE_ADJUST = Math.PI / 2.0;
var showSeconds=false;
var now = Time.now();
var clockTime = Sys.getClockTime();
var hour = clockTime.hour;
var minute = clockTime.min;
var seconds = clockTime.sec;
var hour_fraction = minute / 60.0;
var minute_angle = hour_fraction * TWO_PI;
var seconds_angle = seconds * TWO_PI / 60.0;
var hour_angle = (((hour % 12) / 12.0) + (hour_fraction / 12.0)) * TWO_PI;
seconds_angle -= ANGLE_ADJUST;
minute_angle -= ANGLE_ADJUST;
hour_angle -= ANGLE_ADJUST;

// draw the hour hand
dc.setPenWidth(9); hour_radius = 60;
dc.setColor(Gfx.COLOR_YELLOW,Gfx.COLOR_TRANSPARENT);
dc.drawLine(center_x, center_y,
(center_x + hour_radius * Math.cos(hour_angle)),
(center_y + hour_radius * Math.sin(hour_angle)));
dc.setPenWidth(5); hour_radius = 59;
dc.setColor(Gfx.COLOR_BLACK,Gfx.COLOR_TRANSPARENT);
dc.drawLine(center_x, center_y,
(center_x + hour_radius * Math.cos(hour_angle)),
(center_y + hour_radius * Math.sin(hour_angle)));
dc.setPenWidth(3); hour_radius = 50;
dc.setColor(Gfx.COLOR_WHITE,Gfx.COLOR_TRANSPARENT);
dc.drawLine(center_x, center_y,
(center_x + hour_radius * Math.cos(hour_angle)),
(center_y + hour_radius * Math.sin(hour_angle)));

// draw the minute hand
dc.setPenWidth(9); minute_radius = 95;
dc.setColor(Gfx.COLOR_YELLOW,Gfx.COLOR_TRANSPARENT);
dc.drawLine(center_x, center_y,
(center_x + minute_radius * Math.cos(minute_angle)),
(center_y + minute_radius * Math.sin(minute_angle)));
dc.setPenWidth(5); minute_radius = 94;
dc.setColor(Gfx.COLOR_BLACK,Gfx.COLOR_TRANSPARENT);
dc.drawLine(center_x, center_y,
(center_x + minute_radius * Math.cos(minute_angle)),
(center_y + minute_radius * Math.sin(minute_angle)));
dc.setPenWidth(3); minute_radius = 85;
dc.setColor(Gfx.COLOR_WHITE,Gfx.COLOR_BLACK);
dc.drawLine(center_x, center_y,
(center_x + minute_radius * Math.cos(minute_angle)),
(center_y + minute_radius * Math.sin(minute_angle)));

if (showSeconds) {
// draw the seconds hand
dc.setPenWidth(3); seconds_radius = 95;
dc.setColor(Gfx.COLOR_YELLOW,Gfx.COLOR_TRANSPARENT);
dc.drawLine(center_x, center_y,
(center_x + seconds_radius * Math.cos(seconds_angle)),
(center_y + seconds_radius * Math.sin(seconds_angle)));
dc.drawCircle((center_x + seconds_radius * Math.cos(seconds_angle)),
(center_y + seconds_radius * Math.sin(seconds_angle)),2);}
  • You can define the pre-transformed points however you want. If you want to make a rounded point, you'll have to create a more points along the edge of the arc as you see fit. If you need a full circle or disc, you can transform a single coordinate to represent the center of the circle, and then call drawCircle or fillCircle at that coordinate.

    Travis
  • Native watch faces don't use CIQ and can do things that CIQ watch faces can't (like display seconds all the time). They actually run on their own low power chip, BTW...

    Polygons, with a bunch of points would work for you want, with a bunch of math while doing so...

    OR, maybe draw it with the blunt end, and then use fillCircle() calls to round off the end? (I just saw Travis first posted the drawCircle() thing a few minutes back)
  • Former Member
    Former Member over 9 years ago
    Try sin cos position of circles

    This draws a circle on the position you wish.
    The parameters are :
    - 55 = length from the centrepoint (r)
    - sec = seconds (or choose min/hour/... )
    - center_x = calculated from width of display
    - center_y = calcultated from height of display

    sec = ( clockTime.sec / 60.0) * Math.PI * 2;
    var xh = 55*Math.sin(sec) ; var yh = -55*Math.cos(sec);
    dc.fillCircle(center_x+xh,center_y+yh,7);


    Hopes this helps you further.

    Greetings, Dirkvd001
  • Great!
    Thank you for your help guys!
  • Hi,
    Sorry to recover this, I have created this libreoffice spreadsheet as a helper of the process of hand design, thank you all!:cool:
  • I know this is an old post, but it was helpful, thanks Slight smile

    Perhaps this will help someone else:

    I had to add 0.5 to xh for the 30s position to be correct, otherwise it was off by a pixel on a Venu2. I think because it has a larger radius than the watches for which the Analog sample was written for, where I saw this adjustment. The adjustment throws off the 40s position by a pixel, which I think is less noticeable and unless you use a magnifier you probably wouldn't see it on a real device.

    Also, the Analog sample in the 6.4.2 sdk is missing this piece, so the second hand won't show when the app starts.

    function onShow() {
            _isAwake = true;
        }
  • I also noticed this thing everywhere where a full screen circle is involved. It kind of makes sense. The screens have a pair number of pixels in both dimensions. When you draw a circle using width/2, height/2 as the origin then you are half a pixel to the right and half a pixel down from the actual middle point.

  • I think this formula yields more accurate results. Credit to github.com/.../garmin-seaside for the formula. This is a shortened version, there's detailed explanation in his source code.

    private function drawSecDot(dc, seconds, radius) {
    var angle = (seconds * 6 + 270) * (Math.PI / 180);
    var x = Math.cos(angle) * radius;
    var y = Math.sin(angle) * radius;
    dc.drawLine(_devCenter, _devCenter, x + _devCenter, y + _devCenter);
    dc.fillCircle(x + _devCenter, y + _devCenter, 4);
    }

  • I also noticed this thing everywhere where a full screen circle is involved. It kind of makes sense. The screens have a pair number of pixels in both dimensions. When you draw a circle using width/2, height/2 as the origin then you are half a pixel to the right and half a pixel down from the actual middle point.

    The general solution to drawing a perfectly centred circle is to draw 4 circles, each one centred around one of the 4 pixels in the center of the screen. For me, this produces results pretty close to native circles.

    https://forums.garmin.com/developer/connect-iq/f/discussion/7660/dc-drawcircle-inside-screen-edge-even-numbered-screen-height-width/52001#52001

    I had to add 0.5 to xh for the 30s position to be correct

    I'm curious whether using fractional coordinates actually works? When I tried using fractional coordinates with FR245 and drawCircle(), it didn't work. Maybe it works with newer devices which have a GPU and built-in antialiasing, but I'm 100% it wouldn't work on older devices.

  • I think they get rounded up / down. I don't recall the exact number but adding 0.5 to it was enough for it to be rounded up to the expected x value in this case.

    I've also seen interesting results with drawing my own rectangles depending on whether the height / width is an even or odd number, e.g. being a pixel off, which I think is expected since you're in between whole numbers.