react-leaflet事始め
何気なくよく使っているGoogleMap、 googleの公式サイト以外で使おうとすると料金がかかるのを知っていますか? ということで、Google MapsAPIを使わずに地図表示する方法を調べてみました。
Leaflet.jsというオープンソースの地図表示ライブラリがありました。 leafletjs.com こちらはreactコンポーネント化したライブラリ react-leaflet.js.org
react-leafletトラブルシューティング
delete L.Icon.Default.prototype._getIconUrl; L.Icon.Default.mergeOptions({ iconRetinaUrl: require("leaflet/dist/images/marker-icon-2x.png"), iconUrl: require("leaflet/dist/images/marker-icon.png"), shadowUrl: require("leaflet/dist/images/marker-shadow.png") });
<Map center={position} zoom={this.state.zoom} style={{ height: 600 }} > <TileLayer attribution='© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors' url="https://{s}.tile.osm.org/{z}/{x}/{y}.png" /> {markers} </Map>
完成
- 日本地図を表示しながら時系列で各地点どのような出来事があったかをアニメーション表示する
- 各チームの拠点にチームアイコンを表示する という機能を追加しました。 cap-baseball.com
参考
パワプロ風画面ジェネレータを作りました。
サービスのURL
https://pawapro-gen.netlify.com/
どんなサービスか
下記のようなフォームを埋めると、 野球における自分の能力をパワプロ風に表現できるというサービスです。
キャップ野球に対応
一般的な野球と、キャップ野球にも対応しています。 例:「蓋」速など。
その他の機能
- 左右での変化球の反転に対応
- 入力内容をブラウザに保存できる
使っている技術
- ReactJS
- SASS
- Netlify
苦労したところ
変化球の変化量をどのようにHTML/CSSで表現するか、
というところが一番の難関だったのですが、
基本的にCSSのtransform(rotate)
だけで何とかなりました。
入力内容に応じて、tdにclassを与えてCSSで色を定義しています。
td.breaking_ball{ background-color:#6ba5e7ba; border: #0e5eb9 2px solid; height: 8px; margin: 0px; padding: 0px; min-width: 8px; &.change{ &:nth-child(1){ background-color: #df6a0bab; } &:nth-child(2){ background-color: #e9be4ac2; } &:nth-child(3){ background-color: #ffeb3bd6; } &:nth-child(4){ background-color: #e9be4ac2; } &:nth-child(5){ background-color: #df6a0bab; } &:nth-child(6){ background-color: red; } } }
今後の改修予定
- 最大変化量を7段階にする
- 第二変化球を設定できるようにする
- レスポンシブ(モバイル対応)
- オリジナル変化球の追加ができるようにする
- オリジナルの特殊能力を追加できるようにする
- 打者用のジェネレータを作る
情報局リニューアル第2弾
crieitの作ったサービスのレビュー依頼掲示板に投稿して、競技を知っている人、知らない人から見て今のサービスはどう映っているのか率直な意見を募ってみた。
- スポーツのサイトとしては動きが足りない
- 全体的に説明が足りない(初見〇し)
- ユーザに導線を明示する
という意見をいただいたので、その点に気を付けながら再構築してみた。
「キャップ野球って?」タブ
動きを出すために動画を一番上に持ってきて、キャップ野球に関する簡単なルールの説明と、「活気が伝わってくる」とのブログ投稿一覧は残して、開催されているリーグや大会を写真で見せることに。
NPBのサイトとか阪神のサイトを参考にメリハリをつけてみた。
以前はテキスト中心だったので思い切って画像を上手く使う方法を模索。
「チームを探す」タブ
まだ野暮ったい印象が抜けないデザインではあるけど、
テキスト中心(元々markdownベース)だったのをチームアイコンをふんだんに使って視覚に訴える形に変更した。
練習会カレンダータブ
timetreeなどのUIからよいなと思ったところ(日付の数字を強調するなど)を吸収させてもらっている。
試合結果タブ
チームを(データ登録されている)試合数で並び替える機能と、試合結果一覧を閲覧できる機能を統合。1行に押し込んでいて窮屈だったUIを改行することで余裕をもたせている。
pixela APIを使ってアクセス数を可視化する
作っているサービス
pixelaという草を生やすAPIをチームページのアクセスカウンタに使ってみます。
pixelaとは
pixelaのAPIドキュメント
開発者(a-knowさん)
実装に使う技術
API側
言語など:NodeJS
pixelaの3rd partyライブラリを使います。 github.com
実装
createGraph
とincrementPixel
というメソッドを作って、各チームページにアクセスされるたびにcreateGraphを呼びます。
重複している場合はAPIから400エラーが返ってくるのでハンドリングしつつ、
カウントアップするメソッドを実行します。
export class pixelaLogic { public createGraph(team) { return new Promise(async(resolve,reject)=>{ try { let response = await client.createGraph({ id: "team"+team[0].team_id.toString(), name: team[0].team_name.toString(), unit: "access", type: "int", color: "shibafu" }); //console.log(response.status); resolve(response.status); } catch (error) { resolve(500) } }) } public incrementPixel(team):Promise<number>{ return new Promise(async(resolve,reject)=>{ let response; try { response = await client.incrementPixel('team' + team[0].team_id) console.log(response.status) return resolve(response.status) } catch (error) { console.error(error); return resolve(500); } }) } }
生成されたグラフのリスト
UI側
ReactJS
グラフの埋め込みを行います。
<iframe src={'https://pixe.la/v1/users/ckoshien/graphs/team'+ store.getState().team.team_id +'.html?mode=simple'} height="150" width="600" frameborder="0" />
a-knowさんとmottox2さんは運営者ギルドのギルドメンバーでもあります。 (私も) qiita.com
D3.jsで日本地図に地点をプロットしてツールチップを表示してみる
作ったもの
キャップ野球チームの全国分布図を作成。
- チームカラー
- (あれば)チーム旗
動作イメージ
地図データの準備
地図データはshapeファイルで提供されているものをGeoJSON→topojson化する。
npm i topojson -g
$ wget http://www.naturalearthdata.com/http//www.naturalearthdata.com/download/10m/cultural/ne_10m_admin_1_states_provinces.zip
# zip解凍 $ unzip ne_10m_admin_1_states_provinces.zip
# ogr2ogrが含まれているgdalをインストールする $ brew install gdal
# GeoJSONから日本のデータのみ抽出してtopoJson化する $ ogr2ogr -f GeoJSON -where "adm0_a3 = 'JPN'" ne_pref_japan_geo.json ne_10m_admin_1_states_provinces.shp
CRAでd3を扱う
準備
# d3とtopojson-clientをインストールする $ npm i --save d3 topojson-client
reactでzoom機能を扱う
コンストラクタでzoom機能を定義する
this.zoom = d3 .zoom() .scaleExtent([-5, Infinity]) .translateExtent([ [-100, -100], [200, 300] ]) .extent([ [0, 0], [0, 0] ]) .on("zoom", this.zoomed.bind(this));
zoomしたときに再描画を発火させるのがミソ。
zoomed() { this.setState({ zoomTransform: d3.event.transform }); }
点をプロットする
プロットする点のデータ構造
{ name:"学習院大", y:35.71, x:139.7, teamId: 73, color:"lightblue" },
データから円を書く
svg .append("g") .attr("id", "circle-g") .selectAll("circle") .data(teamInfo) .enter() .append("circle");
円を塗りつぶす
データで定義した色で塗りつぶします。 マウスオーバーしたときにツールチップに表示する情報や、 表示の切り替えなどもここで記述しています。
svg .selectAll("#circle-g circle") .attr("fill", (d)=>{ return (d.color !== undefined ? d.color :'gray') }) //.attr("opacity", 0.5) .attr("transform", function(d) { var coord = projection([d.x, d.y]); return "translate(" + coord.join(",") + ")"; }) .on("mouseover", function(d) { //console.log(d.name); tooltip .style("display", "block") .html( `<div> <h1>${d.name}</h1> <div style={{ display: flex, margin: 10px }} > <img src="/images/${d.teamId}.jpg" width="100" /> </div> </div>` ) }) .attr("r", 5 / (d3.event !== null ? d3.event.transform.k : 1));
参考
ReactでRSSを取得する
右側の余白が頭痛の種
キャップ野球情報局ではレスポンシブ対応を行っています。
ただ、2カラムレイアウトにするとどうしても右側に余白ができてしまう問題がありました。
そこで意見を募った結果、新着ブログ記事を表示してほしいなどの意見があったので早速実装しました。
rss-parserを使う
再び立ちはだかるCORS
ブラウザでは、セキュリティの観点から、あるサイトで異なるサイトのデータを読み込むことに制限を設けています。それがCORS (Cross-Origin Resource Sharing)です。
解決策
基本的にCORSはサーバ側で'Access-Control-Allow-Origin'ヘッダを付加することによって解決できますが、amebaとかnoteのサーバの設定を変えてくださいとはお願いできないので、 プロキシサーバーを経由することが一般的です。
ありがたいことに、herokuを使ったプロキシサーバが用意されています。
これでブログのRSSが取得できます。
実装編
import Parser from 'rss-parser'; import moment from 'moment'; componentDidMount(){ (async () => { const blogs = [ 'https://note.com/mpre/rss', 'http://rssblog.ameba.jp/capfuta/rss20.xml', 'https://note.com/kumagae_capthrow/rss', 'http://rssblog.ameba.jp/tohru-cap/rss20.xml' ] let parser = new Parser(); let feeds = []; for(let i = 0; i < blogs.length; i++){ let feed = await parser.parseURL('https://cors-anywhere.herokuapp.com/'+blogs[i]); //console.log(feed.items); feeds = feeds.concat(feed.items); } feeds.sort((a,b)=>{ if(moment(a.pubDate) > moment(b.pubDate)){ return -1; }else{ return 1; } }) this.setState({ blogs:feeds }) })() .catch(err=>{ console.error(err); }); }
参考
CRAにSCSSを導入しました
CRA(create-react-app)にSCSSを導入した話。
node-sassをnpmインストールする
npm i -D node-sass
.cssファイルを.scssにリネーム
scssで書いてみる
このような3色の四角の囲みを使っているのですが、
div.topic{ position: relative; top: 0px; padding: 5px; border-radius: 5px; margin: 0px 5px 5px 5px; overflow-x: scroll; max-width: 400px; font-size: 14px; &.border_green{ border:1px solid #386537; } &.border_pink{ border:1px solid #BF7A87; } &.border_blue{ border:1px solid #1F72A6; //トップページyoutube用style iframe#widget2{ max-width: 400px; max-height: 300px; } }
ベースのスタイルを書いて色だけ分岐させるのはこう書けるようです。
埋め込みyoutubeのスタイル指定にメディアクエリを使います。 SCSSの場合は変数を使うこともできますが、ベーシックな書き方を使ってみます。
iframe{ //youtube &#widget2{ @media (max-width: 400px) { width: 100%; height: 300px; } @media (min-width: 400px) { max-width: 600px; } } }
上記画像のサービス
キャップ野球とは
ペットボトルキャップとウィッフルバットで使う野球の縮小型競技。
20191229 【キャップ野球】交流会練習試合 第二試合 A 10-2 B ダイジェスト【MUCtC主催】
ウィッフルバット
ウィッフルボール専用バットとボール1個付き WIFFLE ball
- メディア: スポーツ用品
グリップテープもおすすめ
ヨネックス(YONEX) テニス バドミントン グリップテープ ウェットスーパーグリップ ケース付き (5本入り) AC1025P ワインレッド
- 発売日: 2013/07/05
- メディア: スポーツ用品