您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Color picker for Sketchful
// ==UserScript== // @name Color Picker // @namespace https://greasyfork.org/users/281093 // @match https://sketchful.io/* // @grant none // @version 0.7.5 // @author Bell // @license MIT // @copyright 2020, Bell // @description Color picker for Sketchful // @run-at document-end // ==/UserScript== // jshint esversion: 6 const defaultPalettes = [ [ '#ffffff', '#d3d1d2', '#f70f0f', '#ff7200', '#fce700', '#02cb00', '#01fe94', '#05b0ff', '#221ecd', '#a300bd', '#cc7fad', '#fdad88', '#9e5425', '#514f54', '#a9a7a8', '#ae0b00', '#c84706', '#ec9e06', '#007612', '#049d6f', '#00579d', '#0f0b96', '#6e0083', '#a65673', '#e38a5e', '#5e320d', '#000000', '#827c80', '#57060c', '#8b2500', '#9e6600', '#003f00', '#00766a', '#003b75', '#0e0151', '#3c0350', '#73314d', '#d1754e', '#421e06' ], [ '#3a3a3c', '#8e8e93', '#f8f9fa', '#ffadad', '#ffd6a5', '#fdffb6', '#caffbf', '#9bf6ff', '#a0c4ff', '#bdb2ff', '#ffc6ff', '#fdad88', '#9e5425', '#2c2c2e', '#636366', '#e0e0e0', '#ff7070', '#f3a220', '#f9e079', '#049d6f', '#92ddea', '#6dafe0', '#ab87ff', '#ff87ab', '#e38a5e', '#5e320d', '#1c1c1e', '#48484a', '#c2c2c2', '#f54d4d', '#dc8700', '#f0c808', '#00766a', '#219bc3', '#548bbc', '#715aff', '#ff5d8f', '#d1754e', '#421e06' ], [ '#081c15', '#1b4332', '#2d6a4f', '#40916c', '#52b788', '#74c69d', '#95d5b2', '#b7e4c7', '#d8f3dc', '#000000', '#faf9f9', '#ffd6ba', '#fec89a', '#774936', '#8a5a44', '#9d6b53', '#b07d62', '#c38e70', '#cd9777', '#d69f7e', '#deab90', '#e6b8a2', '#edc4b3', '#ffb5a7', '#fcd5ce', '#f8edeb', '#cb997e', '#eddcd2', '#fff1e6', '#f0efeb', '#ddbea9', '#a5a58d', '#b7b7a4', '#6d6875', '#b5838d', '#e5989b', '#ffb4a2', '#ffcdb2', '#f9dcc4' ], [ '#10002b', '#240046', '#3c096c', '#5a189a', '#7b2cbf', '#9d4edd', '#c77dff', '#e0aaff', '#efcefa', '#d4b2d8', '#a88fac', '#826c7f', '#5d4e60', '#7c6f93', '#886f93', '#a967ad', '#ad6789', '#db81ad', '#ff6c91', '#ff736c', '#ff9e46', '#faa275', '#ff8c61', '#ce6a85', '#985277', '#5c374c', '#721b65', '#b80d57', '#f8615a', '#ffd868', '#bb596b', '#f96d80', '#ff9a76', '#ffc4a3', '#00e0ff', '#74f9ff', '#a6fff2', '#e8ffe8', '#ffffff' ], [ '#007f5f', '#2b9348', '#55a630', '#80b918', '#aacc00', '#bfd200', '#d4d700', '#dddf00', '#eeef20', '#ffff3f', '#03045e', '#0077b6', '#00b4d8', '#ff4800', '#ff5400', '#ff6000', '#ff6d00', '#ff7900', '#ff8500', '#ff9100', '#ff9e00', '#ffaa00', '#ffb600', '#90e0ef', '#caf0f8', '#000000', '#143642', '#263c41', '#38413f', '#4a473e', '#5c4d3c', '#6f523b', '#815839', '#935e38', '#a56336', '#b76935', '#000000', '#ffffff', '#ffffff' ] ]; const palettes = JSON.parse(localStorage.getItem('palettes')) || defaultPalettes; let paletteIndex = parseInt(localStorage.getItem('paletteIndex')) || 0; let lockedPalettes = JSON.parse(localStorage.getItem('lockedPalettes')) || [0]; let activeColor = { node: null, index: null }; const canvas = document.querySelector('#canvas'); const ctx = canvas.getContext('2d'); const gameTools = document.querySelector('#gameTools'); const chatBox = document.querySelector('#gameChat'); const colorButtons = document.querySelectorAll('.gameToolsColor'); const colorsDiv = document.querySelector('#gameToolsColors'); const colorButton = document.querySelector('#gameToolsColors > div:nth-child(1) > div:nth-child(1)'); const colorPickerWrapper = document.createElement('div'); const colorInput = document.createElement('input'); const colorPicker = document.createElement('input'); const inputStyle = 'margin: 5px 0; height: 20px; width: 35%; text-align: center; border: none;font-weight: 800; border-radius: 5px; background-color: #CBCBCB;'; const wrapperStyle = 'position: absolute; margin: 5px 35%; height: 20px; width: 37px; border-radius: 5px;'; (function init() { addPicker(); updatePageStyle(); addObservers(); addListeners(); changePalette(); })(); function addPicker() { colorPicker.type = 'color'; colorPicker.setAttribute('style', 'opacity: 0; width: 37px; cursor: pointer;'); colorPicker.oninput = updatePicker; colorPicker.setAttribute('data-toggle', 'tooltip'); colorPicker.setAttribute('data-original-title', 'Color Picker'); colorPicker.setAttribute('data-placement', 'bottom'); colorPicker.title = 'Color Picker'; colorPickerWrapper.setAttribute('style', wrapperStyle); colorPickerWrapper.style.backgroundColor = colorPicker.value; colorPickerWrapper.appendChild(colorPicker); gameTools.appendChild(colorPickerWrapper); colorInput.oninput = updateInput; colorInput.onclick = selectInputText; colorInput.setAttribute('style', inputStyle); colorInput.setAttribute('spellcheck', 'false'); colorInput.setAttribute('maxlength', '7'); colorInput.value = colorPicker.value; gameTools.appendChild(colorInput); addButtons(); } const setColorDebounced = debounce(setColor, 5); function debounce(func, delay) { let inDebounce; return function() { const context = this; const args = arguments; clearTimeout(inDebounce); inDebounce = setTimeout(() => func.apply(context, args), delay); }; } function addObservers() { const heightObserver = new MutationObserver(adjustChatSize); const config = { attributes: true }; heightObserver.observe(gameTools, config); heightObserver.observe(chatBox, config); } let pickingColor = false; function pickerIconOn(e) { if (e.code !== 'AltLeft') return; canvas.style.cursor = 'crosshair'; pickingColor = true; e.preventDefault(); } function pickerIconOff(e) { if (e.code !== 'AltLeft' || !pickingColor) return; pickingColor = false; regenerateCursor(); e.preventDefault(); } function regenerateCursor() { const selectedTool = document.querySelector('.gameToolsSelected'); selectedTool.id === 'gameToolsDraw' ? selectedTool.nextSibling.click() : selectedTool.previousSibling.click(); selectedTool.click(); } function addListeners() { canvas.addEventListener('pointerdown', pickCanvasColor, false); document.addEventListener('keydown', pickerIconOn, true); document.addEventListener('keyup', pickerIconOff, true); const saveBtn = document.querySelector('#savePalette'); saveBtn.addEventListener('dragenter', highlight, false); saveBtn.addEventListener('dragleave', unhighlight, false); saveBtn.addEventListener('drop', handleDrop, false); saveBtn.addEventListener('dragover', e => { e.preventDefault(); }, false); document.addEventListener('keydown', e => { if (e.altKey && e.shiftKey && !isPaletteLocked(paletteIndex)) { colorsDiv.style.boxShadow = '0 0 0 2px red'; } }, false); document.addEventListener('keyup', e => { if (e.altKey || e.shiftKey) { colorsDiv.style.boxShadow = ''; } }, false); document.addEventListener('paste', e => { if (document.activeElement.tagName === 'INPUT') return; const paste = (e.clipboardData || window.clipboardData).getData('text'); const coolorRegex = /coolors\.co\/([a-f0-9-]+)/; const match = coolorRegex.exec(paste); if (match) {addHexFromString(match[1]);} }, false); colorsDiv.addEventListener('pointerenter', () => { colorsDiv.addEventListener('pointerdown', editColor, true); }); colorsDiv.addEventListener('pointerleave', () => { colorsDiv.removeEventListener('pointerdown', editColor, true); }); document.addEventListener('keydown', e=> { if (!e.ctrlKey || e.code !== 'KeyZ') return; e.preventDefault(); }); } function updatePageStyle() { document.querySelector('#gameToolsSlider').style.top = '77px'; gameTools.style.height = '200px'; } function toggleLock() { const lockBtn = document.querySelector('#lockButton'); if (lockBtn.getAttribute('state') === 'unlocked') { lockPalette(lockBtn); } else { unlockPalette(lockBtn); } updateLock(); } function lockPalette() { lockedPalettes.push(paletteIndex); localStorage.setItem('lockedPalettes', JSON.stringify(lockedPalettes)); } function unlockPalette() { const index = lockedPalettes.indexOf(paletteIndex); if (index < 0) return; lockedPalettes.splice(index, 1); localStorage.setItem('lockedPalettes', JSON.stringify(lockedPalettes)); } function updateLock() { const lockBtn = document.querySelector('#lockButton'); if (isPaletteLocked(paletteIndex)) { lockBtn.classList.remove('fa-unlock-alt'); lockBtn.classList.add('fa-lock'); lockBtn.setAttribute('state', 'locked'); colorsDiv.style.boxShadow = ''; } else { lockBtn.classList.add('fa-unlock-alt'); lockBtn.classList.remove('fa-lock'); lockBtn.setAttribute('state', 'unlocked'); } resetActiveColor(); } function addButtons() { const prevPaletteBtn = document.createElement('button'); const saveColorBtn = document.createElement('button'); const nextPaletteBtn = document.createElement('button'); const lockBtn = document.createElement('button'); const saveTooltip = 'Save Color<br>Hold <strong>shift</strong> to save the current palette.'; const lockTooltip = 'Lock Current Palette'; addButton(prevPaletteBtn, 'arrow-left', '5px 5px 5px 45px;'); addButton(saveColorBtn, 'save', '5px 5px 5px 75px;', saveTooltip, 'savePalette'); addButton(nextPaletteBtn, 'arrow-right', '5px 5px 5px 105px;'); addButton(lockBtn, 'unlock-alt', '5px 5px 5px 135px;', lockTooltip, 'lockButton'); lockBtn.setAttribute('state', 'unlocked'); prevPaletteBtn.addEventListener('click', prevPalette, false); saveColorBtn.addEventListener('click', saveColor, false); nextPaletteBtn.addEventListener('click', nextPalette, false); lockBtn.addEventListener('click', toggleLock, false); } function nextPalette() { paletteIndex = paletteIndex < (palettes.length - 1) ? paletteIndex + 1 : 0; localStorage.setItem('paletteIndex', paletteIndex); changePalette(); } function prevPalette() { paletteIndex = paletteIndex > 0 ? paletteIndex - 1 : palettes.length - 1; localStorage.setItem('paletteIndex', paletteIndex); changePalette(); } function saveColor(e) { if (e.shiftKey) { downloadPalettes(); return; } const currentPalette = palettes[paletteIndex]; if (activeColor.index) { currentPalette[activeColor.index] = colorPicker.value; } else { addColor(colorPicker.value); } changePalette(); savePalettes(); } function addColor(color) { if (palettes[paletteIndex].length > 38 || isPaletteLocked(paletteIndex)) { palettes.push([]); paletteIndex = palettes.length - 1; } palettes[paletteIndex].push(color); } function rgbToHex(rgb) { const regEx = /rgb\((\d+),\s*(\d+),\s*(\d+)\)/; const [, r, g, b] = regEx.exec(rgb); function hex(x) { return ('0' + parseInt(x).toString(16)).slice(-2); } return `#${hex(r)}${hex(g)}${hex(b)}`; } function savePalettes() { localStorage.setItem('palettes', JSON.stringify(palettes)); } function downloadPalettes() { const formattedPaletteData = JSON.stringify(palettes[paletteIndex]).replace(/\],/g, '],\n\n'); download('palette.txt', formattedPaletteData); } function download(filename, text) { const pom = document.createElement('a'); pom.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text)); pom.setAttribute('download', filename); if (document.createEvent) { const event = document.createEvent('MouseEvents'); event.initEvent('click', true, true); pom.dispatchEvent(event); } else { pom.click(); } } function isPaletteLocked(index) { return lockedPalettes.includes(index); } function updateColorInputs(colorValue) { colorPickerWrapper.style.backgroundColor = colorValue; colorPicker.value = colorValue; colorInput.value = colorValue; } function editColor(event) { if (!event.target.classList.contains('gameToolsColor')) return; if (!event.shiftKey) updateColorInputs(rgbToHex(event.target.style.backgroundColor)); if (isPaletteLocked(paletteIndex)) return; const color = { node: event.target, index: Array.prototype.indexOf.call(colorButtons, event.target) }; if (event.altKey && event.shiftKey) { deletePalette(paletteIndex); } else if (event.altKey && color.index >= 0) { const palette = palettes[paletteIndex]; palette.splice(color.index, 1); changePalette(); if (isPaletteEmpty(palette)) deletePalette(paletteIndex); savePalettes(); } else if (event.shiftKey && color.index >= 0) { setActiveColor(color); } } function deletePalette(index) { if (palettes.length < 2) return; palettes.splice(index, 1); lockedPalettes = lockedPalettes.map(lockedIndex => { return lockedIndex > index ? lockedIndex - 1 : lockedIndex; }); localStorage.setItem('lockedPalettes', JSON.stringify(lockedPalettes)); prevPalette(); savePalettes(); updateLock(); } function changePalette() { if (paletteIndex < 0 || paletteIndex >= palettes.length) { paletteIndex = 0; localStorage.setItem('paletteIndex', paletteIndex); } colorButtons.forEach((button, idx) => { button.style.backgroundColor = palettes[paletteIndex][idx] || '#fff'; }); updateLock(); } function isPaletteEmpty(palette) { if (!palette) return true; let empty = true; for (const color of palette) { if (color) { empty = false; break; } } return empty; } function setActiveColor(color) { resetActiveColor(); activeColor = color; activeColor.node.style.border = 'solid 2px red'; } function resetActiveColor() { if (activeColor.node) { activeColor.node.style.border = ''; activeColor = { node: null, index: null }; } } function addButton(button, icon, pos, tooltip = '', id = '') { const buttonStyle = `margin: ${pos}; position: absolute; height: 20px; border: none; background-color: #CBCBCB; border-radius: 5px;`; button.setAttribute('style', buttonStyle); button.setAttribute('class', `fas fa-${icon}`); tooltip && button.setAttribute('data-toggle', 'tooltip'); tooltip && button.setAttribute('data-original-title', tooltip); button.setAttribute('data-placement', 'bottom'); button.title = tooltip; button.id = id; gameTools.appendChild(button); } function updatePicker(event) { const color = event.target.value; colorPickerWrapper.style.backgroundColor = color; colorInput.value = color; setColorDebounced(color); } function updateInput(event) { const hexFound = /([0-9A-Fa-f]{3}){1,2}/.exec(event.target.value); if (!hexFound) return; const color = '#' + hexFound[0]; colorPickerWrapper.style.backgroundColor = color; colorPicker.value = color; setColorDebounced(color); } const pointerdownEvent = new Event('pointerdown'); function setColor(color) { const prevColor = colorButton.style.backgroundColor; colorButton.style.backgroundColor = color; colorButton.dispatchEvent(pointerdownEvent); colorButton.style.backgroundColor = prevColor; } function selectInputText() { colorInput.select(); } function pickCanvasColor(event) { if (!event.altKey) return; event.preventDefault(); event.stopImmediatePropagation(); const pos = getPos(event); const [r, g, b] = ctx.getImageData(pos.x, pos.y, 1, 1).data; const color = `rgb(${r}, ${g}, ${b})`; updateColorInputs(rgbToHex(color)); setColorDebounced(color); } function getPos(event) { const canvasRect = canvas.getBoundingClientRect(); const canvasScale = canvas.width / canvasRect.width; return { x: (event.clientX - canvasRect.left) * canvasScale, y: (event.clientY - canvasRect.top) * canvasScale }; } function handleDrop(e) { e.preventDefault(); colorsDiv.style.filter = ''; handleFiles(e.dataTransfer.files); } function handleFiles(files) { if (!files) return; files = [...files]; files.forEach(file => { const reader = new FileReader(); reader.readAsText(file); reader.onload = loadPalette; }); } function addPalette(palette) { if (palettes[paletteIndex].length + palette.length < 40 && !isPaletteLocked(paletteIndex)) { palettes[paletteIndex] = palettes[paletteIndex].concat(palette); } else { palettes.push(palette); paletteIndex = palettes.length - 1; localStorage.setItem('paletteIndex', paletteIndex); } resetPaletteState(); } function loadPalette(event) { const loadedString = event.target.result; const coolorRegex = /CSV \*\/\s*(\S+)/; const arrayRegex = /\[\[?\s*([^\]]+)/g; const hexRegex = /#([0-9A-Fa-f]{3}){1,2}/g; const coolorMatch = loadedString.match(coolorRegex); const arrayMatch = loadedString.match(arrayRegex); if (coolorMatch) { const palette = coolorMatch[1].split(',').map(color => `#${color}`); addPalette(palette); return; } else if (arrayMatch) { const paletteMatch = arrayMatch.map(palette => palette.match(hexRegex)); paletteMatch.forEach(palette => addPalette(palette)); } else { addHexFromString(loadedString); } } function addHexFromString(string) { const hexRegex = /([0-9A-Fa-f]{3}){1,2}/g; const hexCodesFound = [...new Set(string.match(hexRegex))]; console.log('Hex codes found: ', hexCodesFound); const codes = hexCodesFound.map(code => '#' + code); codes.forEach(code => addColor(code)); changePalette(); savePalettes(); } function resetPaletteState() { updateLock(); changePalette(); savePalettes(); } function highlight(e) { e.preventDefault(); colorsDiv.style.filter = 'brightness(0.6)'; } function unhighlight(e) { e.preventDefault(); colorsDiv.style.filter = ''; } function isDrawing() { return document.querySelector('#gameTools').style.display !== 'none'; } function adjustChatSize() { chatBox.style.height = isDrawing() ? 'calc(100% - 200px)' : 'calc(100% - 180px)'; }