千字文 は,手習いとして前から順に読んでいくといいのでしょうが,一方で特定の文字がどう書かれてるか知りたいみたいなケースもあると思います. もちろん1000文字あるので,手元に書籍として千字文があるときに何ページ目を探せば目当ての字があるのか探すのが若干面倒ということが多い. 基本的には1ページ何文字あるのか調べたらあとは整数の商と剰余ですぐわかるから,簡単に作れるから作りたいなと思ってたのを作りました(語彙).
こんな感じのものです.コード的には極めて自明.
TODO
- 旧字/新字や異体字への対応が TODO (今は黃を黄で検索しても見つけてくれない)
- あとは文字のパーツから文字を検索できる を使ってみたい気がしている.
- 使いやすそうな画像があれば文字の該当する画像を表示するのもいいかもしれない
- 1ページにきっかり整数個の文字種類が含まれない(15文字/ページで1種類につき4体で4文字使ってるようなやつ)のは今の所対応しないと思う
コード
せっかくなので少し.
html
ちょっと苦労したのは(普段書き慣れてないので)本文の所.漢詩の4文字の組は paragraph 相当ではという謎の思い込みから<p>
で作っています.
<div id="senjimon-source"> <p class="senjimon">天地玄黃</p> ....
今のところ display:inline; float:left;
として順に積みあがるようにして, :nth-child(4n+1)
で clear:left
することで4段ごとに改行しています.
p.senjimon { width:7em; display:inline; float:left; background-color: rgba(252, 232, 210, 30%); } p.senjimon:nth-child(4n+1) { clear:left; }
本文中の見つかった文字のハイライトは,ちょっとトリッキーになってしまったがこういう形になるようにしています
<p class="senjimon the-phrase">金生<char class="the-char">麗</char>水</p>
でこう
p.the-phrase { background-color: rgba(229,192,152,80%); } .the-char { background-color: rgb(178, 255, 130); text-decoration:underline; font-weight:bold; }
javascript
なんか最近は fetch
がモダンらしいですね? ここ5年くらい殆ど js 書いてないからわからないんだけど…
var senjimon_text = ""; function main(){ fetch("./source/senjimon.txt") .then( (response) => {return response.text(); } ) .then( (txt) => { senjimon_text = txt; }) .then( init ); } function init() { document.getElementById("execute").onclick = function(){ search_char(); update_view(); return false; }; }
senjimon_text
に本文が入る.
普段ならなんか構造体作って色々渡し回していくところなんだけど,javascript でどう書くのか考えるのが面倒になったりもしたのでグローバルな感じの変数をがりがり更新する形にしてしまいました
function search_char() { let the_char = document.getElementById('qchar').value[0]; last_query = the_char; initial_page = parseInt(document.getElementById('initpage').value, 10); chars_per_page = parseInt(document.getElementById('charpage').value, 10); last_match_index = senjimon_text.indexOf(the_char); if (last_match_index >= 0) { last_match_page = Math.floor(last_match_index / chars_per_page); last_match_loc_in_page = last_match_index % chars_per_page; } else { last_match_page = -1; last_match_loc_in_page = -1; } }
何も考えずに lookup して収めておく.使うときは
function update_view() { document.getElementById("query").textContent = last_query; document.getElementById("match-index").textContent = format_index(last_match_index);
こうする.あとはハイライト足すところが頭わるい(どういうふうなDOM操作が綺麗か考えるところで面倒になった)ので書き直したい.
function add_highlights() { if (last_match_index < 0) { return false; } let phrase_idx = Math.floor(last_match_index / 4); let char_idx = last_match_index % 4; let phrase_node = document.getElementsByClassName("senjimon")[phrase_idx]; phrase_node.classList.add("the-phrase"); /// FIXME let the_phrase = phrase_node.textContent; phrase_node.innerHTML = "".concat( the_phrase.substring(0,char_idx), "<char class='the-char'>", the_phrase[char_idx], "</char>", the_phrase.substring(char_idx+1), ); }
というわけで
fetch
の雰囲気を感じたsubstring
ひさしぶりclassList
ひさしぶり
みたいな感じ.
あとは上に書いた TODO のうち異体字対応くらいはしたいですね.これも fetch
で json 読み込めばよさそうと思っている.