みかづきブログ その3

本ブログは更新を終了しました。通算140万ユーザーの方に観覧頂くことができました。長い間、ありがとうございました。

👆

引越し先はこちらです!

404 NOT FOUND

  • 以前、ページのローディング中に ローリング・ストーンズ の曲が流れる 「ローディング・ストーンズ」 というページをつくったことがありました。


The Loading Stones - みかづきブログ その3



今回は、404ページ用に Mr.Children の NOT FOUND が流れるページ をつくってみようと思います。音楽の力は偉大ですね。





DEMO

※ PC版Chromeでご観覧ください。

JavaScript

(function(win) {

    "use strict";
    
    win.App = {};
    
})(this);

(function(win, doc) {

    "use strict";

    function EventDispatcher() {
        this._events = {};
    }

    EventDispatcher.prototype.hasEventListener = function(eventName) {
        return !!this._events[eventName];
    };

    EventDispatcher.prototype.addEventListener = function(eventName, callback) {
        if (this.hasEventListener(eventName)) {
            var events = this._events[eventName],
                length = events.length,
                i = 0;
    
            for (; i < length; i++) {
                if (events[i] === callback) {
                    return;
                }
            }

            events.push(callback);
        } else {
            this._events[eventName] = [callback];
        }
        
        return this;
    };

    EventDispatcher.prototype.removeEventListener = function(eventName, callback) {
        if (!this.hasEventListener(eventName)) {
            return;
        } else {
            var events = this._events[eventName],
                i = events.length,
                index;
    
            while (i--) {
                if (events[i] === callback) {
                    index = i;
                }
            }
    
            events.splice(index, 1);
        }
        
        return this;
    };

    EventDispatcher.prototype.fireEvent = function(eventName, opt_this, opt_arg) {
        if (!this.hasEventListener(eventName)) {
            return;
        } else {
            var events     = this._events[eventName],
                copyEvents = _copyArray(events),
                arg        = _copyArray(arguments),
                length     = events.length,
                i = 0;
    
            // eventNameとopt_thisを削除
            arg.splice(0, 2);
    
            for (; i < length; i++) {
                copyEvents[i].apply(opt_this || this, arg);
            }
        }
    
        function _copyArray(array) {
            var newArray = [],
                i = 0;
    
            try {
                newArray = [].slice.call(array);
            } catch(e) {
                for (; i < array.length; i++) {
                    newArray.push(array[i]);
                }
            }
    
            return newArray;
        }
    };

    function YTPlayer() {
        var _this = this,
            _player = null,
            isAutoStart = false;;

        EventDispatcher.call(this);

        _init();

        function _init() {
            var tag            = doc.createElement("script"),
                firstScriptTag = doc.getElementsByTagName("script")[0];

            tag.src = "https://www.youtube.com/iframe_api";
            firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);

            function onYouTubeIframeAPIReady() {
                _this.fireEvent("YOUTUBE_READY");
            }

            // export
            win.onYouTubeIframeAPIReady = onYouTubeIframeAPIReady;
        }

        function _onPlayerReady(evt) { // 動画再生準備完了時イベント
            var player = this.target;

            if (isAutoStart) {
                player.playVideo(); // 動画再生
            }
        }

        function _onPlayerStateChange(evt) { // 動画再生状態変更時イベント
            switch (this.data) {
                case -1: // 未開始
                    _this.fireEvent("UNSTARTED", this.target, evt);
                    break;
                case 0: // 再生終了時
                    _this.fireEvent("ENDED_VIDEO", this.target, evt);
                    break;
                case 1: // 再生開始時
                    _this.fireEvent("PLAYING_VIDEO", this.target, evt);
                    break;
                case 2: // 一時停止時
                    _this.fireEvent("PAUSED_VIDEO", this.target, evt);
                    break;
                case 3: // バッファリング
                    _this.fireEvent("BUFFERING_VIDEO", this.target, evt);
                    break;
//                case 5: // 頭出し済み
//                    break;
            }
        }

        /**
         * Playerを生成します
         * @param  {string}  id      // Player に置換する DOM の id属性(必須)
         * @param  {string}  videoId // YouTube の video ID(必須)
         * @param  {object}  opt_obj // オプション用のオブジェクト
         *         {number}  width       // プレイヤーの幅(省略時は640)
         *         {number}  height      // プレイヤーの高さ(省略時は480)
         *         {boolean} isAutoStart // 自動再生するか否か(省略時はfalse)
         * @return {object} // play, stopを持ったコントローラーオブジェクト
         */
        function build(id, videoId, opt_obj) {
            _player = new YT.Player(id, {
                    width   : (opt_obj && opt_obj.width)  || 640, // 動画幅
                    height  : (opt_obj && opt_obj.height) || 480, // 動画高さ
                    videoId : videoId,       // 動画ID
                    events  : {
                        onReady : function(player) {
                            _onPlayerReady.call(player, id);
                        },
                        onStateChange : function(player) {
                            _onPlayerStateChange.call(player, id);
                        }
                    },
                    playerVars: {
                        rel      : 0, // 関連動画
                        showinfo : 0, // 動画情報
                        controls : 0, // コントローラー
                        wmode    : "transparent" // z-indexを有効にする
                    }
                });

            isAutoStart = (opt_obj && opt_obj.isAutoStart) || false;

            return {
                play: play,
                stop: stop
            };
        }

        function play() {
            if (_player.playVideo) {
                _player.playVideo();
            } else {
                isAutoStart = true;
            }
        }

        function stop() {
            if (_player.stopVideo) {
                _player.stopVideo();
            }
        }

        this.build = build;
    }

    YTPlayer.originalConstructor   = YTPlayer.prototype.constructor;
    YTPlayer.prototype             = new EventDispatcher();
    YTPlayer.prototype.constructor = YTPlayer.originalConstructor;

    App.YTPlayer = {
        getInstance : function() {
            if (!YTPlayer.instance) {
                YTPlayer.instance = new YTPlayer();
            }

            return YTPlayer.instance;
        }
    };

})(this, document, App);

(function(win, doc, ns) {
    
    "use strict";
    
    var youTube = ns.YTPlayer.getInstance(),
        list = ["kCNpOe5S1B4", "nu8-7huFyvo"];
    
    youTube.addEventListener("YOUTUBE_READY", function() {
        var player = youTube.build("player", list[0], {
            width: win.innerWidth,
            height: win.innerHeight,
            isAutoStart: true
        });
    }).addEventListener("PLAYING_VIDEO", function() {
        player.style.opacity = 0.9;
        doc.body.style.background = "url(http://jsrun.it/assets/h/l/C/1/hlC13.png)";
    });

})(this, document, App);

ちょっぴりスケッチっぽく見えるように背景にノイズを足しているのがポイントです。最近はまっている 塊魂TRIBUTE からヒントを得ました。



本当は こちらの悩み に投稿された曲をAPIで取得して抽選しようと思ったのですが、とりあえずいまは NOT FOUND のみとなっております。

http://ongakusuri.com/topic/2731?comment_id=10687
http://ongakusuri.com/topic/2731?comment_id=10687



今回は以上です。