Screen Display Log

ipadやiphone用に、画面にログを出力する。console.log() の代わりに screenLog() で利用する。

2026/05/10のページです。最新版はこちら

このスクリプトは単体で利用できません。右のようなメタデータを含むスクリプトから、ライブラリとして読み込まれます: // @require https://update.greasyfork.org/scripts/577436/1820897/Screen%20Display%20Log.js

スクリプトをインストールするには、Tampermonkey, GreasemonkeyViolentmonkey のような拡張機能のインストールが必要です。

You will need to install an extension such as Tampermonkey to install this script.

スクリプトをインストールするには、TampermonkeyViolentmonkey のような拡張機能のインストールが必要です。

スクリプトをインストールするには、TampermonkeyUserscripts のような拡張機能のインストールが必要です。

このスクリプトをインストールするには、Tampermonkeyなどの拡張機能をインストールする必要があります。

このスクリプトをインストールするには、ユーザースクリプト管理ツールの拡張機能をインストールする必要があります。

(ユーザースクリプト管理ツールは設定済みなのでインストール!)

このスタイルをインストールするには、Stylusなどの拡張機能をインストールする必要があります。

このスタイルをインストールするには、Stylus などの拡張機能をインストールする必要があります。

このスタイルをインストールするには、Stylus tなどの拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

(ユーザースタイル管理ツールは設定済みなのでインストール!)

このスクリプトの質問や評価の投稿はこちら通報はこちらへお寄せください
// ==UserScript==
// @name         Screen Display Log
// @namespace    http://tampermonkey.net/
// @version      1.0
// @description  ipadやiphone用に、画面にログを出力する。console.log() の代わりに screenLog() で利用する。
// @grant        none
// ==/UserScript==

(function () {
    'use strict';

    /**
     * 画面端にデバッグ用UIを表示するクラス
     */
    class ScreenLogger {
        constructor() {
            this.id = 'tm-debug-console';
            this.container = null;
            this.logArea = null;
            this._setup();
        }

        /**
         * 初期セットアップ
         */
        _setup() {
            if (document.getElementById(this.id)) return;
            this._injectStyles();
            this._createUI();
        }

        /**
         * CSSを<style>タグとして注入(インラインスタイルの撤廃)
         */
        _injectStyles() {
            const style = document.createElement('style');
            style.textContent = `
                #${this.id} {
                #${this.id} { position: fixed; bottom: 10px; right: 10px; width: 280px; max-height: 250px; background-color: rgba(0, 0, 0, 0.85); color: #00ff00; font-size: 11px; font-family: monospace; padding: 5px; border-radius: 5px; overflow-y: auto; z-index: 999999; pointer-events: auto; border: 1px solid #444; box-shadow: 0 0 10px rgba(0,0,0,0.5); }
                #${this.id} .tm-header { border-bottom: 1px solid #444; margin-bottom: 5px; padding-bottom: 3px; display: flex; justify-content: space-between; align-items: center; }
                #${this.id} .tm-header b { color: #fff; }
                #${this.id} button { font-size: 9px; cursor: pointer; margin-left: 4px; }
                #${this.id} .tm-log-area { display: block; }
                #${this.id} .tm-line { border-bottom: 1px solid #222; padding: 2px 0; white-space: pre-wrap; word-break: break-all; }
                #${this.id}.minimized { height: 25px; overflow: hidden; }
                #${this.id}.minimized .tm-log-area { display: none; }
            `;
            document.head.appendChild(style);
        }

        /**
         * UI要素の構築
         */
        _createUI() {
            this.container = document.createElement('div');
            this.container.id = this.id;

            const header = document.createElement('div');
            header.className = 'tm-header';
            header.innerHTML = `
                <span><b>[DEBUG]</b></span>
                <div>
                    <button id="tm-clear-log">Clear</button>
                    <button id="tm-toggle-log">Min</button>
                </div>
            `;

            this.logArea = document.createElement('div');
            this.logArea.className = 'tm-log-area';

            this.container.appendChild(header);
            this.container.appendChild(this.logArea);
            document.body.appendChild(this.container);

            // イベントリスナーの登録
            this.container.querySelector('#tm-clear-log').onclick = () => this.clear();
            this.container.querySelector('#tm-toggle-log').onclick = (e) => this._toggle(e.target);
        }

        /**
         * 表示・非表示の切り替え
         */
        _toggle(btn) {
            const isMinimized = this.container.classList.toggle('minimized');
            btn.innerText = isMinimized ? 'Max' : 'Min';
        }

        /**
         * ログの消去
         */
        clear() {
            if (this.logArea) this.logArea.innerHTML = '';
        }

        /**
         * 引数を文字列に整形(HTML要素、オブジェクト対応)
         */
        _format(arg) {
            if (arg === null) return 'null';
            if (arg === undefined) return 'undefined';

            if (arg instanceof HTMLElement) {
                const id = arg.id ? `#${arg.id}` : '';
                const classes = arg.className ? `.${Array.from(arg.classList).join('.')}` : '';
                return `<${arg.tagName.toLowerCase()}${id}${classes}>`;
            }

            if (typeof arg === 'object') {
                try {
                    return JSON.stringify(arg);
                } catch (e) {
                    return String(arg);
                }
            }

            return String(arg);
        }

        /**
         * 画面にログを出力
         */
        log(...args) {
            const msg = args.map(arg => this._format(arg)).join(' ');
            const line = document.createElement('div');
            line.className = 'tm-line';
            line.innerText = `> ${msg}`;

            this.logArea.appendChild(line);
            this.container.scrollTop = this.container.scrollHeight;
        }
    }

    /**
     * 外部から呼び出すためのエントリーポイント
     */
    function initOnScreenConsole() {
        const logger = new ScreenLogger();
        // 既存の「関数として呼び出す」挙動を維持するため、メソッドをバインドして返す
        return logger.log.bind(logger);
    }

    // 利用開始
    const screenLog = initOnScreenConsole();

})();