Current Pace DataField

Hi -

Im trying to create my own 3 fields Data field.
I would like HR | Cad | Pace as the 3 fields.

when I look a the documentation - it has a "currentPace" but when I use it in the Simulator, it will give me an error.

I've also seen how some others have done a Pace1min or Pace30Secs and such.
Am wondering how is this done?

is it that the timer is taken for say 30secs and then query the distance that has elapsed in those 30sec?
  • how come doing this give me a ConnectIQ error Exclamation mark on the DataField on the watch?


    using Toybox.WatchUi as Ui;
    using Toybox.Graphics as Gfx;

    class ThreeFieldsView extends Ui.SimpleDataField {

    //! Set the label of the data field here.
    function initialize() {
    label = "Dist | Cad | HR";
    }

    //! The given info object contains all the current workout
    //! information. Calculate a value and return it in this method.
    function compute(info) {
    var HR;
    var Cad;
    var Pace;
    var Dist;
    var ThreeFields;
    // See Activity.Info in the documentation for available information.
    HR = info.currentHeartRate;
    Cad = info.currentCadence;
    Dist = (info.elapsedDistance / 1000).format("%4.2f");
    //Pace = B/A;
    ThreeFields = Dist + " | " + Cad + " | " + HR;

    return ThreeFields;
    }

    }
  • When an activity is not recording, the fields of the Activity.Info structure are null. In the simulator, you have to either load up an existing .fit file or simulate a workout by clicking Simulate > FIT Data > .... Additionally, you need to write your code to avoid accessing a null object reference. i.e.,

    function compute(info) {
    var hr = "-";
    if (info.currentHeartRate != null) {
    hr = info.currentHeartRate.format("%d");
    }

    var cad = "-";
    if (info.currentCadence != null) {
    cad = info.currentCadence.format("%d");
    }

    var dist = "-";
    if (info.elapsedDistance != null) {
    // use distance unit setting to choose between km and mi
    if (Sys.getDeviceSettings().distanceUnits == Sys.UNIT_METRIC) {
    dist = (info.elapsedDistance / 1000).format("%4.2f");
    }
    else {
    dist = (info.elapsedDistance / 1609.34).format("%4.2f");
    }
    }

    return Lang.format("$1$ | $2$ | $3$", [ dist, cad, hr ]);
    }


    That said, chances are good that this data field will have too much data presented at once and it won't display all of it. In that case you'll need to think of some way to do what you want. Additionally, in the past there were problems returning objects of type String from compute(). I'm not sure if this has been fixed or not, but I do know that it will break on some older firmware versions.

    I think a better option would be to rotate through the fields, and only displaying one value at a time. This avoids the issues mentioned above, but does introduce the possibility of confusion since having a heart rate and cadence of 90 is entirely possible.
  • Thanks Travis.


    Many thanks for your help. I'll give it a go when i get to my laptop. (will be a while)

    1) the simpledatafield example in the SDK does cycle the values over time, but its not something which I fancy. I'm a little greedy and would like to have more fields at one glance.

    2) the format-ting was something of an issue I was battling last night. what was supposed to be simple, ended up pulling hair cos I kept getting the unexpected type error. (I tried toFloat(), toDouble() and format(%xxx) but wasn't getting anywhere. In the end, I'm not exactly sure what i did, but I did managed to get to my desired distance format which was X.XX. I'll have to check the code.

    3) I also tried to do the check if it's a "null" much like the code in the simpledatafield example.

    4) at the end, I discarded the pace at 1min or such and settled w/ Distance for the time being, until i figure out how to get a 30Sec datafield pace. (does anyone have a clue how it's done? I've not been able to wrap my head around that yet)



    5) if you see the picture, notice that on one of them, the fields are "BOLDED" and the rest are not. I have no clue how come it is like such. I don't see any doc / examples whereby one can manipulate the character's sizes or bold or colour much like the Gfx.COLOR_XXX command/code

    These 2 apps are doing what I would like to do, but the fields are not per what I wanted, hence my attempt. :-p

    https://apps.garmin.com/en-US/apps/a424c8ea-2b07-431b-9db4-a204791c3285 (SpeedPlus)
    https://apps.garmin.com/en-US/apps/a145a436-95fb-43aa-a2b8-85c55de9ebed (runField)
  • 3) I also tried to do the check if it's a "null" much like the code in the simpledatafield example.

    If my understanding of the original problem is correct, then the null check should have fixed the problem. If you create a text file in Garmin/APPS/LOGS named CIQ_LOG.txt, crashes will be logged to that file when they occur. This can be useful for debugging device problems.

    4) at the end, I discarded the pace at 1min or such and settled w/ Distance for the time being, until i figure out how to get a 30Sec datafield pace. (does anyone have a clue how it's done? I've not been able to wrap my head around that yet)

    You have to determine the distance travelled and the amount of time elapsed. With a data field you get one data sample every second. If you keep an array of 30 elements you will can store the last 30 seconds worth of distance samples. If you keep track of the last position you inserted into, and the number of elements in the array that have been used, you can keep a moving sum of the distances traveled. Something like the following untested code should get you in the right area...

    // array of distances traveled in each second of the past N seconds
    var history;

    // sum of the distances traveled in the past N seconds
    var sum_of_samples;

    // number of seconds for which we have data in `history'
    var number_of_samples;

    // location for next insert into `history' array
    var next_sample_idx;

    // cache so we can determine the distance traveled on the next tick
    var prev_distance;

    function initialize() {
    history = new [30];

    for (var i = 0; i < history.size(); ++i) {
    history = 0;
    }

    sum_of_samples = 0;
    number_of_samples = 0;
    next_sample_idx = 0;
    prev_distance = null;
    }

    function compute(info) {
    if (info.currentDistance == null) {
    return "?"; // just for testing. you'll want something better.
    }
    else if (prev_distance == null) {
    prev_distance = info.currentDistance;
    }

    // subtract the oldest sample from our moving sum
    sum_of_samples -= history [next_sample_idx];

    // calculate the distance traveled since the last call
    history [next_sample_idx] = info.currentDistance - previous_distance;

    // add the newest sample to our moving sum
    sum_of_samples += history [next_sample_idx];

    // record the previous data point so we can calculate the distance travelled
    // on the next call.
    previous_distance = info.currentDistance;

    // advance to the next sample, and wrap around to the beginning
    next_sample_idx = (next_sample_idx + 1) % history.size();

    // keep track of how many samples we've accrued
    if (number_of_samples < history.size()) {
    ++number_of_samples;
    }

    // return the average of the last N seconds
    return (sum_of_samples / number_of_samples).format("%0.2f);
    }
    [/code]

    5) if you see the picture, notice that on one of them, the fields are "BOLDED" and the rest are not. I have no clue how come it is like such. I don't see any doc / examples whereby one can manipulate the character's sizes or bold or colour much like the Gfx.COLOR_XXX command/code[/CODE]
    When you implement a simple data field, you have no control over how the text is drawn. I'm guessing that you're running into the problem I mentioned above. i.e., you are trying to display too much text in such a small space, so the system opts to use a smaller font in order to display it all. If you want more control over the presentation, then you need to implement Ui.DataField and do the rendering part yourself.
  • Former Member
    Former Member over 10 years ago
    When you implement a simple data field, you have no control over how the text is drawn. I'm guessing that you're running into the problem I mentioned above. i.e., you are trying to display too much text in such a small space, so the system opts to use a smaller font in order to display it all. If you want more control over the presentation, then you need to implement Ui.DataField and do the rendering part yourself.


    This could very well be what you are seeing. The device will select the largest native font that can display the values returned with that will fit the data into the field.

    The other thing to look out for is character availability. It looks like the data you are showing might fit with a slightly larger font, but the largest fonts on our devices only contain the characters needed to display numbers. The '|' character you are using forces the device to use a font that contains all characters, which excludes the fonts the native data fields use to display data.
  • This could very well be what you are seeing. The device will select the largest native font that can display the values returned with that will fit the data into the field.

    The other thing to look out for is character availability. It looks like the data you are showing might fit with a slightly larger font, but the largest fonts on our devices only contain the characters needed to display numbers. The '|' character you are using forces the device to use a font that contains all characters, which excludes the fonts the native data fields use to display data.


    Curious, it it a CIQ Simulator bug or something else.

    cad = info.currentCadence.format("%d")

    the format is not being honorned by the simulator.
    %d and %02d and %03d all results in 0 and not 00 or 000 in the simulator.

    When I put %03d in the code and sideload it, i get 000.

    for UI.Datafield, looks like I need to research this more. Nothing in the API Doc / SDK for me to reference.