4 Datafield for Vivoactive HR

Former Member
Former Member
I would like to design the following for the Vivoactive HR. I am assuming I would use a datafield (would it be simple or complex ??)

Distance (km)
Steps per km (running total)
Steps per km (last km)
Cadence (steps per min)

I am able to use a Footpod.

I am new to Connect IQ .. so be patient.

I am ok with starting an activity .. though I would not keep it.

Wondering how I could capture that data from the device ??

I see I can use ActivityMonitor .. to get some of this data.

elapsedDistance for Distance km
Steps per Km .. not sure on this one. But I need a running total of steps for current km to be reset to zero for each km ran.

I am thinking that I can do this .. if I do about 182 steps/min cadence when running that is 3.03 per second. I know in Garmin Connect you can see the cadence in the file so I am sure that I can get the cadence from the device. So I would just keep a running total every second until it hits distance mod 1 and just retain that number and display it.

Steps per km (last km) .. would like to retain these numbers if I can on the device for future reference. Not sure if I can store this in a file on the device ? But I would like to retain them if I can.

Cadence .. not sure as it seems to reference RPM so seems it is for cycling ??

Here is a mock up of what I would like ..


  • For a datafield, compute() gets passed Activity.info, so the data is right there for you. (for step data, you need to also access ActivityMon, and you might have to add some logic that uses the data. Cadence is in Activity.info already)

    For a simple DF, you return a value, and it displays (see the sample in the SDK) as it also rotates what is returned.

    With a complex DF, you can display more than one thing at a time, by picking the proper font, etc. On the va-hr there are only 2 and 3 field layouts for DF's, but here's something where I display 4 values in a 2 field layout. (elapsedTime, distance, pace, altitude). You can of course draw extra lines if it's a complex DF

  • Former Member
    Former Member over 9 years ago
    Have a ? .... do I do all my calculations in Compute or OnUpdate ?

    When I try this in Compute .. I get an error (could not find symbol cadence), it does not like cadence at all. But in the datafield sample it is exactly the same.

    CD = info.cadence;
    DST = info.elapsedDistance;

    How do I return more than one value .. ?
  • compute() is where you calculate the data you want to display in onUpdate(). compute() is called even if the DF isn't visible (say you're on another data screen).onUpdate() is called when the DF is visible.

    In activity.Info, it's "currentCadence" and not "cadence"
  • Former Member
    Former Member over 9 years ago
    compute() is where you calculate the data you want to display in onUpdate(). compute() is called even if the DF isn't visible (say you're on another data screen).onUpdate() is called when the DF is visible.

    In activity.Info, it's "currentCadence" and not "cadence"


    Thank you .. that would do it. I will see how far I can get.
  • Former Member
    Former Member over 9 years ago
    I didn't get too far ..

    So I have 4 items in Compute .. I think I can do that.

    1) distance (easy) .. I think I am getting that.
    2) cadence (easy) .. I think I am getting that.

    Right now .. these are both null in the simulator. I see .. it is possible to use a FIT file .. which I have. But I do not know how to simulate that in the simulator ? Can I use that to simulate real life data ??

    3) steps per current km .. calculated and I think I got this one.
    4) steps per last completed km .. calculated and I think I got this one.

    I see that it is doing the compute every second.

    But how do I return these 4 items to onUpdate ? Lets say they are A,B,C and D .. and I want to display all 4 in onUpdate.

    Sorry for the questions .. but I am getting there.
  • I didn't get too far ..

    So I have 4 items in Compute .. I think I can do that.

    1) distance (easy) .. I think I am getting that.
    2) cadence (easy) .. I think I am getting that.

    Right now .. these are both null in the simulator. I see .. it is possible to use a FIT file .. which I have. But I do not know how to simulate that in the simulator ? Can I use that to simulate real life data ??


    Ok, something else to note here. On real devices, those values will initially be null, and in compute(), you need to check for that before you use it. so for elapsedDistance, I do this for example:
    if(info.elapsedDistance!=null) {
    if(settings.distanceUnits==Sys.UNIT_STATUTE) {
    distance=(info.elapsedDistance* 0.000621371).format("%0.2f")+" mi";
    } else {
    distance=(info.elapsedDistance/1000).format("%.2f")+" km";
    }
    }


    In the simulator, yes, you use Simulation>Fit Data (simulate data is interesting for some things, but I often playback a .fit I've saved).
    For the things you use "steps" for, Simulation>Activity Monitoring>Steps per minute.

    I see that it is doing the compute every second.

    Yes.
    But how do I return these 4 items to onUpdate ? Lets say they are A,B,C and D .. and I want to display all 4 in onUpdate.


    for a Complex DF, save what you want in a variable within the class in compute(), and then in onUpdate(), just display. Using the code above I posted for elapsedDistance for compute, I have this in onUpdate():
    dc.drawText(width/2,height/2,Gfx.FONT_SMALL,distance,Gfx.TEXT_JUSTIFY_CENTER);

    for example.

    And "distance" is a variable in the class defined as:
    hidden var distance="";
  • Former Member
    Former Member over 9 years ago
    Ok .. thank you.

    Of note .. I am actually not using steps from the device at all. I am just calculating the steps per second from the cadence number and then doing a running total for the 1 km distance. The reason .. I do not think that the steps is all that accurate on these devices. I believe that the cadence / steps information from the footpod is more accurate.

    It would be nice if Garmin added the steps per lap in Garmin Connect in the splits area (in addition to just steps per activity) in order to give a more precise stride length.

    I know .. I like steps. :cool:
  • Former Member
    Former Member over 9 years ago
    We are making progress .. and thank you.

    EDIT .... I did manage to run a FIT file .. that will help a lot. I see I need to make one change or two but that is ok.

    So I need to have a layout of 2 fields (with 2 data items on top and 2 on bottom) but as you can see .. not happening.



    I will draw some lines as well to separate the data fields. I am ok with 3 lines. That is just cosmetic. I will do that after the data is on the screen.

    Code is as below ...

    //! Set your layout here. Anytime the size of obscurity of
    //! the draw context is changed this will be called.
    function onLayout(dc)
    {
    var obscurityFlags = DataField.getObscurityFlags();

    // Top left quadrant so we'll use the top left layout
    if (obscurityFlags == (OBSCURE_TOP | OBSCURE_LEFT))
    {
    View.setLayout(Rez.Layouts.TopLeftLayout(dc));

    // Top right quadrant so we'll use the top right layout
    }
    else if (obscurityFlags == (OBSCURE_TOP | OBSCURE_RIGHT))
    {
    View.setLayout(Rez.Layouts.TopRightLayout(dc));

    // Bottom left quadrant so we'll use the bottom left layout
    }
    else if (obscurityFlags == (OBSCURE_BOTTOM | OBSCURE_LEFT))
    {
    View.setLayout(Rez.Layouts.BottomLeftLayout(dc));

    // Bottom right quadrant so we'll use the bottom right layout
    }
    else if (obscurityFlags == (OBSCURE_BOTTOM | OBSCURE_RIGHT))
    {
    View.setLayout(Rez.Layouts.BottomRightLayout(dc));

    // Use the generic, centered layout
    }
    else
    {
    View.setLayout(Rez.Layouts.MainLayout(dc));
    var labelView = View.findDrawableById("label");
    labelView.locY = labelView.locY - 16;
    var valueView = View.findDrawableById("value");
    valueView.locY = valueView.locY + 7;
    }

    View.findDrawableById("label").setText(Rez.Strings.label);
    return true;
    }



    function onUpdate(dc)
    {

    var width = dc.getWidth();
    var height = dc.getHeight();

    // Set the background color
    View.findDrawableById("Background").setColor(getBackgroundColor());

    // Set the foreground color and value
    var value = View.findDrawableById("value");
    if (getBackgroundColor() == Gfx.COLOR_BLACK)
    {
    value.setColor(Gfx.COLOR_WHITE);
    dc.setColor(Gfx.COLOR_WHITE, Gfx.COLOR_BLACK);
    }
    else
    {
    value.setColor(Gfx.COLOR_BLACK);
    dc.setColor(Gfx.COLOR_BLACK, Gfx.COLOR_WHITE);
    }

    // Call parent's onUpdate(dc) to redraw the layout

    View.onUpdate(dc);


    dc.drawText(width/2,30,Gfx.FONT_SMALL,"Distance: " + DST.format("%.2f") + " km",Gfx.TEXT_JUSTIFY_CENTER); // Distance
    dc.drawText(width/2,60,Gfx.FONT_SMALL,"Steps/Km: " + cadenceTotalThisKm.format("%4d"),Gfx.TEXT_JUSTIFY_CENTER); // Steps per Km
    dc.drawText(width/2,120,Gfx.FONT_SMALL,"Steps/LastKm: " + cadenceTotalLastKm.format("%4d"),Gfx.TEXT_JUSTIFY_CENTER); // Steps - Last Km
    dc.drawText(width/2,150,Gfx.FONT_SMALL,"Cadence: " + CD.format("%2d") + "spm",Gfx.TEXT_JUSTIFY_CENTER); // Cadence

    }
  • Ok, a few things here...

    When you have a 2 (or more) field layout in the sim, your one DF is is displayed in all the "spots" For a two field layout, you pretty much have to have two different CIQ data field apps to have the top different than the bottom (and 2 CIQ data fields is the max when used in a native app).

    You could use the height of the dc to see if the same DF was on top or bottom though, as top DF has a height of 102, and the bottom one, 101, and use the same .prg for both, but it would still be "two CIQ datafields" on the watch but only one .prg)

    The obscurity flags on the va-hr don't come into play, as that's really more for a round or semi-round display thing, where parts of the DF can't be used, as they are "Obscured" by roundness. The va-hr DF's are simple rectangles.

    Your "y" for the drawText() calls can't be greater than the height of the dc the data fields is in if you want to see it.. (see dc.getHeight() to get the dc height...)
  • Former Member
    Former Member over 9 years ago
    Ok, a few things here...

    When you have a 2 (or more) field layout in the sim, your one DF is is displayed in all the "spots" For a two field layout, you pretty much have to have two different CIQ data field apps to have the top different than the bottom (and 2 CIQ data fields is the max when used in a native app).

    You could use the height of the dc to see if the same DF was on top or bottom though, as top DF has a height of 102, and the bottom one, 101, and use the same .prg for both, but it would still be "two CIQ datafields" on the watch but only one .prg)

    The obscurity flags on the va-hr don't come into play, as that's really more for a round or semi-round display thing, where parts of the DF can't be used, as they are "Obscured" by roundness. The va-hr DF's are simple rectangles.

    Your "y" for the drawText() calls can't be greater than the height of the dc the data fields is in if you want to see it.. (see dc.getHeight() to get the dc height...)


    I guess I am confused as I understood some of that. Is this a simulator thing only .. or can I not do what I want to do ?
    For now I am going to squeeze the 4 items into the half of the screen for testing purposes. I have one thing to fix I see .. the rest of the data is fine.

    Is this different than what I am trying to do ?

    https://apps.garmin.com/en-US/apps/a37dc002-8edc-43db-9496-4117d6d3660e