勉強時間記録アプリ制作(C3.js/firebase)

はじめに

前回でfirebaseを用いたCRUD・認証認可の実装はなんとなく理解できたので本格的にアプリ制作をしていきたいと思います。

Firebase+JavaScriptでToDoアプリ(認証・認可)

✅参考

JavaScriptでカレンダーを自作したら勉強になった

これ追々確認したい。

HTMLの基本、Webページにカレンダーを設置する方法

inputタグ便利すぎる。。。

グラフ作成のライブラリ選定

JavaScriptグラフ描画ライブラリ比較 – Chart.jsをやめた理由

比較が非常にわかりやすい。今回はグラフも織り交ぜながら作っていきたい。

今日から始めるC3.js

D3.js⇒C3.js気になる。気軽らしい。あんまり参考書はないので公式でですね。

c3.jsの円グラフで表示順を指定する 公式

pie chartを個人的には使いたい。

chart.jsのpie chart公式(日本語) 詳しめの記事

C3とChart.jsを比較して、グラフの中に任意の文字を入れられるC3を使ってみようと思います。

 

C3.jsを使ってみる

公式スタートガイド

https://github.com/c3js/c3/releases/latest からzipをダウンロード

index.htmlに以下を追記。

<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <title>C3.js</title>
    <link rel="stylesheet" href="./css/style.css">
    <link rel="stylesheet" href="./css/c3.css" >
  </head>
  <body>
    <header>
      <h1>C3.js</h1>
    </header>
    <main>
      <div id="chart"></div>
    </main>
    <script src="./js/d3-5.8.2.min.js" charset="utf-8"></script>
    <script src="./js/c3.min.js"></script>
    <script src="./js/index.js"></script>
  </body>
</html>

✅チャート

index.js(公式コピペ)

var chart = c3.generate({
  bindto: '#chart',
  data: {
    columns: [
      ['data1', 30, 200, 100, 400, 150, 250],
      ['data2', 50, 20, 10, 40, 15, 25]
    ]
  }
});

表示

✅Pie chart

index.js

var chart = c3.generate({
  data: {
      // iris data from R
      columns: [
          ['data1', 30],
          ['data2', 120],
      ],
      type : 'pie',
  }
});

表示

ちょっとアレンジ。

let array = [
  ['JavaScript', 10],
  ['React', 30],
  ['Vue.js', 60],
  ['Ruby', 40],
  ['PHP', 50],
]
let chart = c3.generate({
  data: {
      columns: array,
      type: 'pie',
      order: null
  }
});

確認

これ、割合を自動算出してくれる&mouse hoverのエフェクトとかもデフォルト。

便利すぎる!!

試しに追加できるか試したところできた◎

👇把握できたこと

①同名のキーを与えなければエラーにはならない。

②色は10色をリピートする。

感動!これは使い勝手良すぎる!!

Firebaseの実装

※初期設定などは以前やっているので割愛。

Firebase+JavaScriptでToDoアプリ(認証・認可)

✅取得

参考:ウェブでのデータの取得

※公式引用

前回のToDoアプリ作成の時はonceメソッドやその他イベントを使わなかったので使ってみる。

child_addedイベントだとオブジェクト形式で個数分繰り返し取得することがわかったので以下のように記述。

let databaseInitFC = () => {
  let connect_DB = db.ref(`/users/${firebase.auth().currentUser.uid}`);
  // DB取得
  connect_DB.on('child_added', (data) => {
    console.log('child_added※1つずつ取得して繰り返す');
    message = "child_added"
    firebase_db = data.val();
    mkListFC();
  });
}

data.val();でオブジェクト形式で1つのデータを取得して、全部の数分処理を繰り返してくれます。

これ、データがなかった場合は処理されないから優秀。

そして理解するのに時間がかかった(これは公式以外参考記事が少ない印象)けどchild_changedメソッドは変更、child_removedメソッドは変更時にトリガーしてくれるメソッドです。

削除更新は割と簡単に実装できました。

// databaseInitFCに追記
~~~~
  connect_DB.on('child_changed', function(data) {
    console.log('child_changed');
    serverEditedData(data.val());
  });
  connect_DB.on('child_removed', function(data) {
    console.log('child_removed');
    serverRemovedData(data.val());
  });
};

関数をグローバルに定義

// DB更新後
let serverEditedData = (data) => {
  let editArray = [data.item, data.time];
  array[data.id - 1] = editArray;
  console.log(array);
  mkChart();
}
// DB削除後
let serverRemovedData = (data) => {
  console.log(data);
  array.splice(data.id -1,1);
  mkChart();
}

※後程関数の数を-1したからといってidが一致しないことに気付く。。。firebase側から編集することも少ないので一旦ステイすることにする。リロードすれば問題ないし。

カレンダーの実装

参考:HTMLの基本、Webページにカレンダーを設置する方法

以下で作成。inputタグのtypeをdateにすればできてしまうなんて。。。

input#addDate.display-block(type="date")

value属性で選択した日付が取得できる。

 

バリデーションの実装

軽くやってみました。

html

tr.validate-message-display-none
  td ※両方入力してください
  td

js

let validate = () => {
  console.log("validate");
  validate_message_display_none.className = "validate-message";
};
let input_text = $("inputText");
input_text.addEventListener('change', () => {
  l("event");
  if (add_item.value !== "" && add_time.value !== "") {
    validate_message_display_none.className = "display-none";
  }
})

css

.validate-message {
  color: red; }

こんな感じ。

一応両方入力済みになるとメッセージ非表示になるようにしたけどだいぶめんどくさい感じ。。。笑

ついでにデータベースにも同名のタイトルが入らない&数字型しか入らないように実装してみる。

※C3のデータが同名だと透明の円形をつくってしまうため。testを2回入れるとこんな感じ。

数字のバリデートはinput type=”number”で簡単にできた。

カレンダーも必須にした。

勉強したことも同名の入力を不可にしたい。後マイナスの入力もできちゃう。。。笑

参考:数字のみを入力できるフォーム(テキストボックス)を作成する

typeにtelがあるのも初めて知った。最初から数字が表示されるので親切設計ですね!

✅既にあるitemの名前を入力不可にする

以下の感じでfindメソッドを用いて実装しました。

let item_overlap_validate = () => {
  let find_result = array.find((value) => {
    return value[0] === add_item.value; 
  })
  return find_result; // あれば配列、なければundefined
}

被る値がなかった場合、返り値でundefinedが渡されるのでそれをif文で条件分岐させて処理。

✅timeで負の数字を入力不可にする

参考:[JavaScript] 数値の正数、ゼロ、負数を判定する(Math.sign)

let negative_or_0_number_validate = () => {
  console.log("正の数か確認")
  let x = Math.sign(add_time.value);
  l(x);
  if (x === 1){
    return true;
  }
}

こんな感じで実装しました。

before_validate関数で条件分岐がネストしちゃってるので良くない気が。。。

とりあえずここまでで試したかったことは一通り終了!!

α版完成ってことにします。

ここまでのリポジトリ

β版製作記録

続いて、実際に使えそうなアプリ(β版)を目指して修正していきたいと思います。

仕様:①日毎に記録(1日1つまでの投稿・確認機能)②勉強時間をグラフ化

🙄とりあえずこれ目指して作ります。ノートにいろいろとやってみたいことを書いたのですが、書きだしたら逆に途方に暮れたので小出しにしていきます。。。笑

✅日付を選択して確認を押すと勉強したことや時間が確認できる。

とりあえずこんな感じで実装。

add_childメソッドで取得している配列が[item,time]でdateが入っていないので別途確認ボタンを押した際に取得してくるよう実装していきます。

今回valueメソッド使おうと思ったけど、配列&オブジェクト両方の出力ケースを考慮しないといけないので不採用。

以下の感じで配列にオブジェクトをぶっこむ。

let diaryCheck = () => {
  console.log("diaryCheck");
  connect_DB.on('child_added', (snapshot) => {
    let firebase_daily_db = snapshot.val();
    allArray.push(firebase_daily_db);
  });
}

アクセス

> allArray[0].date
"2020-06-20"

配列の更にオブジェクトの中を調べて一致させないといけない感じ、、、

と思ったけど結構簡単に実装できました。

let allArray = [];

let diaryCheck = () => {
  console.log("diaryCheck");
  if(allArray = []){
    connect_DB.on('child_added', (snapshot) => {
      let firebase_daily_db = snapshot.val();
      allArray.push(firebase_daily_db);
    });
    let result = allArray.find((value) => {
      return value.date === addDate.value; 
    })
    add_item.value = result.item;
    add_time.value = result.time;
    add_diary.value = result.diary;
  }
}

✅日毎の時間をグラフ化

まずはグラフ選定。

Timeseries Chart ※折れ線グラフ

Bar Chart ※棒グラフ

🙄X軸に日付、Y軸で時間。タグ毎(=言語なり)に時間出て、合計時間も出るのが理想。

参考:円・棒・折れ線グラフを選ぶ基準とは?

どっち選ぶのがいいかわからずだったけど、こんな記事を見つけた。

今回はデータが時系列なので折れ線グラフを採用

c3.generate({
  bindto: '#chart2',
  data: {
    x: 'x', // colums配列から先頭がxのモノを引用してx軸を生成する
    columns: [
      ['x', '2013-01-01', '2013-01-02', '2013-01-03', '2013-01-04', '2013-01-05', '2013-01-06'],
      ['data1', 30, 200, 100, 400, 150, 250],
      ['JavaScript', 130, 340, 200, 500, 250, 350]
    ]
},
  axis: {
      x: {
          type: 'timeseries',
          tick: {
              format: '%Y-%m-%d'
          }
      }
  }
});

とりあえずfirebaseのdateとtimeを引っ張ってきてグラフを作ります(とりあえず棒グラフ1つ)。

サンプルを見た感じ、columns配列下で1つ目の値がxのものをx軸に、それ以外は1つ目の値を棒グラフのタイトルにする感じですね。

変数に書き換えて以下の感じにします。

columns: [
  lineGraphArrayX,
  lineGraphArrayY
]
let lineGraphArrayX = ['x', '2013-01-01', '2013-01-02', '2013-01-03'];
let lineGraphArrayY = ['学習時間', 60, 600, 180];

これでこんな感じ。

🙄右端の値がちょん切れるのが少し気になる。。。仕様っぽいからしょうがないですね。

DB取得後に処理してくれる関数を作成。

let lineChartAddData = () => {
  lineGraphArrayX.push(firebase_db.date);
  lineGraphArrayY.push(firebase_db.time);
  mkLineChart();
}

表示

🙄意外に簡単に作れました。

β版制作記録②

✅課題点

ここで更に気になっている点を洗い出し

・日ごとに1つしか登録できないようにバリデート

→不要。理由以下後述。

・更新、削除機能

→日付選択でfirebaseにデータがある場合、更新・削除ボタンを表示/追加ボタン非表示表示。日ごとのバリデートが不要に!

・折れ線グラフのY軸が非常に見にくい

→単位を時間にする

✅更新・削除機能の実装(firebaseのDBに紐づいていない変数に依存しない)

更新

let editDataFB = () => {
  console.log("edit!!")
  connect_DB_edit = calendar_result.id;
  db.ref(`/users/${firebase.auth().currentUser.uid}/${connect_DB_edit}`).update({
    item:add_item.value,
    time:add_time.value,
    diary:add_diary.value
  });
};

削除

let removeDataFB = () => {
  console.log("remove")
  connect_DB_edit = calendar_result.id;
  db.ref(`/users/${firebase.auth().currentUser.uid}/${connect_DB_edit}`).remove();
};

続いて削除・更新時にグラフもリアルタイムで変更されるよう処理する。

問題点。

firebaseのDBに紐づいていない変数に依存していること。

これをこのタイミングで解消していきます。

まずは追加面。

let firebase_latest_id = 0;

※現状は取得時に0から最新の値に。追加時に新たに基準となる変数(firebase_added_id)に+1してる。

なのでfirebaseから取得した配列から基準となる値で処理できるよう変更。

// let firebase_added_id = firebase_latest_id + 1;
// db.ref(`/users/${firebase.auth().currentUser.uid}/${firebase_added_id}`).set({
db.ref(`/users/${firebase.auth().currentUser.uid}/${firebase_db_latest.id + 1}`).set({

🙄そもそもこの変数作る必要性なかった。。。

次に更新・削除

サーバー側から削除→ブラウザ上の基準としている変数がfirebaseのDBと紐づいていないため更新されず、表示が変更されない。以下の原因である変数に依存しない方法を考える。

両方のグラフで配慮しないといけないけど、とりあえずpie chart側で検証していきます。

キー2を最後に削除した際にグラフ側で反映されない。

削除時

connect_DB.on('child_removed', function(data) {

data.val()には以下のように削除されたオブジェクトが渡される。

{date: "2020-06-20", diary: "1", id: 1, item: "1", time: "1"}

なのでdata.val().idで1を取り出せる。

現状はspliceメソッドで削除処理している。

pieArray.splice(data.val().id -1,1);

※第1引数は要素抽出の開始位置。第2引数は取り出す要素数。

2が最後に残った時点で検証

> console.log(pieArray)
["tag2", 20] // 要素数1 配列キー0の状態
> console.log(pieArray[0][0])
"tag2" // こんな感じで配列の配列はアクセスできる。

ここで理解。配列のキーとspliceメソッドで利用しているdata.value.id -1が合致していない。

となるとキーに頼らず、配列の値と削除時の値で一致したものを削除すればよいが。。。

pieArrayに入れているのはtagとtime。一意ではないのでいずれバグが起きる。

ってことでリロード処理することにしました。結局。。。笑

location.reload();

※下記のようにサーバー側から削除した場合、データないのにカレンダー側では選択&表示できる問題もリロードで解消。

🙄更新も同様にリロード処理にしました。C3で扱う配列の形式が決まっているのでこれはしょうがない。

✅単位を時間にしてチャートに表示する&必須バリデーションの見直し

1時間なら1、1時間半なら1.5と表示されるようにしていきます。

なので、登録時のフォーマットから変更。

参考までにスタディプラスはセレクトタグが使われている。真似しよう。

select#selecte-h(name="selecte-h")
  - for (var x = 0; x < 24; x++)
    option(value=x) #{x}
span 時間
select#selecte-m(name="select-m")
  - for (var x = 0; x < 60; x++)
    option(value=x) #{x}
span 分

🙄こればっかりはまじでPug様様だと思う。あとセレクトタグはブラウザが自動で上下どっちに表示するか判断するのね。さらにこれによって負の数字も選択できなくなることに気付いた。

保存の仕方を考える。。。

pie chartは分で考えたほうが楽。
→これも1.5など統一すればOKか。

時間と分を個別に保存しておいた方が更新時に楽なので時間と分、グラフ用時間の3つを保存する。

// 時間の計算
let minutesToHourTime = () => {
  let minutesToHour = Math.floor(Number(time_m.value)/60 * 100) /100;
  return Number(time_h.value) + minutesToHour;
}

割と簡単に実装できた。

ここからvalidate.jsも整理しながら実装。

とりあえずさんざんバリデーションで記載していた以下の部分を削除。

add_time.value !== ""

負の数字も出なくなったので以下も削除。

let negative_or_0_number_validate = () => {
  let x = Math.sign(add_time.value);
  l(x);
  if (x === 1){
    return true;
  }
}

let after_validate_negative_number = () => {
  validate_message_text.className = "validate-message";
  validate_message_text.textContent = "正の数(※半角)を入力してください";
}

あとタグ名も重なっても良いので以下を削除(後程、タグ名一致の項目を合算処理計算する予定)。

let item_overlap_validate = () => {
  let find_result = pieArray.find((value) => {
    return value[0] === add_item.value; 
  })
  return find_result;
}

let after_validate_overlap = () => {
  validate_message_text.className = "validate-message";
  validate_message_text.textContent = "既に登録されたitem名です"
};

現状は学習記録未記入でも登録できる。

→タグ含め、編集機能実装で後程追加できるようになったので未入力でもいいかもしれない。

→日付のみバリデーション付けるようにすることに。

ってことで以下削除。

if (add_item.value === ""){
  validate_message_text.className = "validate-message";
}

input_text.addEventListener('change', () => {
  if (add_item.value !== "") {
    validate_message_text.className = "display-none";
  }
})

他にもエンターキーでの登録や項目数増えることに伴ってマストではなくなったものは不要として削除。

itemからtagに命名変更。

✅タグの同名登録可能にして合算する

現状、pie chartの仕様の関係で、tagを同名で登録すると重複されてホワイトアウトしてしまう。

これを直していきます。

pie chartはpieArrayという配列の変数を元に作っている。

👆タグが全てtestだった場合の図。何も表示されない。。。笑

pieArray = [タグ名, タグの合計時間]にしたい。現状は以下の形で生成されている。

connect_DB.on('child_added', (data) => {
  firebase_db_latest = data.val();
  allArray.push(firebase_db_latest);
  chartAddData();
  lineChartAddData();
});
~~~~
let chartAddData = () => {
  let addArray = [firebase_db_latest.tag, Number(firebase_db_latest.time)]
  pieArray.push(addArray);
  mkChart();
};

🙄1つ毎にmkChart();実行されていること自体微妙な気が。更新があった際に実行させたい。

indexOfメソッドを使います。文字が見つからない場合は-1が返る。

if (check_tag.indexOf(firebase_db_latest.tag) === -1){
    check_tag.push(firebase_db_latest.tag);
    let addArray = [firebase_db_latest.tag, Number(firebase_db_latest.time)]
    pieArray.push(addArray);
  } else {

とりあえずこんな感じでpushをしないようにしたので1つは生成される。

ただこのままだと、仮に複数データがあっても時間は追加されない。

> pieArray
["test"1.08] // この2つ目配列(time)に時間を合算していきたい。
> pieArray[0][1]
1.08

被ったタグの時間を取得して時間を合算させたい。

以下だとエラー

} else {
  // 被ったタグの時間を取得して時間を合算させたい。
  l(firebase_db_latest.time);
  addArray[0][1] += Number(firebase_db_latest.time);
  console.log(addArray[0][1]);
}

一旦チャート関連の関数をミュートしてデータの絞り方を探してみる。

公式引用

orderByChild()とequalTo()を組み合わせる。

ぶっちゃけこれだけじゃわからず、調べて使い方理解。例の書籍少しだけ見れる。

connect_DB.orderByChild('tag').equalTo("test").once("value",(snapshot)=> {
  let data = snapshot.val();
  console.log(data);
});

これで以下のように取得できる。

tagにtestがあるものだけオブジェクトで取得。ただこれ、該当するオブジェクトを全部引っ張ってきちゃうのね~・・・(該当する値だけ欲しかった。。。

~~しばらく格闘~~

以下で実装できました。filterとindexOfとfillを組み合わせて実装。

// DB取得後、chartの作成
let chartAddData = () => {
  // タグが生成されていなかった場合
  if (check_tag.indexOf(firebase_db_latest.tag) === -1){
    check_tag.push(firebase_db_latest.tag);
    let addArray = [firebase_db_latest.tag, Number(firebase_db_latest.time)]
    pieArray.push(addArray);
  } else {
    // タグが既にあった場合,allArrayから1つずつ配列をピックアップしてフィルタ
    allArray.filter((value) => {
      // 被ったタグの合計時間を出力
      if (value.tag === firebase_db_latest.tag) {
        ttl_time += value.time;
      }
    })
    // 被ったタグの配列を作成
    overlap_tag_array = [firebase_db_latest.tag, ttl_time];
    console.log(overlap_tag_array);
    // 開始位置を特定。
    let overlap_key = check_tag.indexOf(firebase_db_latest.tag)
    console.log(overlap_key);
    // 配列の要素の上書き(新しい要素,開始位置,上書き個数)
    pieArray.fill(overlap_tag_array,overlap_key,overlap_key+1);
    ttl_time = 0;
  }
  mkChart();
};

🙄めちゃ難しかった。。。

ここまでのリポジトリ

✅タグを複数登録できるようにする(時間を合算する)

・タグを3つまで登録できる

・それぞれタグと紐づけて時間を登録できる

firebaseの設計を考慮して、とりあえず3つまで。以下の感じでクラスを変えて追加ボタンに連動して表示されていく形で実装。

let tag2 = $("tag2");
let tag3 = $("tag3");
let tag_add_btn = $("tagAddBtn");

let tagAdd = () => {
  if (tag2.className === "display-none"){
    tag2.className = "";
  } else if(tag3.className === "display-none") {
    tag3.className = "";
    tag_add_btn.className = "display-none";
  }
}

🙄以前はelementからJSで生成していたけど、こっちの方が楽かもしれない。。。

次に時間の処理をしていく。

登録処理用関数

db.ref(`/users/${firebase.auth().currentUser.uid}/${firebase_db_latest.id + 1}`).set({
  id:firebase_db_latest.id + 1,
  date:add_date.value,
  tag:add_tag.value,
  time:minutesToHourTime(),
  timeH:time_h.value,
  timeM:time_m.value,
  diary:add_diary.value
});

編集抜粋

time:minutesToHourTime(time_h.value,time_m.value),
timeH:time_h.value,
timeM:time_m.value,
time2:minutesToHourTime(time_h2.value,time_m2.value),
timeH2:time_h2.value,
timeM2:time_m2.value,

🙄こんな感じで引数で渡せるようにする。登録項目が多いのが欠点。。。

TTL時間を算出する関数

let minutesToHourTime = () => {
  let minutesToHour = Math.floor(Number(time_m.value)/60 * 100) /100;
  return Number(time_h.value) + minutesToHour;
}

引数を渡せるように編集

let minutesToHourTime = (h,m) => {
  let minutesToHour = Math.floor(Number(m)/60 * 100) /100;
  return Number(h) + minutesToHour;
}

カレンダー選択時も表示されるように。

※タグは最初から3つ表示されていたほうが楽かもと思ったので追加ボタン消して常に表示するように変更。

以下で正しくカレンダーの日付選択で表示が切り替わるようにも編集。

add_tag2.value =  calendar_result.tag2 === undefined ? "" : calendar_result.tag2;
time_h2.value = calendar_result.timeH2 === "0" ? "0" : calendar_result.timeH2;
time_m2.value = calendar_result.timeM2 === "0" ? "0" : calendar_result.timeM2;

🙄三項演算子様様ですね。

✅合計時間を登録⇒学習推移のグラフは合計時間を元に表示。

上の変更に伴ってタグごとの時間を合計してfirebaseに保存。dailyTtlTimeと命名。

以下の感じで表示されるようにした。

✅タグごとに学習推移が見れるようにする

タグ3つ登録できることによって、tag,tag2,tag3で重なるtag名の合計時間を計算

⇒pie chartに反映されるようにしないといけなくなった。

これを編集

// DB取得後、chartの作成
let chartAddData = () => {
  // タグが生成されていなかった場合
  if (check_tag.indexOf(firebase_db_latest.tag) === -1){
    check_tag.push(firebase_db_latest.tag);
    let addArray = [firebase_db_latest.tag, Number(firebase_db_latest.time)]
    pieArray.push(addArray);
  } else {
    // タグが既にあった場合,allArrayから1つずつ配列をピックアップしてフィルタ
    allArray.filter((value) => {
      // 被ったタグの合計時間を出力
      if (value.tag === firebase_db_latest.tag) {
        ttl_time += value.time;
      }
    })
    // 被ったタグの配列を作成
    overlap_tag_array = [firebase_db_latest.tag, ttl_time];
    console.log(overlap_tag_array);
    // 開始位置を特定。
    let overlap_key = check_tag.indexOf(firebase_db_latest.tag)
    console.log(overlap_key);
    // 配列の要素の上書き(新しい要素,開始位置,上書き個数)
    pieArray.fill(overlap_tag_array,overlap_key,overlap_key+1);
    ttl_time = 0;
  }
  mkChart();
};

※コードが長すぎたので編集後は割愛。

※冗長ですがとりあえずtag1,2,3毎に上記の処理を作って実装しました。

と、ここでtagを未記入で入力すると以下のように不要な項目がグラフで出てきてしまうことが発覚。

firebaseにタグ名が未記入&時間が0の際はnullで登録できるよう編集。

tag:add_tag.value === "" ? null : add_tag.value,

で登録はできましたが、そうするとグラフ作成で使っているfirebase_db_latest.tagのエラーが発生。これの考慮はちょっと手間なので変更しないで””で保存する形にしました。(そこまで致命的なエラーではないので。。。)

✅テストログイン機能

参考:JavaScript を使用して Firebase 匿名認証を行う

これを参考に以下を追記。ほぼコピペ。

// テストログイン
let testLoginFC = () => {
  firebase.auth().signInAnonymously()
  .catch(function(error) {
    console.log(error.message);
  });
  firebase.auth().onAuthStateChanged(function(user) {
    var isAnonymous = user.isAnonymous;
    var uid = user.uid;
    location.reload();
  });
};

どうやらonAuthStateChangedメソッド内で定義されている変数はマストっぽい。

匿名ユーザーのアカウント データをUserオブジェクトから取得しているらしい。

※リロード処理は自分で加えました。

比較的簡単に実装することができた。

が、ログアウト後はデータが消えるらしい。再度そのユーザーのデータは引っ張ってこれないから単純にゴミになるな。。。

トップ画面は以下の感じに。

完成

リポジトリ

細々としたリファクタリング事項メモ

・スマホ側からだとplaceholderが改行されない⇒半角スペースを入力。

・削除ボタンの事前チェック

window.confirm()メソッドを追加。

let removeDataFB = () => {
  if(window.confirm("本当に削除してもいいですか?")){
    connect_DB_edit = calendar_result.id;
    db.ref(`/users/${firebase.auth().currentUser.uid}/${connect_DB_edit}`).remove();
  }
};

・学習記録の部分に注意書きを表示

・小数点を含む計算

参考:JavaScriptで小数点の誤差が発生する件の備忘録

とりあえず100かけて100で割るで対処。

・display-none用に親div要素を作成

→カレンダーが未ログイン時表示されていたため。

・入力項目の変更・追加

変更:勉強したこと→タグ

追加:学習記録

・PCから全角数字も半角数字に変換されるようにしたい

参考:[JavaScript] 全角⇔半角の変換を行う(英数字、カタカナ)

replaceメソッドですぐ実装できちゃいそう。バリデーションかかっているし一旦ステイ。

・dateの登録がないときに確認すると表示が更新されない点

→条件分岐で解決

→確認ボタンなくしてイベントchangeメソッドで自動反映されるように変更

→追加ボタンから更新ボタンに変更。さらに削除ボタンを実装する。

・改行はfirebaseが問題なく処理してくれる。便利!!

躓いた点

✅超初歩的なミス

let firebase;

これ入れるとfirebaseの処理諸々非同期で処理されなくなる。要注意。。。(ハマった)

どうして!?document.querySelectorAll(selector).addEventListener()が動かないわけ

フォームで未入力・未選択時の値

input type=”text”のvalueのデフォ値は””だけど””を明示しないとうまくバリデーションできなかった。原因不明。

✅firebaseに同名を同時に複数登録できるか

→できない。

let addDataFB = () => {
  db.ref(`/users/demo/1`).set({
    id:1,
    date:"2020-6-1",
    tag:"tag1",
    tag:"tag2",
    time:70
  });
};

上記の形で登録してもこうなる。

後述の登録で上書きされます。

これは素直にtag2とかして、読み込み時は数字の部分をなくして配列なりぶっこむ必要がありそう。

おわりに

制作時間約25時間。

こうやって考えると短時間でとりあえず完成できた。

特にテストログインが簡単でびっくりした。firebase本当に便利。

サーバーサイド言語を使わずにデータを扱えるのは素晴らしい。

だいぶAPIの勉強になった。

※以下備考。

今更だけどGit Historyのcompare便利!!

そしてCSSを少し弄っていて、reset.cssの必要性は感じた。デフォルトだとpタグに上下のmarginが16pxくらいあったり何かと邪魔。

今回考慮/実装できていないこと

・未来の入力のバリデーション

・日付表示(Yは正直いらない)→グラフを1から作成する必要がある

・折れ線グラフで負の値が出る。

・データが増えた際のグラフの見にくさ

・同時に同じタグが登録されちゃうケース

・棒グラフもタグごとに表示できるようにする

タグ複数作っちゃうとそのタグを学習していない日0なんてざらに起きてしまうし、グラフの見栄えがかなり悪くなる気がしたので作らないことにしました。

※実装も難しそうだけど。。。

コメントを残す