ただ、走るだけ。いつまでも

ただただ走ってます。いつかはサブ3.5。

初めてのConnectIQアプリ〜データフィールド構築compute(info)編〜

みなさんおつかれさまです。

 

今朝は朝ランに行ってきました。4時代は涼しくて良いですね。

 

にほんブログ村 その他スポーツブログ マラソンへ
にほんブログ村 

 

☆★☆

 

これまでの拙い軌跡です。

【予告編】ガーミンVivoactive3を自分でカスタマイズしたいぞ - ただ、走るだけ。いつまでも

初めてのConnectIQアプリ〜セットアップ編〜 - ただ、走るだけ。いつまでも

初めてのConnectIQアプリ〜サンプルプロジェクトの実行編〜 - ただ、走るだけ。いつまでも

ビルドアップ走から、初めてのConnectIQアプリ〜新規プロジェクトでMonkeyC編〜 - ただ、走るだけ。いつまでも

 

さて、ConnectIQでのデータフィールド構築。最初は平均ペースと全体距離を横に並べて表示するようなものを作ってみたいと思います。まずは、情報を保持。

1 プロジェクトの構成

前回新規プロジェクトとして作ったのを見てみると、クラスは3つ(.mcの拡張子)、その他にリソースファイルと設定ファイルが見えます。データフィールドの場合、修正するのはソースコードのうち、[プロジェクト名]+View.mcとリソースファイルのxmlのようです。

f:id:yoneba_1717:20180708155444p:plain

2 データフィールドのViewクラスの構成

まず、Viewクラスの構成です。新規プロジェクトで出来てきたメソッドは4つで、全てオーバーライドしてあるようです。

どうも、基本的な作りとしては、onLayout()で表示場所を決めて、compute()で表示項目を作って、onUpdate()で表示するのが流れのようです。非表示の時にはcompute()だけが1秒間隔で呼ばれ、表示すると1回onLayout()が呼ばれ、その後は1秒おきにcompute()とonUpdate()が呼ばれる仕様です。なんか、データフィールドだと、onUpdate() に全部書き込んでもいいような気がしますが、まあ従いますか。

onUpdate()とcompute()の処理順に保証がないので、onUpdate()で使用する変数は初期化が必要ですね。「ぬるぽ」「ガッ」(古すぎる)が出る可能性がありそうです。

さて、できたメソッドにコメントがくっついてきました。読んでおきましょう。

    // 初期化のメソッド

function initialize() {

     

    // 

    // レイアウト情報をここにセット。サイズが変わったり表示場所が変わると呼ばれるぜ

function onLayout(dc) {

     

    //ここで引数で渡すinfoにはトレーニングの全情報が入ってる。このメソッドで計算して、

    // ローカルに値を保存しておくんだぜ。

    // おっと、気をつけておいてもらいたいんだが、表示用にonUpdate()メソッドを用意しているが、

    // この2つは非同期だからな。必ずしもcompute()がonUpdate()より先に呼ばれる保証は無いぜ。

function compute(info) {

 

    // ここで、さっき計算した値を表示するんだ。このメソッドはデータフィールドが表示されている

    // 時だけ、1秒に1回くらい呼ばれるからそのつもりでいろよ。

function onUpdate(dc) {

       コメントは、超意訳です。保証はありません。

 

3 compute(info)をカスタマイズしてみる

では、compute(info)をカスタマイズして、平均ペースと全体距離を保持することにしましょう。

まず、変数宣言。自分しか使わないので、hidden(=private)で宣言しておきます。

class Yone5kmLapDataFieldView extends Ui.DataField {

 

    hidden var averagePace=0.0f;

    hidden var distance=0.0f;

  とりあえずは、新規プロジェクトでくっついてきたコードはそのまま置いておきます。 

compute(info)の中を変更していきます。

まあ、基本的な作り方は、引数でくっついてきたinfo(=Activity.info)から値を取り出すってことですよね。

今日は、infoから平均ペースと走った距離を引っこ抜いて変数に格納するだけですね。

と思ってたんです。

Activity.infoの中身

 infoから値を取り出す時は、特にgetterがあるわけでは無いようなので、info.currentHeartRateのように、直接参照するようです。

どうも、調べてみると、同じ方式でそれぞれの値に代入もできそうです。そんなことを前提にしてもぶち壊しになりそうですので、オススメしません。

 

ガーミン公式から

Class: Toybox::Activity::Info — Connect IQ SDK

日本語(一部)ウィキ

www54.atwiki.jp

これを見てみると、ペースって存在しない(^_^;)

自分で作らないといけないみたいです。

アクティビティの平均ペースと全体距離をインスタンス変数に保持

では先に距離を取り出しましょう。どうも該当するのは、elapsedDistanceのようです。

        //全体距離を抽出します。

        if(info has :elapsedDistance){

            if(info.elapsedDistance != null){

               distance = info.elapsedDistance;

            } else {

               distance = 0.0f;

            }

         }

使う前にnullチェックを入れます。その後に、infoからelapsedDistanceを取り出します。

 

次にペースを出すようにしなきゃいけないんですが、ペースは無いので、スピードの逆数で作りましょう。

ペース(sec/km)=1/(スピード(m/sec)/1000)

もちろん、経過時間(msec)/経過距離(m)でも出せます。(むしろこちらの方が誤差が少なそう)

これを作っておきます。

infoにaverageSpeedがあったので、これを元にして、逆数を計算してセットします。

秒速0.27m未満はkmあたり1時間(3,600秒/km)とします。これを停止していると定義しておきます。まあ、止まってますよね。

         //全体ペースをセットします。

         if(info has :averageSpeed){

            if(info.averageSpeed != null){

                if(info.averageSpeed > 0.27){ //1秒あたり27cm以上の時だけ計測

                   averagePace = 1 /(info.averageSpeed/1000);//1000はmからkmへ変換

                } else {

                   averagePace = 3600.0f; //秒あたり27cm未満の遅すぎる時は1時間/kmで。

                }

            } else {

               averagePace = 0.0f;

            }

         }

まあ、これで数値は出てきました。

次に、表示しやすくなるよう加工します。

まず、ペースの小数点以下を丸めるため、四捨五入しておきます。四捨五入は、Toybox.Math.round()です。ちなみに切上げはceil(),切り捨てはfloor()です。なんとなく分かりますよね。

フルパスで書くのは面倒なので、using句をつけておきます。

using Toybox.Math:

さらに、表示する時に分と秒を分けておきます。インスタンス変数宣言部をこのように変えます。

class Yone5kmLapDataFieldView extends Ui.DataField {

 

    hidden var averagePaceMinute=0;

    hidden var averagePaceSecond=0;

    hidden var distance=0.0f;

先ほど計算したペースは秒で出てきたので、これを60で割った商が分を示し、割った余りが秒を示しますので、それぞれを格納しておきます。

剰余演算子(%)は、整数型で無い場合は、答えが出ないそうです。計算元にtoNumber()を付けて、整数型にしておきます。

以上の加工を入れたcompute()関数はこんな感じで出来上がりです。

    function compute(info) {

 

        //全体距離を抽出します。

        if(info has :elapsedDistance){

            if(info.elapsedDistance != null){

               distance = info.elapsedDistance;

            } else {

               distance = 0.0f;

            }

         }

 

         //全体ペースをセットします。

         if(info has :averageSpeed){

            if(info.averageSpeed != null){

          //1秒あたり27cm未満。まあ、止まっている状態の時以外に計算

                if(info.averageSpeed > 0.27){ 

           //1000はmからkmへの変換.toNumber()で整数型に変換

                  var averagePace =Math.round( 1 / info.averageSpeed * 1000 )

                      .toNumber(); 

                  averagePaceMinute = averagePace / 60 ;//全体秒を60で割った商は分

                  averagePaceSecond = averagePace % 60 ;//全体秒を60で割った剰余は秒

                } else {

                   averagePaceMinute = 60; //遅すぎる時は60分/kmで止めておく。

                   averagePaceSecond = 0;

                }

            } else {

               averagePaceMinute = 0;

               averagePaceSecond = 0;

            }

         }

    }

 

とりあえずコンソールに出してみよう。

compute(info) の中にprintln()を入れて表示してみましょう。今はシミュレータには何も出ませんので、コンソールに表示させます。

 Sys.println("Distance "+distance+" averagePace "+averagePaceMinute+":"+averagePaceSecond+" averageSpeed "+info.averageSpeed);

 

f:id:yoneba_1717:20180709211310p:plain

 まあ、想定どおり表示されました。次は時計に表示させる準備をします。

 

はじめてのConnectIQプログラミング〜レイアウトを決める。 onLayout()の編集〜 - ただ、走るだけ。いつまでも

 

にほんブログ村 その他スポーツブログ マラソンへ
にほんブログ村