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

2019-01-13に作成

image
野球リーグスコア管理システムに関する進捗です。

使っている技術など

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

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

残りタスクリスト

trello

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

1/2 キャップ野球情報局リニューアル

2020.jpg
新年2本目のボード投稿になります。
(新年の実績としては1本目)

キャップ野球情報局

https://cap-baseball.com/

成績管理システムとの連携

今回の改修の目玉は、成績管理システム「みんなのSCORE」との連携です。
成績管理システムのデータベースを利用しているのでいわば兄弟サイトです。

試合結果の表示

  • リーグ戦
  • 練習試合
  • 大会(大福大会、佐倉大会など)

の結果をトップページで閲覧できるようになりました。
右下のページング部分から10件ずつ遡ることが可能です。

試合結果詳細

試合結果とともに関連するツイートの表示と
(あれば)試合動画の表示を行います。

チームページ


例:一橋大のページ
通算成績と直近の試合結果が表示されます。

使っている技術

  • ReactJS
  • Netlify
  • NodeJS
  • MySQL
  • Docker
  • nginx

今後の課題

  • 一回見ると飽きてしまう(リピーターがいない)
  • ブログ記事などの集約・紹介
  • コンテンツなどの充実
  • 個別記事とチームの紐づけ

CMS風サイトを作りました

ogp.jpg

CMS(ブログ)風サイトを作りました

以前、7月ごろに技術ブログを作ってみたという記事を書いたのですが、結局保守が面倒ということでボツにしまして。

URL

https://cap-baseball.com/

機能

トップページ

キーワードによる記事の絞込みが可能です。
新着記事とキーワードで探すメニューを用意しています。

記事ページ


主に試合結果を掲載しています。youtubeの埋め込みはmarkdownにソースを挿入するだけで問題なく動作しました。
あと、1文字目の色を変えるところに凝りました。

h1::first-letter{
  color: #468847;
}

技術

今回は記事を簡単に書けること(markdownとか)を目指して、ヘッドレスCMSを調査したのですが、コンポーネントの再利用を考えるとwordpressは除外、strapiやcontentfulも試してみたものの、データの準備に時間がかかり過ぎるので今回は見送りました。今回もDBレスで、マスタデータはjsonです。

ヘッドレスCMS

Kosugi Maruフォントへの移行

優勝ラインシミュレーター作りました。

急遽クソアプリ2 Advent Calendar 2019の1日目に参加することになりました。

計算を自動化するスプレッドシートを作っていて、やっぱりReactで書いた方が動的にスタイル変更できるしいいじゃない!と思って作りました。

どんなアプリ?


試合数、チームの成績をもとにリーグ戦の優勝ラインをシミュレーションします。勝率と勝ち点方式に対応しています。

制作期間

2019/12/01~
突貫で最低限の機能だけ作ったので今回はUIに凝っていないです。

URL

https://championship.netlify.com

工夫したところ

結果のテーブルヘッダを固定してスクロールできるようにしています。元々<table>タグで書いていたのですが、固定しようとすると横幅が一致しない問題が出てきたので<div>タグで初めてテーブル書きました。

div.table_header{
  display: table-row;
}
div.table_cell{
  display: table-cell;
  border: 0.5px solid #696969;
  padding: 2px;
  min-width: 4rem;
  text-align: right;
  white-space: nowrap;
}
div.scroll{
  overflow-y: scroll;
  height: 80vh;
}

把握している課題

  • UI
  • 試合数全てのパターンを計算・表示しているため、試合数に大きな数字を入れるとブラウザがメモリ不足で落ちる。
    • いずれかのチームに該当する結果があるまで表示しないようにする
  • チームの列入れ替え機能欲しい

10/12-14進捗

image

ランディングページの実装

カルーセルのtouch対応

先日の記事でreact-slideshowを推しましたが、スワイプに対応していないという問題があったのでいくつかtouchイベントに対応しているカルーセルコンポーネントを調査しました。

react-slick、君に決めた!

LINE風CSSの適用

会社の同僚にアイデアをもらったので自力で実装してみました。

 <div style={{
        padding:5
       }}
     >
            <div className="question">掲載料金はかかりますか?</div>             
            <div className="answer">いいえ。料金はかかりません.</div>
            <div className="question">データはどうやって登録するのですか?</div>
            <div className="answer">現在、運営がデータを入力する形となっていますのでデータをお送りください。</div>
        </div>
.question{
  width: 70%;
  position: relative;
  padding: 10px;
  background-color: #f2f3f7;
  font-size: 16px;
  color: #231815;
  border-radius: 12px;
  box-sizing: border-box;
  margin: 5px;
}
.answer{
  width: 70%;
  position: relative;
  left:50px;
  padding: 10px;
  background-color: #fde5e5;
  padding: 10px;
  font-size: 16px;
  color: #231815;
  border-radius: 12px;
  box-sizing: border-box;
  margin: 5px;
}

webフォントの軽量化

https://gist.github.com/manabuyasuda/b5c867a7cbd17d1eb905b3a8cfd621a6

flexboxを実装する


今回はグリッドレイアウトを使わずにflex-boxを使いました。
幅500pxを境界に、flex-directionを切り替えるメディアクエリを書きます。flex-directionを切り替えるのと同時に画像をウインドウの50%か100%に切り替えます。
サイズの異なる画像を並べるのにobject-fit : coverが便利でした。

JSX

const imageLink = (toLink,image_url,text) => {
    return(
          <div 
            style={{
              position:'relative'
            }}
          >
            <div
              style={{
                fontSize: 20,
                cursor:'pointer',
                position:'relative'
              }}
              onClick={()=>{
                window.location.href= toLink
              }}
            >
              <img 
                style={{
                  height:'20vh',
                  objectFit:'cover'
                }}
                src={image_url}/>
              <span
                  style={{
                    fontSize: 20,
                    color:'aliceblue',
                    textShadow:'2px 2px 2px black',
                    position:'absolute',
                    top:0,
                    left:0
                  }}
                >{text}
              </span>
            </div>
          </div>
    )
  }

CSS

@media(max-width:500px){
  .flex-parent{
    display: flex;
    flex-direction: column;
  }
  .flex-parent img{
    width: 100vw;
  }
}
@media(min-width:501px){
  .flex-parent{
    display: flex;
    flex-direction: row;
  }
  .flex-parent img{
    width: 50vw;
  }
}

参考
- Flexbox【第1回】並べる方向 〜flex-direction編〜
- 縦横比の違う画像を均等に横並びにする方法
- 画像の上におしゃれに文字やボタンをのせる方法

キャップ野球全国大会の非公式特設サイトを作った件

桜咲く佐倉蓋ざんまい

非公式特設サイト作りました。

先週末に千葉県佐倉市で開催されたキャップ野球の全国大会の結果をまとめたサイトをCRA(CreateReactApp)でサクッと作りました。
結局手直し含めると2.5人日ぐらいです。

テーマカラーは運営の公式twitterのロゴがこんな感じだったので
(実際は改行されているけれども)そこから採用しました。
カラーピッカーでだいたいの色コードを入れてそこから構成します。
今回はグラデーション使えるようになったので楽しくて多用しています。え、昔マーキーとかいっぱい使いませんでした?(インターネット老人会)

ちなみに、この後さらにUIをいじっています。
どこが変わったかわかるかな?

なぜ作ろうと思ったか

最初は手書きしかないトーナメントをまとめるだけ...のつもりだったのですが、どうせならリーグ戦も表示させたいなーと思い、
よさそうなツールを探したのですが、あまりピンとくるものがなくて自分で書いてしまった次第。最近UI書くの楽しすぎる問題

大会といえば

トーナメント結果と表彰状に個人開発のサービスを採用しています。いつもお世話になっております...!
2.png

トーナメント

おおにしさんの「THE TOURNAMENT」ですよね。

表彰状

鉄板のあんどさんの「WEB表彰」ですよね。

大会概要とか


体裁的にあった方がいいかなーと思ったのですが、
まあ誰も見ませんよね...!

ご意見・ご要望お待ちしています!

快適に楽しく使ってもらえるのが制作者冥利に尽きるので。

終わりに

最近このボードの野球リーグスコア管理システムの進捗があまり出ていません。何だかんだver2で安定しています...w

チーム成績登録API実装完了

チーム成績登録API実装完了

node-mysql2が数値を文字列として返してくる

おかげでtoFixed()とかコケます。parseFloat(文字列を小数にパースするメソッド)とか間に挟みました。

undef判定はちゃんと書きましょう

undefの判定に! valueって書いてたらvalue0で躓きましたw

テーブルの大文字小文字に注意しましょう

今回からdockerコンテナを使い始めたのですが、小文字のテーブルを大文字でSQL書くと認識しません。やっぱりlinuxですね。

エンドポイント調整

複数リーグ対応のためにUIからAPIに渡すパラメータなどを増やす必要があるので調整。

サンプルデータ投入しながらデバッグ

関東キャップリーグさんの試合データが公開されているので入力していきます。
1カード分探しても見つからなかったのですが。

シーズンスタッツ

image

日別試合結果一覧

image

試合結果詳細

image

2/27進捗

概要

image

昼休み開発

サーバサイドは夜に差し替え。
夜は運営者ギルドでのKoretteさんのレビュー会に参加。

選手ページの打撃成績に出塁率・長打率・OPSを表示するよう修正

  • スマホ版(375px未満)は非表示

選手一覧API

  • 名前を昇順にソートする(全件表示・検索結果)

2/14-15進捗

概要

image

  • 選手一覧(UI)
  • 選手一覧(API)

選手一覧

現在右上メニューバー内から遷移できます。

UI

チームの一覧と所属選手一覧を実装しました。materializeのchipsを使用しています。それから、チーム名・選手名検索ができるフォームの実装をしました。今回は所属チームごとの表示の振り分けをクライアント側で行うようにしました。チームの一覧を最近試合を行った順に並び替えできていないのが課題です。

API

フォームに何も入力されていないときは選手一覧を返すようにして、
入力された場合はAPIに検索結果を取りに行く方式にしています。
フォームがクリアされるとまた選手一覧を取得します。

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/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分ぐらい使って何とか直して再デプロイ。

1/27進捗

全期間通算成績

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

本日から新シーズン始動

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

スコア入力

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

昨日の進捗

ReactでOGP対応した

1/23進捗

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

image

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