発端
えー、ナニコレ?! かっちょええ~
って、なりますよね? 当然。
ならないなどという意見は認めません。
この記事、最後の方でちらっと「なでしこ」のことも紹介してくれているんだよね☆
文言には負けたくない!
SVGですよ
あまりにも素敵なので、思わずレンダリングしたものをダウンロードしてみたところ、SVG画像でした。
ベツに対抗するためにSVGを始めたわけじゃ無いんですが、これがSVG縦書きに良さそう! と思うきっかけになりました。
が!!!
文言のは、textを一文字一文字設定していますよ。シンタックスハイライトするなら、当然そうなりますね~。
今回、そこまではやりません(すでに負け💧)
原稿用紙
とりあえず、なでしこさんのコードのことは忘れて(え)、原稿用紙を描いていきましょうかね。
四角と線が描ければだいたいは描けますよ……と思ったら、真ん中のとこ「魚尾」とゆうマークがありますよ。その名の通り魚の尾っぽみたいな形だからです。
凝ったデザインのものもありますし、上下のデザインが異なり下は二重線とかになっているなどが多いですが、パスを使えばラシイ形がいくらでも作れそうではありますが、今回はめんどくさいので【】で代用
ぽい感じにするための細かい微調整に手間はかかりましたが、クリスマスツリーより全然カンタンでしたね♪
ちなみに、ブラザーのダウンロード素材のデザインを参考にして描画しました。色名がみんなステキなのよ
というわけで、できました!
コードは後でまとめてのせます。
50%に縮小していますが、こんなかんじ。
よきーよきー♪
うーん、これだけでテンション上がれる
テキスト
今回は、原稿用紙の中に空のテキストを埋め込んでおき、それにテキスト設定することで文章を書き換えられるようにする。
そのテキストですが、まとめてコピペした場合、位置に依らず要素を作成した順になるので、縦書き日本語の場合、右側から配置していかなきゃいけません。(別にこっからコピペしたコードが動くわけじゃないんだけど、一応ふつーの文章としては成立させたい)
普通にループでx,yを決めて描画していけば、左側からの描画になってしまうので、横線を描く時テキストの位置だけ先に決めておき、
### テキスト描画位置
行番号=行数-回数。
# 魚尾があるので半分以降は+1する
もし、(回数>行数/2+1)ならば、行番号=行数+1-回数。
文字描画位置[行番号]=[x+マス幅/2,y+文字余白/2]。
後から別途まとめて作成するってことにした。
# テキスト
書体にSVG文字フォント設定。
「{マス幅-文字余白}px」にSVG文字サイズ設定
無色にSVG線色設定。筆色にSVG塗り色設定。
行数回:
原稿用紙テキスト[回数-1]=文字描画位置[回数-1]に空をSVG縦書き文字描画。
それの「文字間」に「{文字余白}px」をDOMスタイル設定。
とりあえず、SVGの描画自体はこれでOK?
執筆
原稿用紙に執筆とか言うと、文豪感が出てかっこいい♪
イマドキ原稿用紙で書いてる先生もいらっしゃらないでしょうが。
原稿用紙のテキスト要素は行ごとの配列として管理されているので、文章を20文字で行揃えして、それを改行で区切って配列としたものを原稿とします。
それを、繰り返しで行毎にテキスト設定していけばいいだけ!
原稿=文章を行文字数で行揃えして、それを改行で区切る。
原稿を執筆。
●(Aを)執筆とは:
行数回:
もし、回数>(Aの要素数)ならば、此行=空。
違えば、此行=A[回数-1]。
原稿用紙テキスト[回数-1]に此行をテキスト設定。
行揃えについて頑張った件は、こちら。
ページめくり
でもまって!
原稿は20行以上あるかもしれません、ってかありますよね普通。
原稿は原稿用紙の行数毎に分割して、ページをめくれるようにしなくては。
「<<戻る」のボタン作成して、頁戻るボタンに代入。
「進む>>」のボタン作成して、頁進むボタンに代入。
##原稿用紙画面のイベント
頁進むボタンをクリックした時には、:
もし、現在頁<総頁数ならば、:
現在頁を1増やす。
原稿[現在頁-1]を執筆。
頁戻るボタンをクリックした時には、:
もし、現在頁>1ならば、:
現在頁を1減らす。
原稿[現在頁-1]を執筆。
# 頁分割
●(原稿を頁行数で)頁分割
変数 頁データ=空配列。変数 C=0。
原稿=原稿を改行で区切る。
(原稿の配列要素数)>0の間
頁データ[C]=原稿の0から頁行数を配列取出す。
C=C+1。
ここまで。
頁データで戻る。
ここまで。
原稿=文章を行文字数で行揃えして、20で頁分割。
総頁数=原稿の要素数。
原稿[0]を執筆。
こんな感じ?
テスト
!『https://n3s.nadesi.com/plain/bunsyo-seikei.nako3』を取り込む。
!『https://n3s.nadesi.com/plain/SVG.nako3』を取り込む。
描画中キャンバスの「高さ」に0をDOM属性設定。
文章=『 十八日、上田を発す。汽車の中等室にて英吉利婦人に逢う。「カバン」の中より英文の道中記取出して読み、眼鏡かけて車窓の外の山を望み居たりしが、記中には此山三千尺とあり、見る所はあまりに低しなどいう。実に英吉利人はいずくに来ても英吉利人なりと打笑いぬ。長野にて車を下り、人力車雇いて須坂に来ぬ。この間に信濃川にかけたる舟橋あり。水清く底見えたり。浅瀬の波舳に触れて底なる石の相磨して声するようなり。道の傍には細流ありて、岸辺の蘆には皷子花からみつきたるが、時得顔にさきたり。その蔭には繊き腹濃きみどりいろにて羽漆の如き蜻蛉あまた飛びめぐりたるを見る。須坂にて昼餉食べて、乗りきたりし車を山田まで継がせんとせしに、辞みていう、これよりは路嶮しく、牛馬ならでは通いがたし。偶〃牛挽きて山田へ帰る翁ありて、牛の背借さんという。これに騎りて須坂を出ず。足指漸く仰ぎて、遂につづらおりなる山道に入りぬ。ところどころに清泉迸りいでて、野生の撫子いと麗しく咲きたり。その外、都にて園に植うる滝菜、水引草など皆野生す。しょうりょうという褐色の蜻蛉あり、群をなして飛べり。日暮るる頃山田の温泉に着きぬ。ここは山のかいにて、公道を距ること遠ければ、人げすくなく、東京の客などは絶て見えず、僅に越後などより来りて浴する病人あるのみ。宿とすべき家を問うにふじえやというが善しという。まことは藤井屋なり。主人驚きて簷端傾きたる家の一間払いて居らす。家のつくり、中庭を囲みて四方に低き楼あり。中庭より直に楼に上るべき梯かけたるなど西洋の裏屋の如し。屋背は深き谿に臨めり。竹樹茂りて水見えねど、急湍の響は絶えず耳に入る。水桶にひしゃく添えて、縁側に置きたるも興あり。室の中央に炉あり、火をおこして煮焚す。されど熱しとも覚えず。食は野菜のみ、魚とては此辺の渓川にて捕らるるいわなというものの外、なにもなし。飯のそえものに野菜煮よといえば、砂糖もて来たまいしかと問う。棒砂糖少し持てきたりしが、煮物に使わんこと惜しければ、無しと答えぬ。茄子、胡豆など醤油のみにて煮て来ぬ。鰹節など加えぬ味頗旨し。酒は麹味を脱せねどこれも旨し。燗をなすには屎壺の形したる陶器にいれて炉の灰に埋む。夕餉果てて後、寐牀のしろ恭しく求むるを幾許ぞと問えば一人一銭五厘という。蚊なし。』
定数 母艦はDOM親要素。
定数 [行文字数,行数]=[20,20]。
定数 [上下余白,左右余白]=[50,70]。
定数 [マス幅,ルビ枠,版心]=[26,10,32]。
定数 [外枠線幅,内枠線幅]=[4,2]。
定数 枠幅は、外枠線幅+内枠線幅+1。
定数 描画幅は、(マス幅+ルビ枠)*行数+枠幅*2+版心。
定数 描画高さは、枠幅*2+マス幅*行文字数。
定数 用紙幅は、左右余白*2+描画幅。
定数 用紙高は、上下余白*2+描画高。
[用紙幅,用紙高]のSVG親要素作成して、原稿用紙SVGに代入。
変数 紙色は、「#F8F4E6」# 象牙色
変数 罫色は、「#CD8C5C」# 江戸茶
変数 筆色は、「#595857」# 墨
変数 書体は、「serif」
変数 文字余白は、4
無色にSVG線色設定。紙色にSVG塗り色設定。
[0,0,用紙幅,用紙高]へSVG四角描画。
# 外枠
罫色にSVG線色設定。無色にSVG塗り色設定。4にSVG線太設定。「直線」にSVG破線パターン設定。
[左右余白+外枠線幅/2,上下余白+外枠線幅/2,描画幅-外枠線幅,描画高さ-外枠線幅]へSVG四角描画。
2にSVG線太設定。
[左右余白+枠幅,上下余白+枠幅,描画幅-枠幅*2,描画高さ-枠幅*2]へSVG四角描画。
# マス目
1にSVG線太設定。「点線」にSVG破線パターン設定。
## 縦線
x=左右余白+枠幅+マス幅。y=上下余白+枠幅。y2=上下余白+枠幅+マス幅*行文字数。
行数*2+1回:
もし、回数=1ならば、続ける。
[x,y]から[x,y2]までSVG線描画。※縦線
もし、回数=行数+1ならば、x=x+版心。
もし、回数<行数+1ならば、:
もし、(回数%2=1)ならば、x=x+マス幅。
違えば、x=x+ルビ枠。
もし、回数>行数+1ならば、:
もし、(回数%2=0)ならば、x=x+マス幅。
違えば、x=x+ルビ枠。
## 横線
x=左右余白+枠幅。y=上下余白+枠幅。原稿用紙テキスト=空配列。文字描画位置=空配列。
行数+1回。※版心の分をプラス
y=上下余白+枠幅。
もし、回数=行数/2+1ならば、:
x=x+版心。続ける。※版心
もし、((回数≠1)かつ(回数<行数/2+1))または(回数>行数/2+1)ならば、x=x+(マス幅+ルビ枠)
### テキスト描画位置
行番号=行数-回数。
もし、(回数>行数/2+1)ならば、行番号=行数+1-回数。
文字描画位置[行番号]=[x+マス幅/2,y+文字余白/2]。
### 横線描画
※一番下は描画しない
行文字数-1回:
y=y+マス幅。
[x,y]から[x+マス幅,y]までSVG線描画。※横線
ここまで。
# 魚尾
罫色にSVG塗り色設定。「直線」にSVG破線パターン設定。
「sans-serif」にSVG文字フォント設定。「{版心}px」にSVG文字サイズ設定。
[左右余白+枠幅+(マス幅+ルビ枠)*(行数/2),上下余白+枠幅+マス幅*3]に「︻」をSVG文字描画。
[左右余白+枠幅+(マス幅+ルビ枠)*(行数/2),上下余白+枠幅+マス幅*(行文字数-3)]に「︼」をSVG文字描画。
# テキスト
書体にSVG文字フォント設定。
「{マス幅-文字余白}px」にSVG文字サイズ設定
無色にSVG線色設定。筆色にSVG塗り色設定。
行数回:
原稿用紙テキスト[回数-1]=文字描画位置[回数-1]に空をSVG縦書き文字描画。
それの「文字間」に「{文字余白}px」をDOMスタイル設定。
●(Aを)執筆とは:
行数回:
もし、回数>(Aの要素数)ならば、此行=空。
違えば、此行=A[回数-1]。
原稿用紙テキスト[回数-1]に此行をテキスト設定。
変数 原稿=空。変数 総頁数=1。
変数 現在頁=1。
母艦にDOM親要素設定。
改行作成。
「<<戻る」のボタン作成して、頁戻るボタンに代入。
「進む>>」のボタン作成して、頁進むボタンに代入。
##原稿用紙画面のイベント
頁進むボタンをクリックした時には、:
もし、現在頁<総頁数ならば、:
現在頁を1増やす。
原稿[現在頁-1]を執筆。
頁戻るボタンをクリックした時には、:
もし、現在頁>1ならば、:
現在頁を1減らす。
原稿[現在頁-1]を執筆。
# 頁分割
●(原稿を頁行数で)頁分割
変数 頁データ=空配列。変数 C=0。
原稿=原稿を改行で区切る。
(原稿の配列要素数)>0の間
頁データ[C]=原稿の0から頁行数を配列取出す。
C=C+1。
ここまで。
頁データで戻る。
ここまで。
原稿=文章を行文字数で行揃えして、20で頁分割。
総頁数=原稿の要素数。
原稿[0]を執筆。
まるっと貼り付けてお試しください。文章を書き換えれば好きな文章を原稿用紙に表示出来ます☆
できました!
イイ感じ♪
もう、だいたい満足(え)
問題点
なでしこさんのコードを原稿にして描画したいというのが本題でした。
文章のとこにコードを貼っ付ければ、それだけでもう一応、出来ることは出来るんですけれども、いろいろ良き感じにしたいですよね☆
と思ったら、、いくつか問題が……
半角英数が美しくない
半角英数が入ってくるととたんに表示が乱れるよねー
ネタで数字は全て漢数字に、英語も漢字を当ててやろうかと思ったのですが、ナゾの漢文みたいのが出現して、結局美しくないのでやめました💧
本来的に言えば、タテ組の日本語文の中にアルファベットの単語や文章が現れる場合は、そこだけ90度横に倒して挿入するのが普通で、そのためSVG縦書き文字描画
でもtext-orientation
にmixed
を指定しています。
が!
行揃えで安易に半角文字は2つで全角文字1つ分としたものの、横書きなら等幅フォントを使えばこれでピッタリ合うはずなのですが、縦書きだと全くもって合わないんですよね~。しくしくしく。
うーん、これは来年の課題かな(ええっ;)
あと、数字が二桁の時だけ、縦中横にするとゆう厄介なルールもある。
縦中横というのは、縦書きの向きのままで、一マスにその数字二文字だけをヨコ組で納めるという荒技(違;)
このためフツーの横書きの文章でも一桁の時だけ全角、二桁以上の時は半角にして打ったりしてしまいがちだけど、英数にだけ別フォントが割り当てられていたりすると、全角は日本語フォントなので見た目アレって感じになったりもするよね、~。
むー、これはさすがに無視したいなあ。やるとなれば、完全にテキスト要素を一文字ずつにばらさなきゃならない上に、その場その場で位置も計算し直さなきゃならなくなる……ツラみ
とゆうわけで!
最も簡単な方法としては、すべて全角変換だね!(えええっ💧)
全角なら日本語と同じなので、日本語と同じ向きで、一マス一文字で表示されます
AceEditorむじゅい
やっぱり、自分でコピペするんじゃなく、エディタのコードを自動的に流し込みたいですよね!
貯蔵庫エディタのIDを調べてテキスト取得してやろう。
これはもちろん想定外の所業で、現行のなでしこ貯蔵庫では動いても将来的に構成が変わったりしたら動かなくなりますけれども、ネタで作っているのでゆるして
ところが・・・
なでしこさんのコードを美しくシンタックスハイライト付きで表示してくれるだけじゃなく、入力補完や引数の表示など多彩な機能でなでしこのプログラミングを助けてくれる貯蔵庫のエディタはAceEditorの機能が使われています。
こっからテキストを取得するには一体どうしたらいいんだ。むじゅかしすぎる
でもひらめきました!
貯蔵庫エディタはクリック一つでtextareaとAceEditorの切り替えが出来るようになっています。ここにclick
を送ってやればいいじゃない☆
テキストエリアからならテキスト取得で簡単に取得できますよ。
AceEditorだったらclick
を送ってテキストエリアからコードを取得し、また素知らぬ顔でAceEditorに戻す・・・と思ったら素知らぬ顔とは行かず、切り替えるとどこにカーソルがあっても先頭に戻ってしまうけど、とりあえずできました!
テキスト設定やHTML設定で吹っ飛ぶ
やろうとしていたのはプログラムからプラグインのように取り込んだらそのプログラムのコードを取得して原稿用紙に描画するというもの。
取り込んだら即、そのためのボタンを出現させたりしたい。
ところが、そのボタンを設置したり、原稿用紙のSVGを準備した後に、元のプログラムが初期のDOM親要素に直接テキスト設定やHTML設定を行っていたら消えちゃいますよねぇ~。
原稿用紙をnako3_div以外のとこに突っ込むなどという暴挙も考えましたが、クリアを押してもボタンが消えなくなっちゃう上に、プログラム自体はクリアされてるので作動しなくなっちゃうという、かえってダメダメな感じで断念💧
とりあえず無難に、最後に新しいdivを作成して、それをDOM親要素に設定することにしました。
もし、DOM親要素ではなく、「nako3_div」を指定してテキスト設定やHTML設定を行っていたらダメですが、こればっかりはしょうがない😣
v3.4.3にやられまくる!
とりあえずできたできた~♪ あとはアップして記事を書くだけ~☆ と思ったあたりで、突然なでしこさんがばーじょんあっぷし、DOM属性設定
、DOM属性取得
の仕様が大幅に変更になったんですよよよよ~。
まず、これまでは属性の設定取得でもDOM和スタイルを参照していたのですが、DOM和属性が新設されてこちらを参照することに。
これにより、わたしがDOM和スタイルに追加して使っていた属性系のchecked
やhidden
やvalue
なんかが働かなくなってしまった。
チェックボックスやラジオボタン使ってるもの多いですからね~。
この原稿用紙でも「チェック」や「非表示」を使っていました。
v3.4.1のままなら動くんだけど、他から取り込んで遊ぶ前提のものだから、それじゃダメですよね。
安易に和スタイル追加のプラグインに和属性の項目を追加しようとしたら、以前作った旧バージョンで動いてるプログラムで「DOM和属性なんてない!」と怒られてしまったりしながら、とりあえず3.4.3以降の時だけ追加するように変更。
これで解決したかと思いきや!
「DOM属性設定」「DOM属性取得」が、getAttribute
、setAttribute
を使うように変更。
最初からこうであったなら、SVGの属性取得や設定で苦労することはなかったね。
でもこの影響が、ワタシ的には甚大で……
そもそもchecked
とかdisabled
、readonly
、hidden
とかとかといった属性は、論理属性といってその属性の存在自体によって効力を発揮するもので、本来属性値はありません。
もともとのなでしこのDOM属性設定は、プロパティ値を直接設定する仕様になっていて、0や空、FALSEなどの偽と判別されるものを設定した場合は属性自体が設定されず、1とかcheckedとかTRUEとかとか、その他の何かしらを設定した場合には真となって属性が設定されます。
プロパティの値は真か偽か、属性が存在するか否かなので、何を設定しても属性値はありません。
<input type="checkbox" checked>/*オンを設定*/
<input type="checkbox">/*オフを設定*/
ですから、
「オン」のチェックボックス作成して、チェック1に代入。
チェック1の「チェック」にオンをDOM属性設定。
とすることでチェックボックスにチェックが入りましたし、
チェック1の「チェック」にオフをDOM属性設定。
とすることで、すでにchecked属性の付与されているところからchecked属性を消して、未選択の状態にすることができました。
が!!!
setAttribute
さんは、どうやらとにかく設定するのがお仕事みたいなのねん。
0だろうが空だろうがFALSEだろうが、そのとうりに設定してくれちゃうのです。
<input type="checkbox" checked="1">/*オンを設定*/
<input type="checkbox" checked="0">/*オフを設定*/
たとえ属性値にfalseが設定されていようとも、属性が存在する以上trueなのです。
そして、setAttribute
さんには属性そのものを消すということは出来ないようです。
外出の予定があったので、「間に合わねーよぅ」と泣きながらお出かけして返ってきてみたら、他の方からもご報告が上がったようで、
直接ボタンの"disabled"にアクセスすることでこの問題に対処できます。
ボタン["disabled"] = オフ
とのお知らせが発表されておりました。
知ってますよよよ。
出来なくて困ってるんじゃない。これから新しく作るものはいいんです。過去に作ったものを新バージョンに対応させようと思ったら、全部、ことごとく修正をかけなきゃならんのが辛いのねん。っていうか、今このアドベントカレンダーに間に合わないのだよ。今日は時間がないのねん
宿題をギリまでやらないタイプの人の末路とも言いますが💧
ええい、面倒だ。DOM属性設定を元通りの仕様で上書きしてくれるわ!(キレ気味)
●(DOMの属性に値を)DOM属性設定
もし、(DOM和スタイルに属性が辞書キー存在)ならば、属性=DOM和スタイル[属性]。
もし、(DOM和スタイルに値が辞書キー存在)ならば、値=DOM和スタイル[値]。
DOM[属性]=値。
ここまで。
さすがにこれで解決しただろうと思ったら、まだダメだ! なんで~(発狂)
と思ったら、普通にDOM属性取得
でしたw
従来通りの仕様なら、属性が存在すればtrue、存在しなければfalseが返ります。
これによってチェックが入っているか否かが分かる仕組みです。
ところがgetAttribute
さんは、とにかく属性値を返してよこそうとします。
属性が存在しなければnullになりますね。そして……属性が存在しても本来属性値は存在しないのでnullになっちゃうんです!
もちろんsetAttribute
でなにかしら設定していればそれが返るので、それで判別出来るのですが、プロパティを直接設定していた場合は、どちらもnullになってしまうので、getAttribute
さんには判別できないのです。
まあいい、ぼやいてる場合じゃないよ! 時間が無いよ!! これも上書きだよ!!!
●(DOMの属性を)DOM属性取得
もし、(DOM和スタイルに属性が辞書キー存在)ならば、属性=DOM和スタイル[属性]。
DOM[属性]で戻る。
ここまで。
おっと、できたできた(喜)
できました!
つかいかた
プログラム冒頭で取り込んでください。
!『https://n3s.nadesi.com/plain/1949.nako3』を取り込む。
これで、「原稿用紙作成」のボタンが表示されます。
押すと、エディタに書かれているコードが原稿用紙に描画されます。そんだけ!
(冒頭に置くことの多い取り込み文は邪魔になるので原稿から削除しています)
「設定」のボタンを押すと、原稿用紙の色やフォントが変更出来ます。
お気に入りの原稿用紙を作りましょう☆
すべてのコードが美しい原稿用紙になるわけではありません。
頑張って、日本語らしいコードを書きましょうw
ダウンロードはSVG画像です。
「すべてのページ」を押すと、zip化などされることなくページ数分バラでダウンロードされますので、押す時は十分気をつけましょう
おわります
まにあわなかった……orz
いやいや、今は25日の深夜24時20分ですとも!
最後はバタバタになってしまいましたが、アドベントカレンダー2022、一応は完走できた……ということで!
参加してくださった方はもちろん、読んでくださった方々もありがとうございました!