「技術」カテゴリーアーカイブ

【ANDROID】【実質北海道一周】距離をファイルに保存する。

前回までの状況はこちら。

最新ソースはこちら(gitHub)

https://github.com/takishita2nd/AroundHokkaido

今回はGPSの情報から取得した移動距離合計をファイルに保存する処理を作成していきます。

クラスを一つ作成し、北海道一周関連の処理はこのクラスの中で処理していきたいと思います。

package com.takilab.aroundhokkaido

import java.io.File

class AroundHokkaido {
    private val filename: String = "distance.txt"
    private val citylist: CityList = CityList()
    private var totalDistance: Double = 0.0
    private val activity: MainActivity = SingletonActivity.GetActivity()

    fun getDistance(): Double{
        val file = File(activity.filesDir, filename)
        if(file.exists()){
            totalDistance = file.readText().toDouble()
        }
        return totalDistance
    }

    fun updateDistance(distance: Double): Double {
        val file = File(activity.filesDir, filename)
        if(file.exists()){
            totalDistance = file.readText().toDouble()
        }
        totalDistance += distance
        file.writeText("%.3f".format(totalDistance))
        return totalDistance
    }
}

まず、Android内でファイルアクセスするためには、MainActivityが必要です。

exists()でファイルの存在の有無を確認し、存在していれば、ファイルに保存済みのデータを読み込みます。

ファイルはテキストで保存されているので、Double型に変換して取得します。

保存するときは、桁数を指定しないと、指数表記でテキスト保存されてDouble型に変換出来ないという問題があるので、桁数を絞っています。

これをMainActivityでUIに表示させます。

    private lateinit var aroundHokkaido: AroundHokkaido

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        SingletonActivity.SetActivity(this);

        aroundHokkaido = AroundHokkaido()
        val distance: Double = aroundHokkaido.getDistance()
        distanceText.text = "%.3f".format(distance)

        requestPermission()

~中略~

                            override fun onResponse(call: Call, response: Response) {
                                var str = response!!.body!!.string()
                                val jsonObject = JSONObject(str)
                                val jsonArray = jsonObject.getJSONArray("Feature")
                                for (i in 0 until jsonArray.length()) {
                                    val jsonData = jsonArray.getJSONObject(i)
                                    val geometry = jsonData.getJSONObject("Geometry")
                                    val distance = geometry.getDouble("Distance")
                                    val totalDistance: Double = aroundHokkaido.updateDistance(distance)
                                    val mainHandler : Handler = Handler(Looper.getMainLooper())
                                    mainHandler.post(Runnable {
                                        distanceText.text = "%.3f".format(totalDistance)
                                    })
                                }
                            }

まず、AroundHokkaido()の中でMainActivityを使用していますので、AroundHokkaidoの初期化はSingletonActivity.SetActivity(this);の後に行わなければなりません。

で、AroundHokkaidoから現在の移動距離を取得しUIに表示します。

これがアプリ立ち上げたときの初期表示値です。

WebAPIのレスポンスを取得したときの処理も同様にします。

【北海道大戦】プレイヤーの行動処理を実装する。

前回までの状況はこちら。

最新ソースはこちら(gitHub)

https://github.com/takishita2nd/HokkaidoWar

以前作成したこれ。

これの「自分の行動」の部分を作成していきます。

            while (asd.Engine.DoEvents())
            {
                asd.Vector2DF pos = asd.Engine.Mouse.Position;

                switch (gameStatus)
                {
                    case GameStatus.SelectCity:
                        cycleProcessSelectCity(pos);
                        break;
                    case GameStatus.ActionEnemy:
                        cycleProcessActionEnemy(pos);
                        break;
                    case GameStatus.ActionPlayer:
                        cycleProcessActionPlayer(pos);
                        break;
                }

                if (asd.Engine.Mouse.LeftButton.ButtonState == asd.ButtonState.Push)
                {
                    switch (gameStatus)
                    {
                        case GameStatus.SelectCity:
                            onClickMouseSelectCity(pos);
                            break;
                        case GameStatus.ActionEnemy:
                            break;
                        case GameStatus.ActionPlayer:
                            onClickMouseActionPlayer(pos);
                            break;
                    }
                }
                asd.Engine.Update();
            }

分かりやすいようにサブルーチン化した。

        private void cycleProcessActionPlayer(asd.Vector2DF pos)
        {
            _battle.MyTurn(_player.City);
            _player.City.PaintAttackColor();
            var info = Singleton.GetInfomationWindow();
            info.ShowText(pos, "都市を選択してください\r\n");
            var cities = _player.City.GetLinkedCities();
            foreach(var city in cities)
            {
                if (city.IsOnMouse(pos))
                {
                    city.OnMouse(pos);
                    city.PaintDeffenceColor();
                }
                else
                {
                    city.ClearPaint();
                }
            }
        }
        public void MyTurn(City player)
        {
            if (lastDeffece != null)
            {
                lastDeffece.ClearPaint();
            }
            if (lastAttack != null)
            {
                lastAttack.ClearPaint();
            }
            var info = Singleton.GetGameProcessInfomation();
            info.ShowText(player.GetPosition(), string.Format("{0} turn {1} / {2} {3}", turn, cityCnt + 1, _cities.Count, player.Name));
        }

周期処理です。

まず、自分の都市を赤くします。

攻撃対象を選択するのですが、自分の都市の上にマウスカーソルがある場合のみ、その都市を青く表示します。

        private City _target = null;
        private void onClickMouseActionPlayer(asd.Vector2DF pos)
        {
            var info = Singleton.GetInfomationWindow();
            info.ShowText(pos, String.Empty);
            var cities = _player.City.GetLinkedCities();
            foreach (var city in cities)
            {
                if (city.IsOnMouse(pos))
                {
                    _target = city;
                    _battle.MyTrunAttack(_player.City, _target);
                    gameStatus = GameStatus.ShowResult;
                }
            }
        }
        public void MyTrunAttack(City player, City target)
        {
            var info = Singleton.GetGameProcessInfomation();
            var r = Singleton.GetRandom();
            lastAttack = player;
            lastDeffece = target;
            double attack = lastAttack.Population * (double)(r.Next(minRate, maxRate) / 10.0);
            double deffence = lastDeffece.Population * (double)(r.Next(minRate, maxRate) / 10.0);
            if (attack > deffence)
            {
                info.ShowText(lastAttack.GetPosition(), string.Format("{0} turn {1} / {2} {3}\r\ntarget {4} \r\n{5} vs {6}\r\nwin",
                    turn, cityCnt + 1, _cities.Count, lastAttack.Name, lastDeffece.Name, (int)attack, (int)deffence));
                lastAttack.CombinationCity(lastDeffece);
                _cities.Remove(lastDeffece);
                lastDeffece = null;
            }
            else
            {
                info.ShowText(lastAttack.GetPosition(), string.Format("{0} turn {1} / {2} {3}\r\ntarget {4} \r\n{5} vs {6}\r\nlose",
                    turn, cityCnt + 1, _cities.Count, lastAttack.Name, lastDeffece.Name, (int)attack, (int)deffence));
            }
        }

マウスクリック時の処理です。

マウスカーソルにある都市に対して攻撃処理を行います。

攻撃対象は記憶しておきます。

【ダイエット支援】【食事管理】データ詳細から入力処理を作成する。

前回までの状況はこちら。

最新ソースはこちら(gitHub)

https://github.com/takishita2nd/diet-mng

データ入力処理ですが、すでにデータ入力画面や一連の処理は作成してあるので、同じ要領でデータ詳細画面にもデータ入力画面への導線を作成します。

EatingDetailComponent.vue

<template>

<-- 中略 -->

            <p id="inputbutton">
                <button @click="onClickInput">データ入力</button>
            </p>

<-- 中略 -->

        <eating-input-dialog-component :show="showInputDialogContent" :date="date" :datehold=false @update="invokeUpdateList"></eating-input-dialog-component>

<-- 中略 -->

</template>

<script>
export default {

    //中略

    methods: {
        onClickInput: function() {
            this.showInputDialogContent = true;
        },
        invokeUpdateList: function() {
            this.updateList();
        },

【Android】【実質北海道一周】jsonを読み込ませる。

前回までの状況はこちら。

最新ソースはこちら(gitHub)

https://github.com/takishita2nd/AroundHokkaido

さて、前回作成したJsonファイルを、実際にAndroidアプリに読み込ませるのですが、

こちらの記事を参考にさせて頂きました。

https://qiita.com/Bluewind1997/items/c3f8e90e9fb19f47daee

assetsフォルダを作成して、その下にJsonファイルを作成して設置します。

あとはassetManagerを介せば、そのJsonファイルにアクセス出来ます。

ただ、assetManagerが使えるのはMainActivityだけ。

Androidのプログラミングでは、このMainActivityが重要でして、

Androidに関する重要な処理は、このMainActivityが無ければ使用できません。

なので、どこからでもMainActivityを使用できるように、シングルトンにしてしまえば良いのではと思いましたが、

Kotlinにはシングルトン(というか、staticクラス)という概念がないので、

ここだけJavaで書きました。

package com.takilab.aroundhokkaido;

import androidx.appcompat.app.AppCompatActivity;

public class SingletonActivity {
    private static AppCompatActivity _activity;

    public static void SetActivity(AppCompatActivity activity) {
        _activity = activity;
    }

    public static AppCompatActivity GetActivity(){
        return _activity;
    }
}

JavaとKotlinは混在できるんですね。

実際の開発現場では、どのようにMainActivityを扱っているんですかね?

このMainActivityを使ってJsonの読み出し。

package com.takilab.aroundhokkaido

class City(city: String, distance: Double) {
    val city: String = city
    val distance: Double = distance
}
package com.takilab.aroundhokkaido

import org.json.JSONException
import org.json.JSONObject
import java.io.BufferedReader
import java.io.InputStreamReader

class CityList {
    val cityList: ArrayList<City> = ArrayList()

    init{
        val activity: MainActivity = SingletonActivity.GetActivity() as MainActivity
        val assetManager = activity.resources.assets //アセット呼び出し
        val inputStream = assetManager.open("AroundHokkaido.json") //Jsonファイル
        val bufferedReader = BufferedReader(InputStreamReader(inputStream))
        val str: String = bufferedReader.readText() //データ
        try {
            val jsonObject = JSONObject(str)
            val jsonArray = jsonObject.getJSONArray("list")
            for (i in 0 until jsonArray.length()) {
                val jsonData = jsonArray.getJSONObject(i)
                val city: City = City(jsonData.getString("city"), jsonData.getDouble("distance"))
                cityList.add(city)
            }
        } catch (e: JSONException) {
            e.printStackTrace()
        }
    }
}
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        SingletonActivity.SetActivity(this);

        val cityList = CityList()
        for (city in cityList.cityList) {
            Log.d("Check", "${city.city} : ${city.distance}")
        }
2020-08-07 09:02:07.564 6520-6520/com.takilab.aroundhokkaido D/Check: 札幌 : 35.9
2020-08-07 09:02:07.564 6520-6520/com.takilab.aroundhokkaido D/Check: 小樽 : 20.1
2020-08-07 09:02:07.564 6520-6520/com.takilab.aroundhokkaido D/Check: 余市 : 15.9
2020-08-07 09:02:07.564 6520-6520/com.takilab.aroundhokkaido D/Check: 古平 : 6.4
2020-08-07 09:02:07.564 6520-6520/com.takilab.aroundhokkaido D/Check: 積丹 : 49.0
2020-08-07 09:02:07.564 6520-6520/com.takilab.aroundhokkaido D/Check: 神恵内 : 6.3
2020-08-07 09:02:07.564 6520-6520/com.takilab.aroundhokkaido D/Check: 泊 : 17.9
:
:

【北海道大戦】敵の行動処理を実装する。

最新ソースはこちら(gitHub)

https://github.com/takishita2nd/HokkaidoWar

以前作成したこれ。

これの「敵の行動」の部分を作成していきます。

敵を行動させるのであれば、すでに作成済みである、

    class Battle
    {
        public void NextTurn()

を実行すればいいでしょう。

では、次の状態遷移の条件である、「自分の都市の順番が来た場合」を考えます。

それを行うには、自分の都市と、次に実行する都市をBattleクラスから取得する処理があればいいでしょう。

    class Battle
    {
        public City GetActionCity()
        {
            return _cities[cityCnt];
        }
    class Player
    {
        private City _city;

        public City City { get { return _city; } }

        public Player(City city)
        {
            _city = city;
        }
    }
    class HokkaidoWar
    {
        public void Run()
        {
// 中略
            while (asd.Engine.DoEvents())
            {
                asd.Vector2DF pos = asd.Engine.Mouse.Position;

                switch (gameStatus)
                {
// 中略
                    case GameStatus.ActionEnemy:
                        if (_player.City.Equals(_battle.GetActionCity()))
                        {
                            gameStatus = GameStatus.ActionPlayer;
                        }
                        else
                        {
                            Thread.Sleep(100);
                            _battle.NextTurn();
                        }
                        break;
                }

                if (asd.Engine.Mouse.LeftButton.ButtonState == asd.ButtonState.Push)
                {
// 中略
                    switch (gameStatus)
                    {
                        case GameStatus.ActionEnemy:
                            break;
                    }
                }
                asd.Engine.Update();

マウスクリック処理は特にやることがないので、何もやる必要はありません。

【ラズパイ】【いろいろ計測モニター】HTTPサーバを実装する(修正)

すいません、

昨日のこれ、修正します。

何が問題なのかというと、複数のスレッドが同じデバイスにアクセスしている、と言うことです。

デバイスにアクセスするときには「一連のアクセス処理」が発生します。

温湿度計にアクセスする場合は、I2Cインターフェースを使用しているので、データの要求・応答に2つの端子にパルスパターンを送受信しているはずです。

この処理を複数のスレッドで同時に行った場合、正しくアクセス処理が行われない場合があります。

アクセス処理が競合しちゃうんですね。

これを防ぐために、こういったマルチスレッドのプログラミングでは「待ち合わせ処理」(一方の処理が完了するまで、もう一方の処理を待つ)というのが必要なのですが、

今回は規模が小さいので、アクセスを行うスレッドを一つだけ(メインのスレッドのみ)にして、他のスレッドからはデバイスにアクセスしないようにします。

Humidity = 0
Temperature = 0

def __main__():
    global sw
    global Humidity
    global Temperature

    GPIO.setmode(GPIO.BCM)
    GPIO.setup(22,GPIO.IN) 
    GPIO.add_event_detect(22, GPIO.FALLING, callback=callback, bouncetime=300)
    GLCD.PinsInit(20, 7, 8, 9, 18, 19, 10, 11, 12, 13, 14, 15, 16, 17)
    GLCD.GLCDInit()
    GLCD.GLCDDisplayClear()

    roop = 10 * 60 * 60
    mode = 1
    
    thread = threading.Thread(target=httpServe)
    thread.start()
    
    try:
        while True:
            Humidity = AM2320.GetHum()
            Temperature = AM2320.GetTemp()

            if sw == True:
                GLCD.GLCDDisplayClear()
                mode += 1
                if mode > 4:
                    mode = 1
                sw = False

            if mode == 1:
                if roop >= 10 * 60 * 60:
                    GLCD.GLCDDisplayClear()
                    Weather.RequestAPI()
                    weather = Weather.GetWeather()
                    temp = Weather.GetTemp()
                    roop = 0

                GLCD.GLCDPuts(1, 0, "Date :")
                GLCD.GLCDPuts(5, 8, datetime.datetime.now().strftime('%Y:%m:%d %A '))
                GLCD.GLCDPuts(1, 16, "Weather :")
                GLCD.GLCDPuts(10,24, weather)
                GLCD.GLCDPuts(10,32, "Temp : " + format(temp) + 'C')
                GLCD.GLCDPuts(1, 40, "Time : " + datetime.datetime.now().strftime('%H:%M'))
                GLCD.GLCDPuts(1, 48, "Humidity    : " + Humidity + '%')
                GLCD.GLCDPuts(1, 56, "Temperature : " + Temperature + 'C')

                roop += 1

            #中略

            time.sleep(1)
    except KeyboardInterrupt:
        GLCD.GLCDDisplayClear()
        GPIO.cleanup()

#中略

class StubHttpRequestHandler(BaseHTTPRequestHandler):
    server_version = "HTTP Stub/0.1"

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

    def do_GET(self):
        enc = sys.getfilesystemencoding()

        data = {
            'datetime' : datetime.datetime.now().strftime('%Y:%m:%d %H:%M:%S'),
            'temperature': Temperature,
            'humidity': Humidity,
        }

        encoded = json.dumps(data).encode()

        self.send_response(HTTPStatus.OK)
        self.send_header("Content-type", "text/html; charset=%s" % enc)
        self.send_header("Content-Length", str(len(encoded)))
        self.end_headers()

        self.wfile.write(encoded)     

__main__()

これで競合は回避できるはず。

【ラズパイ】【いろいろ計測モニター】HTTPサーバを実装する

測定した温度、湿度をWindows側で表示させたいと思います。

前回HATでやったときはラズパイ側をクライアント、Windows側とサーバとして動作させましたが、

今回は逆で、ラズパイ側をサーバ、Windows側をクライアントとして実行させます。

常に稼働している方をサーバにする方が何かと都合が良い。

こちらの記事を参考にしました。

https://qiita.com/linxuesong/items/8ac98102c24b8f587a16

ただし、このままサーバとして稼働させると、他の処理が出来なくなってしまいます。

なので、HTTPサーバの処理を、既存のループ処理とは別スレッドで実行する必要があります。

なので、スレッドの扱いについて、こちらの記事を参照。

https://qiita.com/tchnkmr/items/b05f321fa315bbce4f77

最終的に組み上がったコードはこちら。

import os
import sys
import urllib.parse
import json
import RPi.GPIO as GPIO
import time
import datetime
import calendar
import GLCD
import AM2320
import Weather
import threading

from http.server import BaseHTTPRequestHandler
from http.server import HTTPServer
from http import HTTPStatus

PORT = 8000
sw = False

def __main__():
    global sw
    GPIO.setmode(GPIO.BCM)
    GPIO.setup(22,GPIO.IN) 
    GPIO.add_event_detect(22, GPIO.FALLING, callback=callback, bouncetime=300)
    GLCD.PinsInit(20, 7, 8, 9, 18, 19, 10, 11, 12, 13, 14, 15, 16, 17)
    GLCD.GLCDInit()
    GLCD.GLCDDisplayClear()

    roop = 10 * 60 * 60
    mode = 1
    
    thread = threading.Thread(target=httpServe)
    thread.start()
    
    try:
        while True:

            #既存のループ処理

            time.sleep(1)
    except KeyboardInterrupt:
        GLCD.GLCDDisplayClear()
        GPIO.cleanup()

def callback(channel):
    global sw
    sw = True

def httpServe():
    handler = StubHttpRequestHandler
    httpd = HTTPServer(('',PORT),handler)
    httpd.serve_forever()

class StubHttpRequestHandler(BaseHTTPRequestHandler):
    server_version = "HTTP Stub/0.1"

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

    def do_GET(self):
        enc = sys.getfilesystemencoding()

        data = {
            'datetime' : datetime.datetime.now().strftime('%Y:%m:%d %H:%M:%S'),
            'temperature': AM2320.GetTemp(),
            'humidity': AM2320.GetHum(),
        }

        encoded = json.dumps(data).encode()

        self.send_response(HTTPStatus.OK)
        self.send_header("Content-type", "text/html; charset=%s" % enc)
        self.send_header("Content-Length", str(len(encoded)))
        self.end_headers()

        self.wfile.write(encoded)     

__main__()

Windows側からHTTPのGETリクエストを受信すると、時刻、温度、湿度をJson形式で応答を返します。

今日の北海道は暑いぜ。

Pixel4aが発表されたぜ!仕様を確認する!

ようやく来たぜ正式発表。

Googleストアにラインナップされています。

リリース日は8月20日。

お値段、何と、Pixel3aより安いんです。

42900円。

それなのに、メモリ6GB、ストレージ128GB、プロセッサもSnapdragon600番台から700番台にスペックアップしています。

しかし、かなり削られた機能もありまして、

まず、アクティブエッジが無い。

端末をぎゅっと握るとGoogleアシスタントが起動するアレ。

まぁ、オイラもPixel3使っているけど、アクティブエッジはあまり使ってない。

そして、当然ながらMotion Senseも無い。

勿論ワイヤレス充電機能も。

そして、防水機能も無い。

下二つはPixel3aから搭載していないけど、Pixel3からの買い換え、と考えると、保留。

まだうちのPixel3が現役で稼働しているので、これが壊れたら購入候補に入るかもしれない。

ただ、もうストレージの容量がパンパンなのよね。

最近のゲーム容量食いまくりで。

重たいゲームはスマホでプレイするつもりは無い(むしろ今メインはPCゲーム)ので、ミドルレンジのスペックでも十分耐えられると思う。

悩む。

いや、今使っているの壊れたら買おう。

【ダイエット支援】【食事管理】データ詳細処理を作成する。

前回までの状況はこちら。

最新ソースはこちら(gitHub)

https://github.com/takishita2nd/diet-mng

今回はこの画面を作成していきます。

前回作成した画面の、

Editをクリックしたときの、遷移先の画面です。

まずは、画面遷移のところを作成する。

EatingListComponent.vue

                        <td class="edit"><a @click="onClickEdit(data.date)">Edit</a></td>


export default {
    data() {
        return {
            url: "eating/detail"
        };
    },
    methods: {
        onClickEdit: function(date) {
            window.location = this.url + "/" + date;
        },

Editをクリックすると、onClickEdit()が実行され、window.locationにURLを設定することで、そのURLに遷移します。

で、遷移先の画面。

web.php

Route::get('/eating/detail/{date}', 'Eating\EatingController@detail')->name('eating/detail');
EatingController.php

class EatingController extends Controller
{
    public function detail($date)
    {
        return view('eatingdetail', ['date' => $date]);
    }
eatingdetail.blade.php

@extends('layouts.app')

@section('content')
<div class="container">
    <div class="row">
        <div class="col-md-8 col-md-offset-2">
            <div class="panel panel-default">
                <div class="panel-heading">食事管理</div>

                <div class="panel-body">
                    @if (session('status'))
                        <div class="alert alert-success">
                            {{ session('status') }}
                        </div>
                    @endif
                </div>
                <eating-detail-component date={{$date}}></eating-detail-component>
            </div>
        </div>
    </div>
</div>
@endsection

詳細画面のURLはeating/detail/(日付)となります。

この(日付)の部分が巡り巡って、eating-detail-componentに渡ります。

<eating-detail-component date={{$date}}></eating-detail-component>

ここで一度詰まった。

:date={{$date}}と書いてはダメみたい。

で、表示するデータの取得。

class EatingManagementRepository
{
    private $paramNames = ['date', 'item', 'protein', 'liqid', 'carbo', 'calorie'];

    public function getDetails($user, $date)
    {
        $eatings = $user->EatingManagements()
            ->where(DB::raw('date_format(date, "%Y-%m-%d")'), $date)
            ->get();
        
        $retDatas = [];
        $index = [0, 0, 0, 0];
        foreach($eatings as $eating) {
            $timezone = $eating->timezones()->first();
            for($j = 1; $j < count($this->paramNames); $j++) {
                $retDatas[$timezone->id - 1][$index[$timezone->id - 1]][$this->paramNames[$j]] = $eating->{$this->paramNames[$j]};
            }
            $index[$timezone->id - 1]++;
        }
        return $retDatas;
    }

今回もかなりカオスな処理。

時間帯によってデータを分けたかったので、

retData[時間帯番号][index][詳細データ]

という形にデータを作成しています。

詳細データの連想配列の名前は、定義済みの$paramNamesの値を使用します。

これをAPIで呼び出します。

class ApiController extends Controller
{
    /**
     * 一日分のデータを取得する
     */
    public function detail(Request $request)
    {
        return response()->json(['dataLists' => $this->eatingManagement->getDetails(Auth::user(), $request->contents['date'])]);
    }
web.php

Route::post('api/eating/detail', 'Eating\ApiController@detail');
<template>
    <div>
        <div>
            <p id="navi">> <a href="/home">HOME</a> / <a href="/eating">食事管理</a></p>
            <p>{{date}}</p>
            <table class="eatingdetail">
                <caption>朝</caption>
                <tbody>
                    <tr>
                        <th class="item">品名</th>
                        <th class="protein">タンパク質</th>
                        <th class="liqid">脂質</th>
                        <th class="carbo">炭水化物</th>
                        <th class="calorie">カロリー</th>
                        <th class="edit"></th>
                    </tr>
                    <tr v-for="data in datalists[0]">
                        <td class="item">{{ data.item}}</td>
                        <td class="protein">{{ data.protein}}</td>
                        <td class="liqid">{{ data.liqid}}</td>
                        <td class="carbo">{{ data.carbo}}</td>
                        <td class="calorie">{{ data.calorie}}</td>
                        <td class="edit"><a @click="onClickEdit(data.date)">Edit</a></td>
                    </tr>
                </tbody>
            </table>
            <table class="eatingdetail">
                <caption>昼</caption>
                <tbody>
                    <tr>
                        <th class="item">品名</th>
                        <th class="protein">タンパク質</th>
                        <th class="liqid">脂質</th>
                        <th class="carbo">炭水化物</th>
                        <th class="calorie">カロリー</th>
                        <th class="edit"></th>
                    </tr>
                    <tr v-for="data in datalists[1]">
                        <td class="item">{{ data.item}}</td>
                        <td class="protein">{{ data.protein}}</td>
                        <td class="liqid">{{ data.liqid}}</td>
                        <td class="carbo">{{ data.carbo}}</td>
                        <td class="calorie">{{ data.calorie}}</td>
                        <td class="edit"><a @click="onClickEdit(data.date)">Edit</a></td>
                    </tr>
                </tbody>
            </table>
            <table class="eatingdetail">
                <caption>夜</caption>
                <tbody>
                    <tr>
                        <th class="item">品名</th>
                        <th class="protein">タンパク質</th>
                        <th class="liqid">脂質</th>
                        <th class="carbo">炭水化物</th>
                        <th class="calorie">カロリー</th>
                        <th class="edit"></th>
                    </tr>
                    <tr v-for="data in datalists[2]">
                        <td class="item">{{ data.item}}</td>
                        <td class="protein">{{ data.protein}}</td>
                        <td class="liqid">{{ data.liqid}}</td>
                        <td class="carbo">{{ data.carbo}}</td>
                        <td class="calorie">{{ data.calorie}}</td>
                        <td class="edit"><a @click="onClickEdit(data.date)">Edit</a></td>
                    </tr>
                </tbody>
            </table>
            <table class="eatingdetail">
                <caption>間食</caption>
                <tbody>
                    <tr>
                        <th class="item">品名</th>
                        <th class="protein">タンパク質</th>
                        <th class="liqid">脂質</th>
                        <th class="carbo">炭水化物</th>
                        <th class="calorie">カロリー</th>
                        <th class="edit"></th>
                    </tr>
                    <tr v-for="data in datalists[3]">
                        <td class="item">{{ data.item}}</td>
                        <td class="protein">{{ data.protein}}</td>
                        <td class="liqid">{{ data.liqid}}</td>
                        <td class="carbo">{{ data.carbo}}</td>
                        <td class="calorie">{{ data.calorie}}</td>
                        <td class="edit"><a @click="onClickEdit(data.date)">Edit</a></td>
                    </tr>
                </tbody>
            </table>
        </div>
    </div>
</template>

<script>
export default {
    props: {
        date: String
    },
    data() {
        return {
            showInputDialogContent: false,
            showEditDialogContent: false,
            showDeleteDialogContent: false,
            datalists: [],
            param: {},
            contents: {
                date: "",
            },
        };
    },
    created: function() {
        this.updateList();
    },
    methods: {
        onClickEdit: function(date) {
        },
        invokeUpdateList: function() {
        },
        updateList: function() {
            this.datalists = [];
            this.contents.date = this.date;
            this.param.contents = this.contents;
            var self = this;
            axios.post('/api/eating/detail', this.param).then(function(response){
                response.data.dataLists.forEach(element => {
                    var data = [];
                    element.forEach(element2 => {
                        data.push({
                            item: element2.item,
                            protein: element2.protein,
                            liqid: element2.liqid,
                            carbo: element2.carbo,
                            calorie: element2.calorie
                        })
                    })
                    self.datalists.push(data);
                });
            }).catch(function(error){
            });
        }
    }
}
</script>

responseの処理がネストになるという、またまたカオスな処理。

でもこれでJS側でもdatalists[時間帯ID][index].詳細データという形になります。

これをテンプレートに表示させれば良い。

【実質北海道一周】都市と距離データを作成する。

前回までの状況はこちら。

さて、GPSから距離を求めることが出来たので、

今度は実際に使用する都市間距離のデータを作成します。

どこかに便利なデータが公開されていないかなー

って探してみたのですが、

ありませんでした。

公開されているデータが無いので、自分で作りました。

チマチマとGoogle Mapを使って、北海道一周で通る都市と、その都市間の距離を測定しました。

ルート検索を使うと、走行距離が出てくるので、このデータを、とりあえずはExcelに入力。

これをエディターにコピペして、置換を使ってタブスペースを削除。

ちなみに、ルートとしては、札幌をスタートして小樽へ向かい、反時計回りで一周して、石狩から札幌に戻るルートです。

疲れた。