Custom-Cursor | 自定义鼠标

custom cursor in page / 自定义鼠标

当前为 2023-12-22 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         Custom-Cursor | 自定义鼠标
// @namespace    http://tampermonkey.net/
// @version      1.0.2
// @description  custom cursor in page / 自定义鼠标
// @license      MIT
// @email        [email protected]
// @author       DQLean
// @match        *://*/*
// @icon         http://tampermonkey.net/favicon.ico
// @grant        GM_registerMenuCommand
// @grant        GM_getValue
// @grant        GM_setValue
// ==/UserScript==

(function () {
  'use strict';

    /*
 * ATTENTION: The "eval" devtool has been used (maybe by default in mode: "development").
 * This devtool is neither made for production nor for readable output files.
 * It uses "eval()" calls to create a separate source file in the browser devtools.
 * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
 * or disable the default devtool with "devtool: false".
 * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
 */
/******/ (() => { // webpackBootstrap
/******/ 	"use strict";
/******/ 	var __webpack_modules__ = ({

/***/ "./data.js":
/*!*****************!*\
  !*** ./data.js ***!
  \*****************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

          eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ({\r\n    \"n-resize\": {\r\n        list: [],\r\n        index: 0,\r\n    },\r\n    \"s-resize\": {\r\n        list: [],\r\n        index: -1,\r\n    },\r\n    \"wait\": {\r\n        list: [],\r\n        index: -1,\r\n    },\r\n    \"nw-resize\": {\r\n        list: [],\r\n        index: -1,\r\n    },\r\n    \"se-resize\": {\r\n        list: [],\r\n        index: -1,\r\n    },\r\n    \"sw-resize\": {\r\n        list: [],\r\n        index: -1,\r\n    },\r\n    \"ne-resize\": {\r\n        list: [],\r\n        index: -1,\r\n    },\r\n    \"help\": {\r\n        list: [],\r\n        index: -1,\r\n    },\r\n    \"e-resize\": {\r\n        list: [],\r\n        index: -1,\r\n    },\r\n    \"w-resize\": {\r\n        list: [],\r\n        index: -1,\r\n    },\r\n    \"pointer\": {\r\n        list: [],\r\n        index: -1,\r\n    },\r\n    \"move\": {\r\n        list: [],\r\n        index: -1,\r\n    },\r\n    \"not-allowed\": {\r\n        list: [],\r\n        index: -1,\r\n    },\r\n    \"default\": {\r\n        \"list\": [],\r\n        \"index\": 2\r\n    },\r\n    \"copy\": {\r\n        list: [],\r\n        index: -1,\r\n    },\r\n    \"crosshair\": {\r\n        list: [],\r\n        index: -1,\r\n    },\r\n    \"text\": {\r\n        list: [],\r\n        index: -1,\r\n    },\r\n});\n\n//# sourceURL=webpack:///./data.js?");

          /***/
}),

/***/ "./i18n.js":
/*!*****************!*\
  !*** ./i18n.js ***!
  \*****************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

          eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   \"En\": () => (/* binding */ En),\n/* harmony export */   \"Zh\": () => (/* binding */ Zh),\n/* harmony export */   \"t\": () => (/* binding */ t)\n/* harmony export */ });\nconst lang = window.language || navigator.language || navigator.userLanguage;\r\n\r\nconst t = (val) => {\r\n    if (lang.startsWith(\"zh\")) {\r\n        return Zh[val] || val\r\n    }\r\n    if (lang.startsWith(\"en\")) {\r\n        return En[val] || val\r\n    }\r\n    return val\r\n}\r\n\r\nconst En = {\r\n    \"default\": \"Default\",\r\n    \"pointer\": \"Pointer\",\r\n    \"crosshair\": \"Crosshair\",\r\n    \"move\": \"Move\",\r\n    \"e-resize\": \"East Resize\",\r\n    \"ne-resize\": \"North East Resize\",\r\n    \"nw-resize\": \"North West Resize\",\r\n    \"n-resize\": \"North Resize\",\r\n    \"se-resize\": \"South East Resize\",\r\n    \"sw-resize\": \"South West Resize\",\r\n    \"s-resize\": \"South Resize\",\r\n    \"w-resize\": \"West Resize\",\r\n    \"text\": \"Text\",\r\n    \"wait\": \"Wait\",\r\n    \"help\": \"Help\",\r\n    \"copy\": \"Copy\",\r\n    \"not-allowed\": \"Not Allowed\",\r\n\r\n    \"imageUploadLimit128\": \"Image upload limit is 128KB!\",\r\n    \"imageUploadLimit64\": \"Image upload limit is 64KB!\",\r\n    \"imageUploadLimit32\": \"Image upload limit is 32KB!\",\r\n    \"imageUploadLimit16\": \"Image upload limit is 16KB!\",\r\n    \"imageUploadLimit8\": \"Image upload limit is 8KB!\",\r\n\r\n    \"imageLink\": \"Image Link\",\r\n    \"pleaseClickToSelectCenter\": \"Please click to select center point (as mouse origin). Support keyboard direction key fine-tuning.\",\r\n    \"imageTypeLimit\": \"Image must be .png or .cur format!\",\r\n\r\n    \"confirm\": \"Confirm\",\r\n\r\n    \"clickToUploadImage\": \"Click to upload image\",\r\n\r\n    \"pleaseInputImageName\": \"Please input name\",\r\n\r\n    \"setting\": \"Setting\",\r\n\r\n    \"clear\": \"Clear Data\",\r\n}\r\n\r\nconst Zh = {\r\n    \"default\": \"默认\",\r\n    \"pointer\": \"指针\",\r\n    \"crosshair\": \"十字线\",\r\n    \"move\": \"移动\",\r\n    \"e-resize\": \"向左调整\",\r\n    \"ne-resize\": \"向左上调整\",\r\n    \"nw-resize\": \"向右上调整\",\r\n    \"n-resize\": \"向上调整\",\r\n    \"se-resize\": \"向左下调整\",\r\n    \"sw-resize\": \"向右下调整\",\r\n    \"s-resize\": \"向下调整\",\r\n    \"w-resize\": \"向右调整\",\r\n    \"text\": \"文本\",\r\n    \"wait\": \"等待\",\r\n    \"help\": \"帮助\",\r\n    \"copy\": \"复制\",\r\n    \"not-allowed\": \"禁用\",\r\n\r\n    \"imageUploadLimit128\": \"图片上传限制为128KB!\",\r\n    \"imageUploadLimit64\": \"图片上传限制为64KB!\",\r\n    \"imageUploadLimit32\": \"图片上传限制为32KB!\",\r\n    \"imageUploadLimit16\": \"图片上传限制为16KB!\",\r\n    \"imageUploadLimit8\": \"图片上传限制为8KB!\",\r\n\r\n    \"imageLink\": \"图片链接\",\r\n    \"pleaseClickToSelectCenter\": \"请点击选择中心点(作为鼠标原点),支持键盘方向键微调。\",\r\n    \"imageTypeLimit\": \"图片必须为.png或者.cur格式!\",\r\n\r\n    \"confirm\": \"确认\",\r\n\r\n    \"clickToUploadImage\": \"点击上传图片\",\r\n\r\n    \"pleaseInputImageName\": \"请输入名称\",\r\n\r\n    \"setting\": \"设置\",\r\n\r\n    \"clear\": \"清除数据\",\r\n}\n\n//# sourceURL=webpack:///./i18n.js?");

          /***/
}),

/***/ "./index.js":
/*!******************!*\
  !*** ./index.js ***!
  \******************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

          eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _data_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./data.js */ \"./data.js\");\n/* harmony import */ var _i18n_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./i18n.js */ \"./i18n.js\");\n\r\n\r\n\r\n\r\nconst cursors = (() => {\r\n    try {\r\n        return GM_getValue(\"cursorData\", _data_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"])\r\n    } catch {\r\n        return _data_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"] || {}\r\n    }\r\n})()\r\n\r\ntry {\r\n    GM_registerMenuCommand((0,_i18n_js__WEBPACK_IMPORTED_MODULE_1__.t)(\"setting\"), createMenu)\r\n}catch{}\r\n\r\nconst cursorKeys = [\r\n    \"default\", \"crosshair\", \"pointer\", \"move\",\r\n    \"e-resize\", \"ne-resize\", \"nw-resize\", \"n-resize\", \"se-resize\", \"sw-resize\", \"s-resize\", \"w-resize\",\r\n    \"text\", \"wait\", \"help\", \"copy\", \"not-allowed\"\r\n]\r\n\r\nconst excludeTags = [\r\n    \"script\", \"meta\", \"head\", \"title\", \"link\", \"style\"\r\n]\r\n\r\nlet isMenuShow = false\r\n\r\nwindow.addEventListener(\"keydown\", (e) => {\r\n    const { key } = e\r\n    if (key === \"F9\") {\r\n        createMenu()\r\n    }\r\n})\r\n\r\nlet closeBtnID = \"\"\r\n\r\nfunction getImageBase64(url, size = 32) {\r\n    return new Promise((resolve, reject) => {\r\n        const img = new Image()\r\n        img.onload = () => {\r\n            const canvas = document.createElement(\"canvas\")\r\n            if (img.width > img.height) {\r\n                canvas.width = size\r\n                canvas.height = size * img.height / img.width\r\n            } else {\r\n                canvas.width = size * img.width / img.height\r\n                canvas.height = size\r\n            }\r\n            const ctx = canvas.getContext(\"2d\")\r\n            ctx.drawImage(img, 0, 0, canvas.width, canvas.height)\r\n            const dataURL = canvas.toDataURL()\r\n            resolve(dataURL)\r\n        }\r\n        img.src = url\r\n    })\r\n}\r\n\r\n/**\r\n * @param {HTMLElement} el \r\n */\r\nasync function renderChild(el) {\r\n    const name = el.nodeName.toLocaleLowerCase()\r\n    const type = el.nodeType\r\n    if (!excludeTags.includes(name) && el instanceof Element) {\r\n        let cursorVal = getComputedStyle(el).getPropertyValue(\"cursor\").toLowerCase()\r\n        const originalCursor = el.getAttribute(\"original-cursor\")\r\n        if (originalCursor) cursorVal = originalCursor\r\n        try {\r\n            if (cursorVal === \"\" || cursorVal === \"auto\") {\r\n                if (cursors.default) {\r\n                    const cursor = cursors.default\r\n                    if (cursor.index != void 0 && cursor.index >= 0 && cursor.index < cursor.list.length) {\r\n                        const source = cursor.list[cursor.index].source || \"\"\r\n                        const center = cursor.list[cursor.index].center || [0, 0]\r\n                        if (!originalCursor) el.setAttribute(\"original-cursor\", cursorVal)\r\n                        el.style.cursor = `url(${source\r\n                            }) ${center[0]} ${center[1]}, auto`\r\n                    }\r\n                }\r\n            } else {\r\n                for (let key of cursorKeys) {\r\n                    const _key = key.toLowerCase()\r\n                    if (cursorVal === _key) {\r\n                        if (cursors[_key]) {\r\n                            const cursor = cursors[_key]\r\n                            if (cursor.index != void 0 && cursor.index >= 0 && cursor.index < cursor.list.length) {\r\n                                const source = cursor.list[cursor.index].source || \"\"\r\n                                const center = cursor.list[cursor.index].center || [0, 0]\r\n                                if (!originalCursor) el.setAttribute(\"original-cursor\", cursorVal)\r\n                                el.style.cursor = `url(${source\r\n                                    }) ${center[0]} ${center[1]}, auto`\r\n                            }\r\n                        }\r\n                        break\r\n                    }\r\n                }\r\n            }\r\n        } catch (err) {\r\n            console.error(\"『custom-cursor』\", err)\r\n        }\r\n    }\r\n    if (el.childNodes) {\r\n        for (const child of el.childNodes) {\r\n            await renderChild(child)\r\n        }\r\n    }\r\n}\r\n\r\nrenderChild(document)\r\n\r\n/**\r\n * @param {HTMLElement} el \r\n */\r\nasync function removeRender(el) {\r\n    const name = el.nodeName.toLocaleLowerCase()\r\n    const type = el.nodeType\r\n    if (!excludeTags.includes(name) && el instanceof Element) {\r\n        const cursor = getComputedStyle(el).getPropertyValue(\"cursor\").toLowerCase()\r\n        const originalCursor = el.getAttribute(\"original-cursor\")\r\n        if (cursor.startsWith(\"url\")) {\r\n            el.style.cursor = originalCursor || \"\"\r\n        }\r\n    }\r\n    if (el.childNodes) {\r\n        for (const child of el.childNodes) {\r\n            await removeRender(child)\r\n        }\r\n    }\r\n}\r\n\r\nasync function reRenderPage() {\r\n    await removeRender(document)\r\n    await renderChild(document)\r\n}\r\n\r\nfunction createCloseBtn() {\r\n    if (!closeBtnID) {\r\n        closeBtnID = \"cursor-\" + Date.now() + (\"\" + Math.random()).replace(\".\", \"\")\r\n        const styleEl = document.createElement(\"style\")\r\n        styleEl.appendChild(document.createTextNode(`\r\n        .${closeBtnID} {\r\n            position: absolute !important;\r\n            right: 0 !important;\r\n            top: 0 !important;\r\n            overflow: hidden !important;\r\n            border: none !important;\r\n            padding: 0 !important;\r\n            width: 2em !important; height: 2em !important;\r\n            border-radius: 50% !important;\r\n            background: transparent !important;\r\n            color: #1da1f2 !important;\r\n            font: inherit !important;\r\n            font-size: 16px !important;\r\n            text-indent: 100% !important;\r\n            cursor: pointer !important;\r\n        }\r\n        \r\n        .${closeBtnID}:hover {\r\n            background: rgba(29, 161, 142, .1)\r\n        }\r\n        \r\n        .${closeBtnID}:before, .${closeBtnID}:after {\r\n            position: absolute !important;\r\n            top: 15% !important; left: calc(50% - .0625em) !important;\r\n            width: .125em !important; height: 70% !important;\r\n            border-radius: .125em !important;\r\n            transform: rotate(45deg) !important;\r\n            background: currentcolor !important;\r\n            content: ''\r\n        }\r\n        \r\n        .${closeBtnID}:after { transform: rotate(-45deg) !important; }\r\n        `))\r\n        document.head.appendChild(styleEl)\r\n    }\r\n\r\n    const closeBtn = document.createElement(\"button\")\r\n    closeBtn.className = closeBtnID\r\n    return closeBtn\r\n}\r\n\r\nasync function createMenu() {\r\n    if (isMenuShow) return\r\n    isMenuShow = true\r\n    const createSelectBox = (cursorKey, cursorOpt, callback) => {\r\n        const box = document.createElement(\"div\")\r\n        box.style.cssText = `\r\n        display: inline-flex !important;\r\n        justify-content: center !important;\r\n        align-items: center !important;\r\n        background-color: #464879 !important;\r\n        color: #fff !important;\r\n        padding-left: 8px !important;\r\n        border-radius: 4px !important;\r\n        overflow: hidden !important;\r\n        margin: 4px 2px !important;\r\n        `\r\n\r\n        const select = document.createElement(\"select\")\r\n        select.style.cssText = `\r\n        cursor: pointer !important;\r\n        display: inline-block !important;\r\n        position: relative !important;\r\n        font-size: 16px !important;\r\n        color: #fff !important;\r\n        width: 240px !important;\r\n        height: 40px !important;\r\n        padding-left: 8px !important;\r\n        background-color: #5D7DB3 !important;\r\n        outline: none !important;\r\n        border: none !important;\r\n        margin-left: 4px !important;\r\n        word-break: break-all !important;\r\n        text-overflow: clip !important;\r\n        `\r\n\r\n        const { list, index } = cursorOpt\r\n        if (Array.isArray(list) && list.length > 0) {\r\n            for (let option of list) {\r\n                const op = document.createElement(\"option\")\r\n                op.value = option.source\r\n                op.innerText = option.name\r\n                select.appendChild(op)\r\n            }\r\n            if (index >= 0 && index < list.length) {\r\n                select.value = list[index].source\r\n            }\r\n        }\r\n\r\n        select.onchange = (e) => {\r\n            const val = e.target.value\r\n            if (Array.isArray(list)) {\r\n                const index = list.findIndex(item => item.source === val)\r\n                callback(index)\r\n            } else {\r\n                callback(-1)\r\n            }\r\n        }\r\n\r\n        const label = document.createElement(\"label\")\r\n        label.innerText = (0,_i18n_js__WEBPACK_IMPORTED_MODULE_1__.t)(cursorKey)\r\n        label.style.cssText = `\r\n        width: 84px !important;\r\n        text-overflow: clip !important;\r\n        text-align: center !important;\r\n        cursor: ${cursorKey} !important;\r\n        `\r\n        label.title = (0,_i18n_js__WEBPACK_IMPORTED_MODULE_1__.t)(\"clickToUploadImage\")\r\n        label.onclick = (e) => {\r\n            createImageReader(cursorKey, ({ source, name, center }) => {\r\n                const op = document.createElement(\"option\")\r\n                op.value = source\r\n                op.innerText = name\r\n                select.appendChild(op)\r\n                reRenderPage()\r\n            })\r\n        }\r\n\r\n        box.appendChild(label)\r\n        box.appendChild(select)\r\n\r\n        return box\r\n    }\r\n\r\n    const container = document.createElement(\"div\")\r\n    container.style.cssText = `\r\n    display: inline !important;\r\n    // flex-direction: column !important;\r\n    // justify-content: center !important;\r\n    // align-items: flex-start !important;\r\n    width: 725px !important;\r\n    position: fixed !important;\r\n    top: 50% !important;\r\n    left: 50% !important;\r\n    transform: translate(-50%, -50%) !important;\r\n    background-color: #B6CAD7 !important;\r\n    padding: 32px 16px 16px 16px !important;\r\n    border-radius: 6px !important;\r\n    font-size: 14px !important;\r\n    z-index: 99999 !important;\r\n    `\r\n\r\n    const clearBtn = document.createElement(\"button\")\r\n    clearBtn.innerText = (0,_i18n_js__WEBPACK_IMPORTED_MODULE_1__.t)(\"clear\")\r\n    clearBtn.style.cssText = `\r\n    cursor: pointer !important;\r\n    display: block !important;\r\n    position: relative !important;\r\n    font-size: 14px !important;\r\n    color: #fff !important;\r\n    width: 160px !important;\r\n    height: 28px !important;\r\n    padding-left: 8px !important;\r\n    background-color: #c72121 !important;\r\n    outline: none !important;\r\n    border: none !important;\r\n    margin: auto !important;\r\n    word-break: break-all !important;\r\n    text-overflow: clip !important;\r\n    `\r\n    clearBtn.onclick = () => {\r\n        for (let key in cursors) {\r\n            cursors[key] = {\r\n                list: [],\r\n                index: -1,\r\n            }\r\n        }\r\n        reRenderPage()\r\n        try { GM_setValue(\"cursorData\", cursors) } catch { }\r\n        isMenuShow = false\r\n        document.body.removeChild(container)\r\n    }\r\n\r\n    const closeBtn = createCloseBtn()\r\n\r\n    container.appendChild(closeBtn)\r\n\r\n    for (let key of cursorKeys) {\r\n        if (!cursors[key]) continue\r\n        container.appendChild(createSelectBox(key, cursors[key], (index) => {\r\n            cursors[key].index = index\r\n            reRenderPage()\r\n            try { GM_setValue(\"cursorData\", cursors) } catch { }\r\n            // window.location.reload()\r\n        }))\r\n    }\r\n\r\n    container.appendChild(clearBtn)\r\n\r\n    document.body.appendChild(container)\r\n    closeBtn.onclick = () => {\r\n        isMenuShow = false\r\n        document.body.removeChild(container)\r\n    }\r\n    renderChild(container)\r\n}\r\n\r\nasync function createImageReader(cursorKey, callback = () => { }) {\r\n    const box = document.createElement(\"div\")\r\n    box.style.cssText = `\r\n    padding-top: 16px !important;\r\n    position: fixed !important;\r\n    top: 50% !important;\r\n    left: 50% !important;\r\n    transform: translate(-50%, -50%) !important;\r\n    min-height: 200px !important;\r\n    background-color: #B6CAD7 !important;\r\n    display: flex !important;\r\n    flex-direction: column !important;\r\n    align-items: center !important;\r\n    z-index: 99999 !important;\r\n    `\r\n\r\n    const uploadArea = document.createElement(\"div\")\r\n    uploadArea.innerText = \"Drag To Upload\"\r\n    uploadArea.style.cssText = `\r\n    margin: 16px !important;\r\n    width: 400px !important;\r\n    height: 300px !important;\r\n    font-size: 20px !important;\r\n    text-align: center !important;\r\n    line-height: 300px !important;\r\n    border: 2px dashed #fff !important;\r\n    background-color: #5D7DB3 !important;\r\n    cursor: grab !important;\r\n    `\r\n\r\n    const linkInput = document.createElement(\"input\")\r\n    linkInput.type = \"text\"\r\n    linkInput.placeholder = (0,_i18n_js__WEBPACK_IMPORTED_MODULE_1__.t)(\"imageLink\") + \" [ENTER]\"\r\n    linkInput.style.cssText = `\r\n    margin: 16px !important;\r\n    width: 400px !important;\r\n    height: 40px !important;\r\n    font-size: 20px !important;\r\n    text-align: center !important;\r\n    line-height: 40px !important;\r\n    border: 2px dashed #fff !important;\r\n    background-color: #5D7DB3 !important;\r\n    cursor: text !important;\r\n    `\r\n\r\n    const closeBtn = createCloseBtn()\r\n\r\n    const showImage = async (file) => {\r\n        if (!file) return\r\n\r\n        let image = new Image()\r\n        if (typeof file === \"string\") {\r\n            image.src = file\r\n        } else if (file instanceof Image) {\r\n            image.src = file.src\r\n        } else {\r\n            image.src = await getImageBase64(URL.createObjectURL(file))\r\n        }\r\n\r\n        image.onload = (e) => {\r\n            box.removeChild(uploadArea)\r\n            box.removeChild(linkInput)\r\n            const tipBox = document.createElement(\"div\")\r\n            tipBox.style.cssText = `\r\ntext-align: center !important;\r\nfont-size: 16px !important;\r\nmargin: 5px !important;\r\nline-height: 16px !important;\r\nuser-select: none !important;       \r\n`\r\n            tipBox.innerText = (0,_i18n_js__WEBPACK_IMPORTED_MODULE_1__.t)(\"pleaseClickToSelectCenter\")\r\n            box.appendChild(tipBox)\r\n\r\n            const canvas = document.createElement(\"canvas\")\r\n            let w = image.naturalWidth\r\n            let h = image.naturalHeight\r\n            let mw = window.innerWidth - 80\r\n            let mh = window.innerHeight - 80\r\n            while (w >= mw || h >= mh) {\r\n                w = w * 0.7\r\n                h = h * 0.7\r\n            }\r\n            canvas.width = w\r\n            canvas.height = h\r\n            canvas.style.cssText = `\r\nmargin: 5px 16px !important;\r\nwidth: ${w}px !important;\r\nheight: ${h}px !important;\r\n`\r\n            const ctx = canvas.getContext(\"2d\")\r\n            ctx.drawImage(image, 0, 0, canvas.width, canvas.height)\r\n            box.appendChild(canvas)\r\n            const textLine = document.createElement(\"div\")\r\n            textLine.style.cssText = `\r\ntext-align: center !important;\r\nfont-size: 14px !important;\r\ncolor: #fff !important;\r\nmargin: 5px !important;\r\nline-height: 16px !important;\r\nuser-select: none !important;\r\n`\r\n            textLine.innerText = `X: 0 | Y: 0`\r\n            box.appendChild(textLine)\r\n\r\n            const nameInput = document.createElement(\"input\")\r\n            nameInput.type = \"text\"\r\n            nameInput.placeholder = (0,_i18n_js__WEBPACK_IMPORTED_MODULE_1__.t)(\"pleaseInputImageName\")\r\n            nameInput.style.cssText = `\r\nmargin: 0px 16px !important;\r\nwidth: 80% !important;\r\nheight: 20px !important;\r\nfont-size: 14px !important;\r\ntext-align: center !important;\r\nborder: none !important;\r\nbackground-color: #e1e1e1 !important;\r\ncursor: text !important;\r\n            `\r\n            box.appendChild(nameInput)\r\n\r\n            const ratioSelect = document.createElement(\"select\")\r\n            ratioSelect.style.cssText = `\r\nmargin: 5px 16px !important;\r\nwidth: 80% !important;\r\nheight: 20px !important;\r\nfont-size: 14px !important;\r\ntext-align: center !important;\r\nborder: none !important;\r\nbackground-color: #e1e1e1 !important;\r\ncursor: pointer !important;\r\n`\r\n            const ratioList = [\r\n                { name: \"8x8\", value: 8 },\r\n                { name: \"16x16\", value: 16 },\r\n                { name: \"32x32\", value: 32 },\r\n                { name: \"64x64\", value: 64 },\r\n                { name: \"128x128\", value: 128 },\r\n                // { name: \"256x256\", value: 256 },\r\n                // { name: \"512x512\", value: 512 },\r\n            ]\r\n            for (let ratio of ratioList) {\r\n                const op = document.createElement(\"option\")\r\n                op.value = ratio.value\r\n                op.innerText = ratio.name\r\n                ratioSelect.appendChild(op)\r\n            }\r\n            ratioSelect.value = 32\r\n            ratioSelect.onchange = async (e) => {\r\n                if (typeof file === \"string\" || file instanceof Image) return\r\n                const val = Number(e.target.value) || 32\r\n                const _image = new Image()\r\n                _image.src = await getImageBase64(URL.createObjectURL(file), val)\r\n                _image.onload = () => {\r\n                    canvas.width = _image.naturalWidth\r\n                    canvas.height = _image.naturalHeight\r\n                    canvas.style.cssText = `\r\nmargin: 5px 16px !important;\r\nwidth: ${_image.naturalWidth}px !important;\r\nheight: ${_image.naturalHeight}px !important;\r\n`\r\n                    ctx.drawImage(_image, 0, 0, canvas.width, canvas.height)\r\n                    textLine.innerText = `X: 0 | Y: 0`\r\n                }\r\n                image = _image\r\n            }\r\n            box.appendChild(ratioSelect)\r\n\r\n            const btnBox = document.createElement(\"div\")\r\n            btnBox.style.cssText = `\r\ntext-align: center !important;\r\nfont-size: 14px !important;\r\ncolor: #6d6d6d !important;\r\nmargin: 5px 16px !important;\r\nline-height: 16px !important;\r\nuser-select: none !important;\r\ncursor: pointer !important;\r\nfont-weight: bold !important;\r\n`\r\n            btnBox.innerText = (0,_i18n_js__WEBPACK_IMPORTED_MODULE_1__.t)(\"confirm\")\r\n\r\n            box.appendChild(btnBox)\r\n\r\n            const center = [0, 0]\r\n\r\n            canvas.onclick = (e) => {\r\n                const x = e.offsetX\r\n                const y = e.offsetY\r\n                center[0] = x\r\n                center[1] = y\r\n                textLine.innerText = `X: ${x} | Y: ${y}`\r\n                ctx.clearRect(0, 0, canvas.width, canvas.height)\r\n                ctx.drawImage(image, 0, 0, canvas.width, canvas.height)\r\n                ctx.fillStyle = \"#ff0000\"\r\n                ctx.fillRect(x - 5, y - 5, 10, 10)\r\n            }\r\n            // 监听上下左右键\r\n            document.onkeydown = (e) => {\r\n                // e.preventDefault()\r\n                const drawPoint = () => {\r\n                    textLine.innerText = `X: ${center[0]} | Y: ${center[1]}`\r\n                    ctx.clearRect(0, 0, canvas.width, canvas.height)\r\n                    ctx.drawImage(image, 0, 0, canvas.width, canvas.height)\r\n                    ctx.fillStyle = \"#ff0000\"\r\n                    ctx.fillRect(center[0] - 5, center[1] - 5, 10, 10)\r\n                }\r\n                const { key } = e\r\n                if (key === \"ArrowUp\") {\r\n                    center[1] -= 1\r\n                    drawPoint()\r\n                } else if (key === \"ArrowDown\") {\r\n                    center[1] += 1\r\n                    drawPoint()\r\n                } else if (key === \"ArrowLeft\") {\r\n                    center[0] -= 1\r\n                    drawPoint()\r\n                } else if (key === \"ArrowRight\") {\r\n                    center[0] += 1\r\n                    drawPoint()\r\n                }\r\n            }\r\n\r\n            btnBox.onclick = (e) => {\r\n                cursors[cursorKey].list.push({\r\n                    source: image.src,\r\n                    name: nameInput.value || \"自定义\",\r\n                    center: center,\r\n                })\r\n                cursors[cursorKey].index = cursors[cursorKey].list.length - 1\r\n                document.body.removeChild(box)\r\n                document.onkeydown = null\r\n                try { GM_setValue(\"cursorData\", cursors) } catch { }\r\n                callback({\r\n                    source: image.src,\r\n                    name: nameInput.value || \"自定义\",\r\n                    center: center,\r\n                })\r\n            }\r\n\r\n            renderChild(box)\r\n        }\r\n    }\r\n\r\n    uploadArea.addEventListener('dragover', (e) => e.preventDefault())\r\n    uploadArea.addEventListener('drop', (e) => {\r\n        e.preventDefault()\r\n        const { dataTransfer: { files = {} } = {} } = e || {}\r\n        console.log('dropped: ', files)\r\n\r\n        showImage(files[0])\r\n    })\r\n    uploadArea.addEventListener('click', (e) => {\r\n        const input = document.createElement(\"input\")\r\n        input.type = \"file\"\r\n        input.accept = \"image/*\"\r\n        input.onchange = (e) => {\r\n            const file = e.target.files[0]\r\n            // limit size to 128KB\r\n            // if (file.size > 128 * 1024) {\r\n            //     alert(t(\"imageUploadLimit128\"))\r\n            //     return\r\n            // }\r\n            showImage(file)\r\n        }\r\n        input.click()\r\n    })\r\n\r\n    linkInput.addEventListener('paste', (e) => {\r\n        const data = e.clipboardData || window.clipboardData\r\n        const text = data.getData('text')\r\n        const image = new Image()\r\n        image.src = text\r\n        image.onload = (e) => {\r\n            showImage(image)\r\n        }\r\n        image.onerror = (e) => {\r\n            alert(\"Image load failed!\")\r\n            linkInput.value = \"\"\r\n        }\r\n    })\r\n\r\n\r\n\r\n    box.appendChild(closeBtn)\r\n    box.appendChild(uploadArea)\r\n    box.appendChild(linkInput)\r\n\r\n    document.body.appendChild(box)\r\n    closeBtn.onclick = () => { document.body.removeChild(box) }\r\n    renderChild(box)\r\n}\n\n//# sourceURL=webpack:///./index.js?");

          /***/
})

      /******/
});
/************************************************************************/
/******/ 	// The module cache
/******/ 	var __webpack_module_cache__ = {};
/******/
/******/ 	// The require function
/******/ 	function __webpack_require__(moduleId) {
/******/ 		// Check if module is in cache
/******/ 		var cachedModule = __webpack_module_cache__[moduleId];
/******/ 		if (cachedModule !== undefined) {
/******/ 			return cachedModule.exports;
        /******/
}
/******/ 		// Create a new module (and put it into the cache)
/******/ 		var module = __webpack_module_cache__[moduleId] = {
/******/ 			// no module.id needed
/******/ 			// no module.loaded needed
/******/ 			exports: {}
        /******/
};
/******/
/******/ 		// Execute the module function
/******/ 		__webpack_modules__[moduleId](module, module.exports, __webpack_require__);
/******/
/******/ 		// Return the exports of the module
/******/ 		return module.exports;
      /******/
}
/******/
/************************************************************************/
/******/ 	/* webpack/runtime/define property getters */
/******/ 	(() => {
/******/ 		// define getter functions for harmony exports
/******/ 		__webpack_require__.d = (exports, definition) => {
/******/ 			for (var key in definition) {
/******/ 				if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
/******/ 					Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
            /******/
}
          /******/
}
        /******/
};
      /******/
})();
/******/
/******/ 	/* webpack/runtime/hasOwnProperty shorthand */
/******/ 	(() => {
/******/ 		__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
      /******/
})();
/******/
/******/ 	/* webpack/runtime/make namespace object */
/******/ 	(() => {
/******/ 		// define __esModule on exports
/******/ 		__webpack_require__.r = (exports) => {
/******/ 			if (typeof Symbol !== 'undefined' && Symbol.toStringTag) {
/******/ 				Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
          /******/
}
/******/ 			Object.defineProperty(exports, '__esModule', { value: true });
        /******/
};
      /******/
})();
/******/
/************************************************************************/
/******/
/******/ 	// startup
/******/ 	// Load entry module and return exports
/******/ 	// This entry module can't be inlined because the eval devtool is used.
/******/ 	var __webpack_exports__ = __webpack_require__("./index.js");
    /******/
    /******/
})()
    ;
})();