The arc graph?

I am a beginner and need help. How do I draw an arc graph? The function must be similar to clock hands, but I do not know how to keep rendered all the steps. Someone help me? How do I edit this?function drawArc(dc, angle, length, width)
{
var coords = [[-width, -(length)*8/10], [-width, -(length)],[width, -length],[width, -(length)*8/10]];
var result = new [coords.size()];

var centerX = dc.getWidth()*3/10;
var centerY = 130;

var cos = Math.cos(angle);
var sin = Math.sin(angle);


for (var i = 0; i < coords.size(); i +=1 )
{
var x = (coords[0] * cos) - (coords[1] * sin);
var y = (coords[0] * sin) + (coords[1] * cos);
result= [ centerX+x, centerY+y];
}

dc.fillPolygon(result);

}[/CODE]
  • Drawing an arc requires you to build up an array of points and render them. The above code transforms points from one coordinate system to another, which is similar, but very different.

    There are a few approaches for how you could do this. The simple way involves pre-building a fixed number of points along the arc and then rendering them as a series of smaller polygon primitives to avoid the 64 polygon limit. The more complicated way is to generate the points on-the-fly so that they are evenly spaced, and then render them. The technique you use depends on what you need. I've been using both techniques, but I think pre-computing them is simpler.

    Here is some code for generating an array of points for an arc.

    //! Generate an array of points on an arc sweeping phi radians starting at theta
    function makeArcPoints(n, theta, phi) {
    var points = new [n + 1];
    for (var i = 0; i <= n; ++i) {
    var radians = theta + (i * phi) / n;

    var px = Math.sin(radians);
    var py = -Math.cos(radians);

    points= [ px, py ];
    }

    return points;
    }
    [/code]

    The parameter theta is the initial angle from the 12 o'clock position, and phi is the angle from theta.

    // create points for an arc of 20 segments that sweeps from 9 o'clock to 3 o'clock...
    points = makeArcPoints(20, -Math.PI / 2, Math.PI);

    // create points for an arc of 20 segments that sweeps from 9 o'clock back to 3 o'clock (along the bottom)...
    points = makeArcPoints(20, -Math.PI / 2, -Math.PI);


    Now that you have the arc points, you can build the polygons and render them. To do this, you need to know the center of the arc, the inner and outer radiuses, and which segments you want to draw. In the below code I've pulled out the allocation of the coords array so I don't need to repeatedly allocate them every time I need to draw an arc.

    // just for efficiency
    hidden var coords = [
    [ 0, 0 ],
    [ 0, 0 ],
    [ 0, 0 ],
    [ 0, 0 ],
    [ 0, 0 ]
    ];

    function fillArcFromPoints(dc, points, cx, cy, r1, r2, min, max) {
    for (var i = min + 1; i <= max; ++i) {
    coords[0][0] = cx + (points[i - 1][0] * r1);
    coords[0][1] = cy + (points[i - 1][1] * r1);

    coords[1][0] = cx + (points[i - 1][0] * r2);
    coords[1][1] = cy + (points[i - 1][1] * r2);

    coords[2][0] = cx + (points[0] * r2);
    coords[2][1] = cy + (points[1] * r2);

    coords[3][0] = cx + (points[0] * r1);
    coords[3][1] = cy + (points[1] * r1);

    coords[4][0] = coords[0][0];
    coords[4][1] = coords[0][1];

    dc.fillPolygon(coords);
    }
    }
    [/code]

    If you had the created the arc points as above, and wanted to render it as a 20 segment progress bar, you'd do something like this...

    function onUpdate(dc) {
    dc.setColor(Gfx.COLOR_BLACK, Gfx.COLOR_BLACK);
    dc.clear();

    var cx = dc.getWidth() / 2;
    var cy = dc.getHeight() / 2;

    // 10 pixel radius, touches edge of screen
    var r2 = (cx < cy ? cx : cy);
    var r1 = r2 - 10;

    // given percent0to1, round to the correct number of segments to fill.
    var n = (percent0to1 * points.size()).toNumber();

    dc.setColor(Gfx.COLOR_RED, Gfx.COLOR_RED);
    fillArcFromPoints(dc, points, cx, cy, r1, r2, 0, n);

    dc.setColor(Gfx.COLOR_DK_GRAY, Gfx.COLOR_DK_GRAY);
    fillArcFromPoints(dc, points, cx, cy, r1, r2, n, points.size() - 1);
    }


    Travis
  • Also, if you are going to be drawing many arcs, it might make sense to only have one array of points that sweeps the arc all the way around, and then just render the points that you want.
  • Former Member
    Former Member over 10 years ago
    If you don't have to many arcs you could also draw a circle, then set the dc-color to match the background and draw a smaller circle with the same center. And then cut out the pieces you don't want with a polygon.
    Or have a look at the source from this watch face: https://apps.garmin.com/en-US/apps/5b58da19-6b09-4bd2-b48a-a830c0b515f4
  • If you don't have to many arcs you could also draw a circle, then set the dc-color to match the background and draw a smaller circle with the same center. And then cut out the pieces you don't want with a polygon.
    Or have a look at the source from this watch face: https://apps.garmin.com/en-US/apps/5...a-a830c0b515f4

    Yes I know it - I studied the source code, but I need exactly this:
    https://apps.garmin.com/en-US/apps/a0718b3b-7eef-4bf2-b6ab-299d7f78be62

    I want it used for a small progress bar.
  • The code I posted above is based on the code from that watch face.
  • Yes I know. Thank you very much. I'll try it tomorrow. :)
  • I'm sorry, but somehow I do not understand. Could you please create a complete and functional code? For example, for a value of 80 from 100? It is easier for me to examine working code.
  • I'm not sure what you don't understand. The provided code is 99% of a working example. Plug it into a class derived from Ui.View, declare a variable named percent0to1 that has the value .8, and update the call to makeArcPoints() to have the appropriate number of segments for your usage.
  • using Toybox.WatchUi as Ui;
    using Toybox.Graphics as Gfx;
    using Toybox.System as Sys;
    using Toybox.Lang as Lang;

    class arcView extends Ui.WatchFace {


    //! Generate an array of points on an arc sweeping phi radians starting at theta
    function makeArcPoints(n, theta, phi) {
    var points = new [n + 1];
    for (var i = 0; i <= n; ++i) {
    var radians = theta + (i * phi) / n;

    var px = Math.sin(radians);
    var py = -Math.cos(radians);

    points= [ px, py ];
    }

    return points;
    }

    // just for efficiency
    hidden var coords = [
    [ 0, 0 ],
    [ 0, 0 ],
    [ 0, 0 ],
    [ 0, 0 ],
    [ 0, 0 ]
    ];

    function fillArcFromPoints(dc, points, cx, cy, r1, r2, min, max) {
    for (var i = min + 1; i <= max; ++i) {
    coords[0][0] = cx + (points[i - 1][0] * r1);
    coords[0][1] = cy + (points[i - 1][1] * r1);

    coords[1][0] = cx + (points[i - 1][0] * r2);
    coords[1][1] = cy + (points[i - 1][1] * r2);

    coords[2][0] = cx + (points[0] * r2);
    coords[2][1] = cy + (points[1] * r2);

    coords[3][0] = cx + (points[0] * r1);
    coords[3][1] = cy + (points[1] * r1);

    coords[4][0] = coords[0][0];
    coords[4][1] = coords[0][1];

    dc.fillPolygon(coords);
    }
    }
    // create points for an arc of 20 segments that sweeps from 9 o'clock to 3 o'clock...
    points = makeArcPoints(20, -Math.PI / 2, Math.PI);

    // create points for an arc of 20 segments that sweeps from 9 o'clock back to 3 o'clock (along the bottom)...
    points = makeArcPoints(20, -Math.PI / 2, -Math.PI);



    function onUpdate(dc) {
    dc.setColor(Gfx.COLOR_BLACK, Gfx.COLOR_BLACK);
    dc.clear();

    var cx = dc.getWidth() / 2;
    var cy = dc.getHeight() / 2;

    // 10 pixel radius, touches edge of screen
    var r2 = (cx < cy ? cx : cy);
    var r1 = r2 - 10;

    // given percent0to1, round to the correct number of segments to fill.
    var n = (.8 * points.size()).toNumber();

    dc.setColor(Gfx.COLOR_RED, Gfx.COLOR_RED);
    fillArcFromPoints(dc, points, cx, cy, r1, r2, 0, n);

    dc.setColor(Gfx.COLOR_DK_GRAY, Gfx.COLOR_DK_GRAY);
    fillArcFromPoints(dc, points, cx, cy, r1, r2, n, points.size() - 1);
    }

    } [/CODE]

    there is a lots of errors.. I don't know how to fix it
  • So basically you're wanting me to write all of the code for you. You pretty clearly don't have a grasp of what the code I provided does, so you aren't learning by reading actual code.

    I'll help, but I'm not going to do it for you. To start, you should only need to declare points. You only need one call to makeArcPoints() and you should put it into your classes initialize() method.