みかづきブログ その3

3ヶ月つづけてみました。

Chromeに風邪を引いてもらおう。

こんにちは。すっかり寒くなってきましたね。
僕は昔から風邪を引きやすいので、この時期は特に気をつけなければなりません。

風邪を引くという言葉に関しては、個人的に思うところがあります。
風邪のほかに引く病気はないので、引くは病気に関して言えばいわば風邪専用の動詞です。
ほかの病気と違って、なんで風邪だけは引くっていうんでしょう。
謎は深まるばかりです。

そんなこんなで、今日はブックマークレットをつかってChomeに風を引いてもらうことに挑戦してみましょう。
下記リンクを思い切ってクリック or ブックマークレットとしてつかってみてください。

風邪を引いてみる


いかがでしょう。
くしゃみのようなエフェクトでChromeが、
"か"、"ぜ"、"カ"、"ゼ"、"風"、"邪"という文字を引いてくれたのではないでしょうか。

f:id:kimizuka:20131127184304p:plain
(エフェクトを派手にするためだけに風邪という文字を使いまくってみました)

ブックマークレットにすればいくつかのサイトで風邪を引いてくれると思います。
Wikipediaもこの通りです。


f:id:kimizuka:20131127184305p:plain

動作原理

実行しているスクリプトはこんな感じです。

(function(win, doc) {

    "use strict";

    var $sickSpanList = [];

    if (checkWebkit()) {
        getVirus();
    }

    function checkWebkit() {
        var ua = win.navigator.userAgent.toLowerCase();

        return /chrome/.test(ua) || /safari/.test(ua);
    }

    function getVirus() {
        var $body       = doc.body,
            $pList      = convertToArray($body.querySelectorAll("p")),
            $divList    = convertToArray($body.querySelectorAll("div")),
            $liList     = convertToArray($body.querySelectorAll("li")),
            $dtList     = convertToArray($body.querySelectorAll("dt")),
            $ddList     = convertToArray($body.querySelectorAll("dd")),
            $h1List     = convertToArray($body.querySelectorAll("h1")),
            $h2List     = convertToArray($body.querySelectorAll("h2")),
            $h3List     = convertToArray($body.querySelectorAll("h3")),
            $h4List     = convertToArray($body.querySelectorAll("h4")),
            $h5List     = convertToArray($body.querySelectorAll("h5")),
            $h6List     = convertToArray($body.querySelectorAll("h6")),
            $domList    = $pList.concat($divList).
                                 concat($liList).
                                 concat($dtList).
                                 concat($ddList).
                                 concat($h1List).
                                 concat($h2List).
                                 concat($h3List).
                                 concat($h4List).
                                 concat($h5List).
                                 concat($h6List),
            index       = 0;

        convertToArray($domList).forEach(function($dom) {
            convertToArray($dom.childNodes).forEach(function($domChild) {
                if ($domChild.nodeType === 3) { // TextNodeのみを抽出
                    $domChild.textContent = $domChild.textContent.replace(/か/g, "<<span<<か>>span>>");
                    $domChild.textContent = $domChild.textContent.replace(/ぜ/g, "<<span<<ぜ>>span>>");
                    $domChild.textContent = $domChild.textContent.replace(/カ/g, "<<span<<カ>>span>>");
                    $domChild.textContent = $domChild.textContent.replace(/ゼ/g, "<<span<<ゼ>>span>>");
                    $domChild.textContent = $domChild.textContent.replace(/風/g, "<<span<<風>>span>>");
                    $domChild.textContent = $domChild.textContent.replace(/邪/g, "<<span<<邪>>span>>");
                }
            });
            $dom.innerHTML = $dom.innerHTML.replace(/&lt;&lt;span&lt;&lt;/g, "<span class='virus'>");
            $dom.innerHTML = $dom.innerHTML.replace(/&gt;&gt;span&gt;&gt;/g, "</span>");
        });

        $sickSpanList = convertToArray($body.querySelectorAll("span.virus")).map(function($sickSpan) {
            return new PandemicSpan($sickSpan);
        });

        setTimeout(catchCold, 500);

        function PandemicSpan($span) {
            var elm          = $span,
                defaultStyle = "; " +
                               "display: inline-block; " +
                               "-webkit-transition: all 1s ease; "  +
                               "-webkit-transform: rotateZ(0deg); " +
                               "font-size: 100%;" +
                               "opacity: 1;",
                queue        = [zoomIn, zoomOut, zoomIn, zoomOut, explode, vanish],
                achooFlag    = false,
                index        = 0;

            constructor();

            function constructor() {
                elm.style.cssText += defaultStyle;
                elm.addEventListener("webkitTransitionEnd", function(evt) {
                    if (!!achooFlag && evt.propertyName === "font-size") {
                        ++ index;
                        if (index < queue.length) {
                            queue[index]();
                        } else {
                            index = 0;
                        }
                    }
                }, false);
            }

            function achoo() {
                achooFlag = true;
                queue[index]();
            }
            function zoomIn() {
                elm.style["font-size"] = "200%";
            }
            function zoomOut() {
                elm.style["font-size"] = "50%";
            }
            function explode() {
                elm.style["-webkit-transform"] = "rotateZ(360deg)";
                elm.style["font-size"] = "5000%";
                elm.style["opacity"] = "0";
            }
            function vanish() {
                elm.style.display = "none";
                achooFlag = false;
            }

            // export
            return {
                elm:   elm,
                achoo: achoo
            };
        }
        function catchCold() {
            if (index < $sickSpanList.length) {
                $sickSpanList[index].achoo();
                ++index;
                catchCold();
            }
        }
    }

    function convertToArray(domList) {
        return Array.prototype.slice.call(domList);
    }

})(this, document);


簡単に解説するとサイト内のp要素、div要素、li要素、dt要素、dd要素、h1 〜 h6要素の中から、
"か"、"ぜ"、"カ"、"ゼ"、"風"、"邪"の文字列を探索し、回転を掛けながらふっ飛ばしています。
なので、現状ではすべての"か"、"ぜ"、"カ"、"ゼ"、"風"、"邪"を引いているわけはありません。非常に残念です。

さらに、横着して、webkitTransitionEnd、-webkit-transition、-webkit-transformをつかってエフェクトをつくってしまったので、
風邪を引けるのはChromeSafariなどのwebkit系のブラウザのみとなっております。


今回は以上です。
風邪には気をつけましょう。