您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Adds an image overlay to skin editor
// ==UserScript== // @name Bonk Skin Editor Overlay // @version 0.3 // @author Salama // @description Adds an image overlay to skin editor // @match https://*.bonk.io/gameframe-release.html // @match https://*.bonkisback.io/gameframe-release.html // @run-at document-end // @grant none // @license GPL-3.0-or-later // @supportURL https://discord.gg/Dj6usq7ww3 // @namespace https://greasyfork.org/users/824888 // ==/UserScript== (function() { 'use strict'; let overlay = document.createElement("div"); let menu = document.createElement("div"); document.getElementById("skineditor_previewbox_skincontainer").appendChild(overlay); document.getElementById("skineditor_previewbox").appendChild(menu); overlay.outerHTML = `<div> <img id="skineditor_imageoverlay" style=" touch-action: none; cursor: inherit; position: absolute; left: 0; top: 0; pointer-events: none; opacity: 0.8; display: none; opacity: 0.5; z-index: 9998; display: none; "> <canvas id="skineditor_imageoverlaycanvas" width="245" height="245" style=" touch-action: none; cursor: inherit; position: absolute; left: 0; top: 0; pointer-events: none; opacity: 0.5; "></canvas> </div> </div>`; menu.outerHTML = `<div> <div class="newbonklobby_playerentry_balancecontainer brownButton brownButton_classic" style=" position: absolute; bottom: 58px; width: 40%; margin-left: 30%; margin-right: 10%; "> <div class="newbonklobby_playerentry_balancetext">Overlay Opacity</div> <input id="skineditor_opacityslider" type="range" min="0" max="100" step="1" value="50" class="compactSlider slider newbonklobby_playerentry_balanceslider" style=" width: 90%; "> </div> <div id="skineditor_filechooser" class="brownButton brownButton_classic buttonShadow" style=" width: 64px; bottom: 58px; left: 5%; position: absolute; height: 35px; font-size: 14px; ">Select Overlay</div> </div>`; // Preview size const ps = 245; let overlaySelected = false; let imageOffset = {x:0,y:0} let flipX = false; let flipY = false; let ctx = document.getElementById("skineditor_imageoverlaycanvas").getContext("2d"); let scale = 1, angle = 0, d, x, y, image = document.getElementById("skineditor_imageoverlay"); overlay = document.getElementById("skineditor_imageoverlay"); const drawOverlay = () => { ctx.save(); ctx.clearRect(0, 0, ps, ps); ctx.setTransform(scale * (flipX ? -1 : 1), 0, 0, scale * (flipY ? -1 : 1), ps/2 + imageOffset.x, ps/2 + imageOffset.y); ctx.rotate(angle); ctx.drawImage(document.getElementById("skineditor_imageoverlay"), -image.width/2, -image.height/2, image.width, image.height); ctx.restore(); overlay.style.rotate = `${angle}rad`; overlay.style.transform = `scale(${scale * (flipX ? -1 : 1)}, ${scale * (flipY ? -1 : 1)})`; overlay.style.left = `${(ps - image.width) / 2 + imageOffset.x}px`; overlay.style.top = `${(ps - image.height) / 2 + imageOffset.y}px`; } document.getElementById("skineditor_filechooser").addEventListener("click", () => { let a = document.createElement("input"); a.type = 'file'; document.body.appendChild(a); a.onchange = e => { let file = e.target.files[0]; image.src = URL.createObjectURL(file); document.getElementById("skineditor_imageoverlay_preview").src = image.src; image.onload = () => { image.style.visibility = "visible"; image.style.display = ""; ctx.clearRect(0, 0, ps, ps); let imageRatio = image.naturalWidth / image.naturalHeight; if(image.naturalWidth > image.naturalHeight) { image.width = ps; image.height = ps / imageRatio; image.style.top = (ps - image.height) / 2; } else { image.width = ps * imageRatio; image.height = ps; image.style.left = (ps - image.width) / 2; } angle = 0; scale = 1; imageOffset = {x:0,y:0}; image.style.rotate = "0rad"; image.style.scale = 1; image.style.top = (ps - image.height) / 2; image.style.left = (ps - image.width) / 2; flipX = false; flipY = false; if(overlaySelected) { document.getElementById("skineditor_propertiesbox_table_x").value = imageOffset.x; document.getElementById("skineditor_propertiesbox_table_y").value = imageOffset.y; document.getElementById("skineditor_propertiesbox_table_angle").value = angle / Math.PI * 180; document.getElementById("skineditor_propertiesbox_table_scale").value = scale.toFixed(2); document.getElementById("skineditor_propertiesbox_table_flipx").textContent = flipX ? "Yes" : "No"; document.getElementById("skineditor_propertiesbox_table_flipy").textContent = flipY ? "Yes" : "No"; } drawOverlay(); } }; a.click(); document.body.removeChild(a); }); document.getElementById("skineditor_opacityslider").addEventListener("input", e => { document.getElementById("skineditor_imageoverlaycanvas").style.opacity = e.target.value / 100; document.getElementById("skineditor_imageoverlay").style.opacity = e.target.value / 100; }); const layerObserver = new MutationObserver(mutations => { for(let mutation of mutations) { for(let node of mutation.addedNodes) { if(node.nodeName === "TR" && node.id === "0") { let overlayLayer = document.createElement("tr"); overlayLayer.classList = ["HOVERUNSELECTED"]; overlayLayer.id = "-1"; overlayLayer.addEventListener("click", () => { node.onclick.apply(overlayLayer); overlaySelected = true; // Execution will be continued in shape window's mutation observer }); document.getElementById("skineditor_layerbox_layertable").children[0].insertBefore(overlayLayer, node); overlayLayer.innerHTML = ` <td> <span class="skineditor_layerbox_layername">Overlay</span> <div class="skineditor_layerbox_layerpreview"> <img src="${image.src}" onload="this.style.display=''" onerror="this.style.display='none'" class="skineditor_layerbox_layerpreview_image" id="skineditor_imageoverlay_preview" style="display:none;"> </div> </td>`; } else if(node.id !== "-1") { node.addEventListener("click", () => { document.getElementById("skineditor_propertiesbox_table_shape").parentNode.parentNode.style.display = ""; document.getElementById("skineditor_propertiesbox_colorrect").parentNode.parentNode.style.display = ""; document.getElementById("skineditor_imageoverlaycanvas").style.display = ""; image.style.display = "none"; document.getElementById("skineditor_propertiesbox_upbutton").style.display = ""; document.getElementById("skineditor_propertiesbox_downbutton").style.display = ""; document.getElementById("skineditor_propertiesbox_deletebutton").style.display = ""; overlaySelected = false; drawOverlay(); }); } } } }); const shapePickerObserver = new MutationObserver(mutations => { if(!overlaySelected) return; for(let mutation of mutations) { if(mutation.type === "attributes" && mutation.attributeName === "style" && mutation.target === document.getElementsByClassName("skineditor_shapewindow")[0]) { // It's actually the shape window close button with a wrong class name mutation.target.getElementsByClassName("skineditor_basiccolorpicker_closebutton")[0].click(); for(let child of document.getElementById("skineditor_layerbox_layertable").children[0].children) { child.classList = ["HOVERUNSELECTED"]; } document.getElementById("skineditor_layerbox_layertable").children[0].children[0].classList = ["HOVERSELECTED"]; // Show properties menu document.getElementById("skineditor_propertiesbox_blocker").style.visibility = "hidden"; document.getElementById("skineditor_propertiesbox_table_x").value = imageOffset.x.toFixed(2); document.getElementById("skineditor_propertiesbox_table_y").value = imageOffset.y.toFixed(2); document.getElementById("skineditor_propertiesbox_table_angle").value = (angle / Math.PI * 180).toFixed(2); document.getElementById("skineditor_propertiesbox_table_scale").value = scale.toFixed(2); document.getElementById("skineditor_propertiesbox_table_flipx").textContent = flipX ? "Yes" : "No"; document.getElementById("skineditor_propertiesbox_table_flipy").textContent = flipY ? "Yes" : "No"; document.getElementById("skineditor_propertiesbox_table_shape").parentNode.parentNode.style.display = "none"; document.getElementById("skineditor_propertiesbox_colorrect").parentNode.parentNode.style.display = "none"; document.getElementById("skineditor_imageoverlaycanvas").style.display = "none"; document.getElementById("skineditor_imageoverlay").style.display = ""; document.getElementById("skineditor_propertiesbox_upbutton").style.display = "none"; document.getElementById("skineditor_propertiesbox_downbutton").style.display = "none"; document.getElementById("skineditor_propertiesbox_deletebutton").style.display = "none"; } } }); layerObserver.observe(document.getElementById("skineditor_layerbox_layertable"), {attributes: false, childList: true, subtree: true}); shapePickerObserver.observe(document.getElementById("skineditor_propertiesbox"), {attributes: true, childlist: false, subtree: true}); document.getElementById("skineditor_propertiesbox_table_x").addEventListener("input", e => { if(!overlaySelected) return; imageOffset.x = parseFloat(e.target.value); if(isNaN(imageOffset.x)) { imageOffset.x = 0; } drawOverlay(); }); document.getElementById("skineditor_propertiesbox_table_y").addEventListener("input", e => { if(!overlaySelected) return; imageOffset.y = parseFloat(e.target.value); if(isNaN(imageOffset.y)) { imageOffset.y = 0; } drawOverlay(); }); document.getElementById("skineditor_propertiesbox_table_angle").addEventListener("input", e => { if(!overlaySelected) return; angle = parseFloat(e.target.value) / 180 * Math.PI; if(isNaN(angle)) { angle = 0; } drawOverlay(); }); document.getElementById("skineditor_propertiesbox_table_scale").addEventListener("input", e => { if(!overlaySelected) return; scale = parseFloat(e.target.value); if(isNaN(scale)) { scale = 1; } drawOverlay(); }); document.getElementById("skineditor_propertiesbox_table_flipx").addEventListener("click", e => { if(!overlaySelected) return; flipX = !flipX; e.target.textContent = flipX ? "Yes" : "No"; drawOverlay(); }); document.getElementById("skineditor_propertiesbox_table_flipy").addEventListener("click", e => { if(!overlaySelected) return; flipY = !flipY; e.target.textContent = flipY ? "Yes" : "No"; drawOverlay(); }); const handleButton = e => { switch(e.target.id) { case "skineditor_x_up": imageOffset.x += 0.1; document.getElementById("skineditor_propertiesbox_table_x").value = imageOffset.x.toFixed(1); break; case "skineditor_x_down": imageOffset.x -= 0.1; document.getElementById("skineditor_propertiesbox_table_x").value = imageOffset.x.toFixed(1); break; case "skineditor_y_up": imageOffset.y += 0.1; document.getElementById("skineditor_propertiesbox_table_y").value = imageOffset.y.toFixed(1); break; case "skineditor_y_down": imageOffset.y -= 0.1; document.getElementById("skineditor_propertiesbox_table_y").value = imageOffset.y.toFixed(1); break; case "skineditor_angle_up": angle += 1 / 180 * Math.PI; document.getElementById("skineditor_propertiesbox_table_angle").value++; break; case "skineditor_angle_down": angle -= 1 / 180 * Math.PI; document.getElementById("skineditor_propertiesbox_table_angle").value--; break; case "skineditor_scale_up": if(scale < 0.2) { scale += 0.005; } else { scale += 0.01; } document.getElementById("skineditor_propertiesbox_table_scale").value = scale.toFixed(2); break; case "skineditor_scale_down": if(scale < 0.2) { scale -= 0.005; } else { scale -= 0.01; } document.getElementById("skineditor_propertiesbox_table_scale").value = scale.toFixed(2); break; } drawOverlay(); } let buttonTimeout; const editorButtonUp = () => { // Clears interval too clearTimeout(buttonTimeout); window.removeEventListener("mouseup", editorButtonUp); } const editorButtonDown = e => { if(!overlaySelected) return; handleButton(e); window.addEventListener("mouseup", editorButtonUp); buttonTimeout = setTimeout(() => { handleButton(e); buttonTimeout = setInterval(() => { handleButton(e); }, 30); }, 400); } for(let button of document.getElementsByClassName("skineditor_field_button")) { button.addEventListener("pointerdown", editorButtonDown); } document.getElementById("skinmanager_edit").addEventListener("click", () => { angle = 0; scale = 1; imageOffset = {x:0,y:0}; image.style.rotate = "0rad"; image.style.scale = 1; image.style.top = (ps - image.height) / 2; image.style.left = (ps - image.width) / 2; flipX = false; flipY = false; image.style.display = "none"; image.style.visibility = "hidden"; image.src = ""; if(document.getElementById("skineditor_imageoverlay_preview")) { document.getElementById("skineditor_imageoverlay_preview").style.display = "none"; document.getElementById("skineditor_imageoverlay_preview").src = ""; } ctx.clearRect(0, 0, ps, ps); }); })();