野球リーグスコア管理システムの開発

2019-01-13に作成

image
野球リーグスコア管理システムキャップ野球情報局に関する進捗です。

使っている技術など

  • NodeJS
  • ReactJS
  • netlify
  • MySQL
  • materializecss
  • react-bootstrap
  • react-bootstrap-table-next

旧システムについてはこちらの記事をご覧ください。

残りタスクリスト

trello

所有者限定モードのためこのボードには投稿できません ボードとは?

2/13進捗

概要

image

UI修正

thタグでフォントを太字→普通、12pxに

robotoフォントのfont-weight700を使っているので、敢えてテーブルヘッダを太字ではないようにして区別する
参考スタイル:Baseball LAB

ソート可能なテーブルヘッダのカーソルをポインタにする

画面幅が375px以下の場合は表のfont-sizeを11pxに下げる

コンテンツ詰め込むにはもうこれしか方法がないなーと思います。
スマホ版だけコンテンツ削るという手法もありだとは思いますが。

2/12進捗

UI

デザイン修正概要

image
同僚のデザインできる方にレビューしていただきました。
本日は指摘事項をいくつか反映してタイムアップ。

ヘッダ

  • ヘッダタイトルの左側にpaddingつけた

メニュー

  • バーガーボタンのhover時の色修正
  • メニューのhoverの色を変えた
  • メニューhover時の範囲を変えた
  • メニューで現在のページ位置表示
.current:before{
  content: '\f101';
  font-family: 'Font Awesome 5 Free';
  font-weight: bold;
  padding-right:5px; 
}
  • 現在いるページのメニューを選択できなくする
.current{
  pointer-events: none;
}
  • 外部リンクに遷移することを示すアイコンをつけた

試合結果一覧

  • アコーディオン内のリストをシンプルにした

2/11進捗

概要

  • フッタにツイートボタン置いてみた
  • IE11対応
  • 期毎打撃成績・投球成績をアコーディオン化
    image

フッタにツイートボタン置いてみた

ページごとにシェアするURLを動的にしたいのでまだ課題として置いておきます。

参考にした記事:Twitterシェアボタンの設置 - Qiita

IE11対応

ふとIE11で表示させてみたら真っ白に近かったので急遽対応しました。下記記事のbabel-polyfill入れてindex.jsでインポートする方を採用しました。

参考記事:Reactアプリを IE11 で表示すると 「オブジェクトは 'startsWith' プロパティまたはメソッドをサポートしていません。」 が発生する

期毎打撃成績・投球成績をアコーディオン化

1/17のボードでシーズンをプルダウンで選択する方式にしたのですが、他の箇所でアコーディオン化に成功して思いのほかよかったのでこちらもアコーディオン化しました。
ただ、苦労したのはアコーディオンの中に格納したテーブルの横幅
テーブルの中で表示するコンテンツが多く、結局paddingで5px程度取っても横幅が足りなくなるのでfont-sizeを下げることにしました。

2/10進捗

概要

  • 試合結果一覧をアコーディオン化
  • 個人タイトルのカード化

試合結果一覧をアコーディオン化

image

シーズンごとにリストアイテム化していた試合日ですが、
今回アコーディオンの中に格納しました。

コンポーネントごとにstateを持ってdisplay:noneを切り替える方法を考えていたのですが、CSSで作るとトランジションが使えて表現が豊かになるのでこちらに変えました。
参考:CSSだけでアコーディオンを作る方法

個人タイトルのカード化

image
昨日の時点でheightが0になってしまってどうしようもなかった問題ですが、
1. BootstrapTableにidを設定する
BootstrapTableにはidというプロパティがないので外側のdivに設定しました。

return (
                <div className='col s12'
                    id={this.props.id}>
                    <BootstrapTable 
                        keyField={this.props.keyField}
                        data={this.props.data}
                        columns={this.props.columns}  />
                </div>
            )

  1. idを元にclientHeightを計算する
    trophyというidを要素につけてclientHeightを計算します。
    22はカードのタイトル分の高さです。
document.getElementById('trophy').clientHeight + 22
  1. stateにセットしてstyleに記述する
this.setState({
   height:document.getElementById('trophy').clientHeight
  })
style={
{ height: this.state.height}}

2/7-9進捗

概要

image

  • メニュー実装
  • react-sticky-footer廃止
  • 個人成績ページに所属チームを表示するように修正
  • コンテンツのカード化
  • レビュー募集しています

メニュー実装

元々スライドメニューはあったのですが完成度が低かったので途中からコメントアウトしていました。
メニューを選択するとfocusで意図しないスタイルが適用されていたので背景色に同化してごまかしましたw

  .bm-item:focus {
    outline-color: darkcyan;
  }

コンテンツのカード化

カード化すると見栄えがよくなりました。
ただ、react-bootstrap-tableをカードでラップしようとするとカードのheightが0になってしまってちょっと悩みどころ。

レビュー募集しています

ずっと公開はしていたのですが、
- UIがだいぶマシになってまともに見られるようにはなった
- UIの修正が一段落ついた
- メニューを実装して導線が張れた

ということで、crieitのサービスのレビュー掲示板でレビューを募集しています。

2/6進捗

昨日記事書けなかったので今日書きます。

概要

  • 配色の変更
  • react-sticky-footerの導入
  • フレーム解除
  • 試合結果ページ内の選手へのリンク追加

配色の変更

カード型コンテンツの配色パターンの決め方があったので参考にしてだいぶ改良しました。アクセントカラーはどこに置けばいいかわからずに結局すごく目立つところに置いてます。

react-sticky-footer

react-sticky-footer
コピーライトとかの表記ですね。
フッタがスクロール中は半透明になり、一番下までいくと指定したスタイルで見える、というコンポーネントです。

フレーム解除

reactのwindow.locationではページをフレーム内で表示していても、現在ブラウザがどこで表示しているか判定できないようだったので結局public/index.htmlにべた書きしました。

    <script type="text/javascript">
      if (top!=self) {
         top.location.href=self.location.href;
      }
    </script>  

試合結果ページから選手ページへのリンク

勝利・敗戦・セーブ・HRを記録した選手に選手ページへのリンクを追加しました。これでトップページ(試合開催日一覧)→試合結果→選手個人ページへの導線まではできたことになります。
肝心のスタッツが独立しているという。

2/5進捗

試合動画の埋め込み

image

コンテンツを活用したい

リーグのコンテンツとして試合動画を撮っているので上手く活用したいところです。

react-youtube

今回はreact-youtubeというパッケージを使っています。

データの紐付け

定石としてはDBにカラム作ってAPIで返すべきなのだとは思いますが、今回はjsonですらないです。

  • jsonにはしたいけどコメント書きたい

ということで試合IDをキーとしてyoutubeの動画IDを格納するファイルを作りました。
DBに追加するのと手間は同じぐらいだと思います。

export const youtubeConfig =
{
  //日付などのコメント
  "試合ID":"youtube動画ID",
}

これをreact内のループでこう書いてやります。

import { youtubeConfig } from './youtubeConfig'
(中略)
<YouTube
 videoId={youtubeConfig[試合ID]}
/>

CSSでアスペクト比を維持する

個人開発でcalcを使ったのは初めてです。
業務でもそんなに使ったことはないのですが...。
ブラウザの幅に応じて動画の幅を拡大縮小し、高さをアスペクト比を維持するように変えてやります。

iframe{
    width: 90%;
    height: calc(90vw*9/16);
  }

react-bootstrapのbreaking change

個人開発のちょっと恥ずかしい話(失敗談)です。
image

1.0からBootstrap4対応へ

react-bootstrap
Reactを使われている方は馴染みがあるかと思いますが、
0.32.4までがbootstrap3に対応しており、bootstrap4対応によって0.32.4から1.0.0-betaまで一気にバージョンが上がりました。
公式ではbootstrap3系と4系は分けてサポートしていくとアナウンスされています。

breaking changeに気づかなかった

昨年9月に1.0.0-betaがリリースされていましたが、知ったのは昨日。しかも「ドキュメントのフォーマットちょっと変わったなー」ぐらいの認識で見ていたのと、Cardコンポーネントが新たに追加されていたのでそちらの実装に気を取られていたのとでbreaking changeに気づいたのが今朝。昨夜デプロイしてたので一晩メインのページが落ちた状態でした...。

昼休みに直す

昨夜実装したコンポーネントをコメントアウトして一旦デプロイしなおし、エラー箇所のソースを確認していた際にようやくbreaking changeに気づく。Cardコンポーネントがある4系に寄せるか、3系に戻してCardコンポーネントがない状態で対応するか少し迷いましたがとりあえず3系に戻してCardはmaterializeCSSで対応しました。元々ベースのデザインにmaterializeCSSを採用しています。
結局昼休み30分ぐらい使って何とか直して再デプロイ。

2/3進捗

日付一覧実装

image
とりあえずreact-bootstrapのListGroup.itemを使って日付の一覧を入れ子で実装。アコーディオン化したいが時間ないので仮置き。
UIは練らないといけないが日付→日付別試合一覧への導線は完成。

日別試合一覧ページ実装

image
1日に3-5イニングの試合を3-5試合行うので日別の試合結果一覧ページを実装。投手成績とHRの本数を取得する処理が割と面倒で、試合直前までの成績を取得した後にその試合での成績を合算する処理をしないといけない。HR本数の取得処理は旧システムでも行っていたのでSQLをそのまま移植できると思っていたが、
その日までに成績がなく、その日の一番最初の試合に1号HRを打つとSQLで取得できないバグがあることに気づいた。

修正後のSQL

select 
    h.player_id,
    name,
    homerun,
    before_homerun_count
from 
    (SELECT
        b.player_id,
        name,
        homerun
    FROM batting_sum b
    inner join player p on p.id = b.player_id
    WHERE b.game_id= ? and b.homerun>=1
    group by player_id) h
left outer join (
    select
        b.player_id,
        sum(homerun) as before_homerun_count
    from batting_sum b
    inner join game g on g.game_id=b.game_id
    where
    ((game_date>= ? and game_date< ?)
    or (game_date= ? and game_number<= ? ))
    group by player_id) sum_homerun
on h.player_id = sum_homerun.player_id

あとはSQLの引数を渡す順番を間違えていて2時間ぐらい結果が取得できなくて嵌ってしまった。。

1/27進捗

全期間通算成績

現在入力している全てのシーズンのデータから通算成績を取得する処理を実装しました。
image
react側は旧システムAPIであらかじめ作っていたのもあって、
これにはそんなに時間がかかりませんでした。

本日から新シーズン始動

本日、2019年度前期シーズン開幕戦でした。
現行のReact/NodeJS/Netlifyのシステムでは初めての本格運用が始まります。

スコア入力

スコアの速報を入力していたのですがサーバサイド側で打率が0のときに打撃十傑から除く処理が抜けていたことに気づいてスコア入力を中断してシステムの修正を行うなど。

昨日の進捗

ReactでOGP対応した

1/23進捗

スタッツページから個人成績への遷移

image

ここのところreactでOGPを動的に変える方法を模索していて進捗が出ていませんでした。
これまでスタッツページから個人の成績ページへの遷移は打率タブの名前欄のみ実装していましたが、ノンタイトル以外のタブで個人成績へジャンプできるように実装しました。
また、選手名をマウスオーバーした際にスタイルを変えるよう実装しました。

1/20進捗

個人獲得タイトル

image
旧システムではAPI化していなかったものをAPI化してトロフィアイコンを組み込んでみました。

球団別投球成績

image

シーズンページ打者全成績・投手全成績実装

image

動的にOGP生成→失敗

react-helmetを使用してmetaタグを書き換えるとページごとにOGPを生成できるのではないかと思ったが、結果としては動的に生成している部分のタグが認識されず。
SSRしないとできない模様

1/17進捗

image

[API]期毎投球成績

期毎投球成績を返すAPIを実装しました。

[UI]シーズンセレクタ

ドロップダウンでシーズンを選択するコンポーネントを「シーズンセレクタ」と呼んでいますが、期毎打撃成績と期毎投球成績タブで共通のコンポーネントとする実装を行いました。

1/16

[UI]タブ入れ子問題修正

image
何となくマテリアルデザインを使っているのですが、
「マテリアルデザインではタブを入れ子にしてはいけない」というルールをつい先日知りまして。
タブの代わりにドロップダウンでシーズンを選択するように修正しました。
UX的にどうなんですかねー?

1/14進捗

1/14進捗

[UI]スコア入力画面実装中

image

[UI]

  • react-autocompleteを用いた選手名の候補表示
  • 数値入力コンポーネントの実装・スタイル調整

[API]

  • クライアントから投げられた検索クエリに対して選手候補の一覧を返す実装

[API]試合結果データ取得

image

[API]

  • 試合結果データを返す

フォーム(UI)と入出力の形が一致していないのでどこかで策定する必要あり。