今日やったこと
統計年鑑の主産地データ(2022年産収穫量)から、都道府県の農作物クイズを実装した。みかんの1位はどこか、りんごの1位はどこか、といった4択を、左のSVGチャートと連動させながら順に解いていくページ。
最初は別プロジェクト(書籍ナレッジベース側)に作ったのだが、リポジトリを横断して動かすうちに「mdx-playground 側に置いた方が読み手が触りやすい」と判断して移植した。同じVueでもページの作法が違うため、まるごと書き換えになった。
完成形
左ペインに横棒の都道府県ランキングをSVGで描き、右ペインに同じ品目の4択問題を縦に並べる。スクロールすると右ペインの問題カードが切り替わり、左ペインのチャートも同期して切り替わる。矢印キー(←→)で前後の問題に移動でき、右ペインも一緒に動く。
詰まったところ
IntersectionObserverのバンドが狭すぎた
最初の実装では、画面中央付近を判定バンドにしていた。Q1を読んでいるつもりなのに、画面の上下にQ2/Q3の端が入った瞬間に左ペインの図が切り替わってしまう。「Q1のチャートが見たいのに、Q3のチャートが表示される」状態で、初期表示の時点ですでに崩れていた。
判定バンドの上下マージンを広げ、画面の中央付近に厚みを持たせて、Q1がはみ出にくいようにした。ここはEurekapu-NUXT4のQuizPageを参考にしつつ、しきい値だけ調整している。
自動スクロール中にObserverが拾いすぎる
矢印キーでQ2に飛ぶときに、スクロールが滑っていく途中で Observer がQ1とQ2の境目を一瞬拾い、左ペインの図がチラチラ切り替わる現象が出た。
suppressObserverUntil というタイムスタンプを Ref に持たせて、自動スクロール開始から900msのあいだは Observer の callback を return で打ち切るようにした。ユーザーの自然スクロール時には反応する、矢印キーでの飛び移動時には黙る、という二段構えになる。
// 概念だけ抜粋
if (Date.now() < suppressObserverUntil.value) return
ユーザーから細かい指示が連続して入った
ここからが今日の本番。一度動くようになってからの調整が長かった。
- 正解の色: 最初はマゼンタで「正解!」を出していた。「正解は緑、誤答はグレーに✗マーク」と指示が入り、配色を組み直した。マゼンタはたしかに目立ちすぎて、画面を見るたびに目が痛い
- 解説の出し方: 「正解の選択肢だけに解説」ではなく「選択肢全部の末尾に解説を出す」に変更。誤答を選んだ人にも、なぜそれが違うのかが届く
- 解説の中身: 「なぜ和歌山がみかん1位なのか」「なぜ静岡・愛媛が続くのか」を細かく書いた。地形・気候・歴史の3点を毎回入れる形に統一
- 件名(都道府県名)を隠す: グラフの棒に最初から「和歌山」と書いてあったら答えがバレる。回答前は順位だけ、回答後に「9-1 和歌山」のように表示する形に変えた
- 「いまここ」表示: 現在の問題カードに active クラスを当て、濃いグレー(#4b5563)の枠線と影を載せた。スクロール中にどのカードが採点対象なのか目で追える
- フォントと選択肢: 解説は16px、行間1.75に上げた。選択肢は縦並びだと縦に間延びするので、横4列に並べ直した
- 解説の見出し: v-html を使い、【日本全体の偏り】【1位 ○○が首位の理由】を独立行の太字で出す
修正のたびにブラウザを再読み込みして、選択肢を1つ選んでみて、また指示が飛んでくる。1往復で1つの違和感を潰していく作業を10往復ほど続けた。
index.vue への動線
「学習・クイズ」セクションに🗾アイコンのカードを追加して、トップから一気に飛べるようにした。ここを作っておかないと、せっかく実装したクイズが奥に埋まる。
学び
- IntersectionObserverは「拾いすぎ」と「拾わなさすぎ」のあいだに細い谷がある。バンド幅と suppress 時間の両方を持っておくと安定する
- 正解色をマゼンタにしてはいけない。緑+グレー+✗が、目に優しいし意味も伝わる
- 「正解の選択肢にだけ解説を出す」と、誤答を選んだ人にとっては何が起きたのか分からない。全選択肢に同じ解説を出す方が、教材としては親切
- UIは画面を見ながら指示が飛んできて初めて磨かれる。最初に全部決めようとせず、まず動かして、見ながら直す方が早い
明日やること
- 統計データブックの他ページ(工業出荷額・人口など)も同じ枠組みでクイズ化できるか試す
- スマホ幅で左ペインが潰れるので、768px以下では左右を縦積みに切り替える
- 正答率を localStorage に保存して、復習モードを用意する