【配布】AA/AAAモードをクライアント側で対応させるJavaScript【Blog/WordPress】

12/24/2020 0 Comments

AA/AAAモードとは

AAはアスキー・アートの略です。AAモードはおーぷん2ちゃんねるの機能で、AAを通常の書き込みと区別して、キレイに等幅フォントで示すためのものです。等幅フォントでは通常の書き込みが読み難い反面、プロポーショナルフォントではAAがズレてしまう、行間も適切に見えないといった問題を解決してくれました。

AAAモードはこれを一定の時間で表示を切り替えることによって、AAでアニメーションを行わせるという機能です。

仕様

工事中。暇ができたら書き足す。

導入方法

JavaScript

以下をコピペして、aamode.jsの名前で保存してください。

document.addEventListener('DOMContentLoaded', function () {
    //速度設定
    const baseTime = 1000;
    //速度設定に対するデフォルトの倍率
    const defaultWait = 0.2;
    //フォントサイズ設定
    const fontSize=16;
    //フォント色
    const fontColor='#000';
    //背景色
    const bgColor='#fff';
    //CSSで指定したフォントファミリ名
    const fontFace ='aahub_light';

    const targetClass = 't_b';
    const aaMarker = /!AA\s*<br[^>]*>/;
    const aaPreClass = 'aaview';
    const aaaPreClass = 'aaaView';
    const newLineRExp = /<br[^>]*>/g;
    const aaaMarker = /@(AAA|aaa)/;
    const aaaSplitter = '@@@';
    let aaaFlag = false;

    let postBodies = document.getElementsByClassName(targetClass);
    for (let postBody of postBodies) {
        if (aaMarker.test(postBody.innerHTML)) {
            let aaPre = document.createElement('pre');
            aaPre.setAttribute('class', aaPreClass);
            let str = postBody.innerHTML.split(aaMarker);
            postBody.innerHTML = str.shift();
            while (0 < str.length) {
                let lines = str.shift().replace(/\n/g, '').replace(newLineRExp, '\n').split('\n');
                while (0 < lines.length) {
                    if (!aaaMarker.test(lines[0])) {
                        aaPre.innerHTML += lines.shift() + '\n';
                    } else {
                        let aaaPre = document.createElement('div');
                        aaaPre.setAttribute('class', aaaPreClass);

                        let aaaInterval = document.createElement('div');
                        aaaInterval.setAttribute('style', 'display:none');
                        aaaInterval.setAttribute('class', 'interval');
                        aaaInterval.textContent = lines.shift().replace(aaaMarker, '').replace(':', '');

                        let aaaContent = document.createElement('div');
                        aaaContent.setAttribute('style', 'display:none');
                        aaaContent.setAttribute('class', 'content');
                        aaaContent.textContent = lines.join('\n');

                        let aaaDisplay = document.createElement('canvas');
                        aaaDisplay.setAttribute('class', 'display');

                        aaaPre.appendChild(aaaInterval);
                        aaaPre.appendChild(aaaContent);
                        aaaPre.appendChild(aaaDisplay);
                        aaPre.appendChild(aaaPre);
                        aaaFlag = true;
                        lines = [];

                        continue;
                    }
                }
                postBody.appendChild(aaPre);
            }
        }
    }
    if (aaaFlag) {
        const aaaDivs = document.getElementsByClassName(aaaPreClass);
        for (let aaaDiv of aaaDivs) {
            animateAaa(aaaDiv);
        }
    }
    function animateAaa(aaaDiv) {

        let interval = aaaDiv.getElementsByClassName('interval')[0].textContent;
        if ('' == interval || 0 == interval) {
            interval = baseTime * defaultWait;
        } else {
            interval = baseTime * parseFloat(interval);
        }
        const contents = aaaDiv.getElementsByClassName('content')[0].textContent.split(aaaSplitter + '\n');
        const canvas =aaaDiv.getElementsByClassName('display')[0];
        const ctx = canvas.getContext('2d');
        ctx.font = fontSize + "px aahub_light,sans-serif";

        let canvasSize = getCanvasSize(contents);

        canvas.width=(canvasSize.x+4)*(fontSize/2);
        ctx.width =canvas.width;
        canvas.height=canvasSize.y*(fontSize+1)*1.1;
        ctx.height= canvas.height;

        let i = 0;
        let max = contents.length;

        setInterval(() => {
            if (max == i) {
                i = 0;
            }
            ctx.font = fontSize + "px aahub_light,sans-serif";
            ctx.clearRect(0,0,canvas.width,canvas.height);
            ctx.fillStyle =bgColor;
            ctx.fillRect(0,0,ctx.width,ctx.height);
            showAA(ctx,contents[i]);
            i = (i+1)|0;
        }, interval);

        function getCanvasSize(contents){
            let size ={x:0,y:0};
            contents.forEach(element => {
                let lines =element.split('\n');
                size.y = Math.max(lines.length,size.y);
                for (let line of lines){
                    size.x = Math.max(line.length,size.x);
                }
            });
            return size;
        }
        function showAA(ctx,content){
            let lines = content.split('\n');
            for(let i=0;i<lines.length;i=(i+1)|0){
                ctx.fillStyle = fontColor;
                ctx.font = fontSize + 'px '+ fontFace' +',sans-serif";
                ctx.fillText(lines[i], fontSize/2, fontSize*(1.1*(2*i+3)/2));
            }
        }
    }
});

はじめの5つをお好みに設定してください。6つ目のフォントファミリ名については、CSSの項で述べます。

CSS/HTML

ローカルで表示を確認したい方は以下をコピペし、index.htmlという名前で保存してください。

ブログ・WordPressでのご利用の場合は、CSSに当たる部分を抜き出してコピペし、ご利用のブログ・WordPressで記事表示に適用されるCSSの中に含めてください。

<!DOCTYPE html>
<html lang="ja">

<head>
    <meta charset="utf-8" />
	<title>AA&AAAmodeTest</title>
        <script type="text/javascript" src="aamode.js"></script>
        <!--ココでフォント指定-->
    <style type="text/css">
            <!--
@font-face {
    font-family: "aahub_light";
    src: url("./fonts/aahub_light.woff2") format("woff2");
    font-display: swap;
}
.aaview {
    font-family: aahub_light, sans-serif !important;
    font-size: 16px !important;
    line-height: 18px !important;
    margin: auto;
    padding: 0.5em;
    white-space: pre;
    border: dotted 2px #c7dce3 !important;
    overflow-x: auto;
}
                -->
    </style>
</head>

<body>
<!--ここから下に「まとめくす」でコピーしたものを貼り付け-->
    
<p style="color:gray;text-align:right;">引用元: <a href="https://hayabusa.open2ch.net/test/read.cgi/livejupiter/1607385735/" target="_blank">なんでもAA</a></p><dl></dl><!-- Generated by まとめくす (https://2mtmex.com/) -->
<dl><dt >26: <span style="color: green; font-weight: bold;">名無しさん@おーぷん</span> <span style="color: gray;"> 20/12/08(火)09:47:34 ID:uwQ</span></dt>
<dd class="t_b" style="margin-bottom:4px;margin-top:2px;">  !AA<br />      \       はげって言ったやつだれだ・・・   /\  ノ<br />        \                         /- ̄   ̄`ヽ<br />   (~)     \       γ´⌒`ヽ         /γ´        ヽ<br /> γ´⌒`ヽ     \     (・ω・` )       /γ           ヽ<br />  {i:i:i:i:i:i:i:i:}       \     O┬O:::)      /  {i:i:i:i:i:i::i:i:i:i:i:i:i:i:i:::i:i:i:i:i:i:ii}<br /> ( ´・ω・)このセーター\  ◎┴し'-◎   / .   (~):i:i:i:i::i:i:i:i:i::i:i:i:i::i:i:i:i:i:i:i}<br />  (:::::::::::::) しまむらで  \  ∧∧∧∧/     γ´⌒`ヽ         ::|<br />   し─J  買ったんだ。   <    し >       {i:i:i:i:i:i:i:i:}l⌒l    l⌒l :::::|<br />_____________ <   ま >     (´・ω・`) ̄      ̄ ::::|<br />     /~~丶         < の む >      (::::::::つ          :::|<br />     \  ノ            < 予 ら >     ヽ__つ l⌒l    l⌒l ::|<br /> γ-´ ̄ ̄ ̄ ̄``ヽ キング < 感 く > ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄<br />γ          │しまむら < ! ん >      (~)   さむいね<br />{i:i:i:i:i:i:i:i::i:i:i:i:i:i:i::i::i:ii:i}    くん/∨∨∨∨      γ´⌒`ヽ<br />{i:i:i:i:i:i:i:i::i:i:i:i:i:i:i::i::i::i:i}     /        \    {i:i:i:i:i:i:i:i:}    うん、さむいね<br />/    ⌒      ヽ   /           \  ( ´・ω・)     (~)<br />|     ●   ● |  / (~)           \ (    )   γ´⌒`ヽ<br />ヽ、    (__人__) ノ /γ´⌒`ヽユニクロ行ってくる\し─J    {i:i:i:i:i:i:i:i:}<br /> /:::::::::::::::::::::::・:::::::::::/  {i:i:i:i:i:i:i:i:}     _____\      (・ω・` )<br /> |::::::::::::::::::::::::・::::::/   ( ´・ω・`)    | しまむら →| \     (    )<br /> ヽ、:::::::::::::::::::::/       (:::O┬O       ̄ ̄ || ̄ ̄   \     し─J<br />   |    /     ◎-ヽJ┴◎ キコキコ            \<br />   |__丿/                               \  </dd>
</dl>
<dl><dt >25: <span style="color: green; font-weight: bold;">名無しさん@おーぷん</span> <span style="color: gray;"> 20/10/17(土)17:41:28 ID:Wl9</span></dt>
<dd class="t_b" style="margin-bottom:4px;margin-top:2px;">  !AA<br />ズレてたから修正<br />@aaa:0<br />  /   /  /  /<br />  _n_<br /> ///|ヾ \ / /<br /> ⌒⌒|⌒⌒<br />/   |∧_∧ /  /<br />   |・ω・`)<br /> /  Oと  ) / /<br />、   しーJ ,.. ,. .。 _<br />@@@<br />/      /   /<br />  _n_/<br /> ///|ヾ \  /<br /> ⌒⌒|⌒⌒/   /<br /> /  |∧_∧   <br />   |・ω・`)  /<br />/   Oと  )   /<br />、   しーJ,  、,. 。<br />@@@<br />   /   /<br />  _n_     /<br /> ///|ヾ \ <br /> ⌒⌒|⌒⌒  /<br />/   |∧_∧   <br />   |・ω・`) /<br />  / Oと  )   /<br />。 、 しーJ.,  _._ 、,.<br />@@@<br /> /      /<br />  _n_  <br /> ///|ヾ \ /   /<br /> ⌒⌒|⌒⌒  <br />  / |∧_∧  /  /<br />   |・ω・`)   <br />/   Oと  )/    /<br />_.,   しーJ。 、 _ _._<br />@@@<br />/    /      /<br />  _n_   /<br /> ///|ヾ \  <br /> ⌒⌒|⌒⌒/    /<br />/   |∧_∧  /<br />   |・ω・`)    /<br /> /  Oと  )  /  /<br /> , ._ しーJ.,_ 。 .,. 、,.  </dd>
</dl>
<dl><dt >3: <span style="color: green; font-weight: bold;">名無しさん@おーぷん</span> <span style="color: gray;"> 20/12/06(日)00:37:04 ID:b6x</span></dt>
<dd class="t_b" style="margin-bottom:4px;margin-top:2px;">  !AA<br />@aaa<br />い<br />@@@<br />いk<br />@@@<br />いき<br />@@@<br />いきs<br />@@@<br />いきす<br />@@@<br />いきすg<br />@@@<br />いきすぎ<br />@@@<br />いきすぎい<br />@@@<br />イキスギイ  </dd>
<dt >19: <span style="color: green; font-weight: bold;">名無しさん@おーぷん</span> <span style="color: gray;"> 20/12/06(日)00:50:10 ID:qAn</span></dt>
<dd class="t_b" style="margin-bottom:4px;margin-top:2px;">  !AA<br />@AAA:0.1<br />る  さ<br />@@@<br />  さと<br />@@@<br /> さとる<br />@@@<br />さとる<br />@@@<br />とる  </dd>
</dl>

<!--ここまで。上の内容は削除してOK-->
</body>

</html>

上記では、AA表示に適したフォントを利用するため、こちらからaahub_lightをダウンロードし、利用するように記述してあります。ローカルで用いる場合はindex.htmlを置くフォルダの下に/fontsフォルダを作って置くか、同じフォルダに置いて上の記述の./fonts/を消すかして下さい。

使い方

index.htmlに書いた通り、まとめくすさんでレスを選んで出力したものを<body></body>の内部にコピペして、index.htmlをブラウザで開いてください。

おーぷんを利用する限りはAAAの更新速度の微調整は、HTML側の速度指定用の数値(!AAA:ここの数字)でしか変更できませんが、スクリプトを利用する場合はbaseTimeを自由に変更できますので、お好みの速度を作り出せることでしょう。

baseTimeはデフォルトで1000となっており、1000ミリ秒を表します。これに!AAAコマンドで指定した数値を掛けた秒数ごとに(ブラウザの能力が追いつく限りは)アニメーションの更新を行おうと努めます。コマンド指定が0.1ならば100ミリ秒、つまり0.1秒ごとです。baseTimeを1、コマンド指定を16にすれば0.016秒ごとの更新となり、秒間60フレームを少々上回るレートとなりますが、ブラウザ側がその速度を出せるかどうかは私にはわかりません。

工事中

以下、暇を見て必要な事項を書き足す予定。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です