Greasy Fork

Greasy Fork is available in English.

下書き君(画像)v1.6.1

ピクトセンスに画像をオーバーレイ表示して模写・下書きを支援!iPadでもズレずに使える!

// ==UserScript==
// @name         下書き君(画像)v1.6.1
// @namespace    http://tampermonkey.net/
// @version      1.6.1
// @description  ピクトセンスに画像をオーバーレイ表示して模写・下書きを支援!iPadでもズレずに使える!
// @author       虚言癖
// @match        https://pictsense.com/*
// @grant        none
// @license      MIT
// ==/UserScript==

(function () {
    'use strict';
  //UIの設定 操作パネルもろもろ
    const imageContainer = document.createElement("div");
    imageContainer.id = "imageOverlayUI";
    Object.assign(imageContainer.style, {
        position: "fixed",
        bottom: "10px",
        right: "10px",
        backgroundColor: "#222",
        padding: "6px",
        borderRadius: "6px",
        color: "#fff",
        fontFamily: "Arial,sans-serif",
        userSelect: "none",
        boxShadow: "0 0 6px #000",
        zIndex: 10000,
        fontSize: "12px",
        lineHeight: "1.4",
        cursor: "grab",
    });
    //UIのHTML 操作パネルの見た目いじりたいときはこのへんいじればいいよ。
    imageContainer.innerHTML = `
        <div style="font-weight:bold; margin-bottom:6px; cursor: grab;">🖼 下書き君(画像)</div>
        <input type="file" id="imageInput" accept="image/*" style="margin-bottom:4px; font-size: 11px; background-color: #222; color: white; border: none; padding: 2px;" />
        <label style="display:block; margin-top:4px;">サイズ</label>
        <input type="range" id="imageSize" min="10" max="200" value="100" style="width:100%; margin-bottom:4px; accent-color: #555;" />
        <label style="display:block;">透明度</label>
        <input type="range" id="imageOpacity" min="10" max="100" value="100" style="width:100%; margin-bottom:4px; accent-color: #555;" />
        <button id="lockBtn" style="width:100%; font-size:11px; margin-top:4px; background-color: #444; color: white; border: none; padding: 4px;">🔒 固定モード OFF</button>
        <button id="removeBtn" style="width:100%; font-size:11px; margin-top:4px; background-color: #844; color: white; border: none; padding: 4px;">画像を消す</button>
    `;

    document.body.appendChild(imageContainer);

    const imageInput = document.getElementById("imageInput");
    const imageSize = document.getElementById("imageSize");
    const imageOpacity = document.getElementById("imageOpacity");
    const lockBtn = document.getElementById("lockBtn");
    const removeBtn = document.getElementById("removeBtn");

    //出した画像の設定もろもろ
    const overlayImage = document.createElement("img");
    overlayImage.style.position = "fixed";
    overlayImage.style.top = "150px";
    overlayImage.style.left = "20px";
    overlayImage.style.zIndex = 9999;
    overlayImage.style.pointerEvents = "auto";
    overlayImage.style.opacity = 1;
    overlayImage.style.maxWidth = "none";
    overlayImage.style.maxHeight = "none";
    overlayImage.style.cursor = "move";
    overlayImage.style.transformOrigin = "top left";
    document.body.appendChild(overlayImage);

    let currentScale = 1;
    let locked = false;

    imageInput.addEventListener("change", (e) => {
        const file = e.target.files[0];
        if (!file) return;
        const reader = new FileReader();
        reader.onload = (event) => {
            overlayImage.src = event.target.result;
            overlayImage.style.display = "block";
        };
        reader.readAsDataURL(file);
    });

    //サイズを変えるスライダーで変える。
    imageSize.addEventListener("input", () => {
        currentScale = imageSize.value / 100;
        overlayImage.style.transform = `scale(${currentScale})`;
    });

    //透過度。スライダーでオーパシティをいじる。
    imageOpacity.addEventListener("input", () => {
        const opacity = imageOpacity.value / 100;
        overlayImage.style.opacity = opacity;
    });

  //画像を動かないようにするボタンドラッグを無効にする。
    lockBtn.addEventListener("click", () => {
        locked = !locked;
        overlayImage.style.pointerEvents = locked ? "none" : "auto";
        overlayImage.style.cursor = locked ? "default" : "move";
        lockBtn.textContent = locked ? "🔓 固定モード ON" : "🔒 固定モード OFF";
    });

    removeBtn.addEventListener("click", () => {
        overlayImage.src = "";
        overlayImage.style.display = "none";
    });

    let dragging = false;
    let offsetX = 0, offsetY = 0;

    overlayImage.addEventListener("mousedown", (e) => {
        if (locked) return;
        dragging = true;
        const rect = overlayImage.getBoundingClientRect();
        offsetX = (e.clientX - rect.left) / currentScale;
        offsetY = (e.clientY - rect.top) / currentScale;
        e.preventDefault();
    });

    document.addEventListener("mousemove", (e) => {
        if (!dragging || locked) return;
        overlayImage.style.left = `${e.clientX - offsetX * currentScale}px`;
        overlayImage.style.top = `${e.clientY - offsetY * currentScale}px`;
    });

    document.addEventListener("mouseup", () => {
        dragging = false;
    });
        //タッチ系。AIに任せた。
    overlayImage.addEventListener("touchstart", (e) => {
        if (locked) return;
        const touch = e.touches[0];
        const rect = overlayImage.getBoundingClientRect();
        const scale = window.visualViewport ? window.visualViewport.scale : 1;
        offsetX = (touch.clientX - rect.left) / (currentScale * scale);
        offsetY = (touch.clientY - rect.top) / (currentScale * scale);
        dragging = true;
        e.preventDefault();
    }, { passive: false });

    document.addEventListener("touchmove", (e) => {
        if (!dragging || locked) return;
        const touch = e.touches[0];
        const scale = window.visualViewport ? window.visualViewport.scale : 1;
        overlayImage.style.left = `${touch.clientX - offsetX * currentScale * scale}px`;
        overlayImage.style.top = `${touch.clientY - offsetY * currentScale * scale}px`;
    }, { passive: false });

    document.addEventListener("touchend", () => {
        dragging = false;
    }, { passive: false });

    let uiDragging = false;
    let uiOffsetX = 0, uiOffsetY = 0;

    imageContainer.addEventListener("mousedown", (e) => {
        if (["INPUT", "BUTTON", "LABEL"].includes(e.target.tagName)) return;
        uiDragging = true;
        const rect = imageContainer.getBoundingClientRect();
        uiOffsetX = e.clientX - rect.left;
        uiOffsetY = e.clientY - rect.top;
        imageContainer.style.cursor = "grabbing";
        e.preventDefault();
    });

    document.addEventListener("mousemove", (e) => {
        if (!uiDragging) return;
        imageContainer.style.left = `${e.clientX - uiOffsetX}px`;
        imageContainer.style.top = `${e.clientY - uiOffsetY}px`;
        imageContainer.style.bottom = "auto";
        imageContainer.style.right = "auto";
    });

    document.addEventListener("mouseup", () => {
        uiDragging = false;
        imageContainer.style.cursor = "grab";
    });

    imageContainer.addEventListener("touchstart", (e) => {
        if (["INPUT", "BUTTON", "LABEL"].includes(e.target.tagName)) return;
        const touch = e.touches[0];
        const rect = imageContainer.getBoundingClientRect();
        uiOffsetX = touch.clientX - rect.left;
        uiOffsetY = touch.clientY - rect.top;
        uiDragging = true;
        imageContainer.style.cursor = "grabbing";
        e.preventDefault();
    }, { passive: false });

    document.addEventListener("touchmove", (e) => {
        if (!uiDragging) return;
        const touch = e.touches[0];
        imageContainer.style.left = `${touch.clientX - uiOffsetX}px`;
        imageContainer.style.top = `${touch.clientY - uiOffsetY}px`;
        imageContainer.style.bottom = "auto";
        imageContainer.style.right = "auto";
    }, { passive: false });

    document.addEventListener("touchend", () => {
        uiDragging = false;
        imageContainer.style.cursor = "grab";
    }, { passive: false });
})();