Color Picker

Color picker for Sketchful

目前为 2020-06-30 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name Color Picker
  3. // @namespace https://greasyfork.org/users/281093
  4. // @match https://sketchful.io/*
  5. // @grant none
  6. // @version 0.5
  7. // @author Bell
  8. // @description Color picker for Sketchful
  9. // @run-at document-end
  10. // jshint esversion: 6
  11. // ==/UserScript==
  12.  
  13. let defaultPalettes = [
  14. [
  15. "#ffffff","#d3d1d2","#f70f0f","#ff7200","#fce700","#02cb00","#01fe94","#05b0ff","#221ecd","#a300bd","#cc7fad","#fdad88","#9e5425",
  16. "#514f54","#a9a7a8","#ae0b00","#c84706","#ec9e06","#007612","#049d6f","#00579d","#0f0b96","#6e0083","#a65673","#e38a5e","#5e320d",
  17. "#000000","#827c80","#57060c","#8b2500","#9e6600","#003f00","#00766a","#003b75","#0e0151","#3c0350","#73314d","#d1754e","#421e06"
  18. ],
  19.  
  20. [
  21. "#3a3a3c","#8e8e93","#f8f9fa","#ffadad","#ffd6a5","#fdffb6","#caffbf","#9bf6ff","#a0c4ff","#bdb2ff","#ffc6ff","#fdad88","#9e5425",
  22. "#2c2c2e","#636366","#e0e0e0","#ff7070","#f3a220","#f9e079","#049d6f","#92ddea","#6dafe0","#ab87ff","#ff87ab","#e38a5e","#5e320d",
  23. "#1c1c1e","#48484a","#c2c2c2","#f54d4d","#dc8700","#f0c808","#00766a","#219bc3","#548bbc","#715aff","#ff5d8f","#d1754e","#421e06"
  24. ],
  25.  
  26. [
  27. "#081c15","#1b4332","#2d6a4f","#40916c","#52b788","#74c69d","#95d5b2","#b7e4c7","#d8f3dc","#000000","#faf9f9","#ffd6ba","#fec89a",
  28. "#774936","#8a5a44","#9d6b53","#b07d62","#c38e70","#cd9777","#d69f7e","#deab90","#e6b8a2","#edc4b3","#ffb5a7","#fcd5ce","#f8edeb",
  29. "#cb997e","#eddcd2","#fff1e6","#f0efeb","#ddbea9","#a5a58d","#b7b7a4","#6d6875","#b5838d","#e5989b","#ffb4a2","#ffcdb2","#f9dcc4"
  30. ],
  31.  
  32. [
  33. "#10002b","#240046","#3c096c","#5a189a","#7b2cbf","#9d4edd","#c77dff","#e0aaff","#efcefa","#d4b2d8","#a88fac","#826c7f","#5d4e60",
  34. "#7c6f93","#886f93","#a967ad","#ad6789","#db81ad","#ff6c91","#ff736c","#ff9e46","#faa275","#ff8c61","#ce6a85","#985277","#5c374c",
  35. "#721b65","#b80d57","#f8615a","#ffd868","#bb596b","#f96d80","#ff9a76","#ffc4a3","#00e0ff","#74f9ff","#a6fff2","#e8ffe8","#ffffff"
  36. ],
  37.  
  38. [
  39. "#007f5f","#2b9348","#55a630","#80b918","#aacc00","#bfd200","#d4d700","#dddf00","#eeef20","#ffff3f","#03045e","#0077b6","#00b4d8",
  40. "#ff4800","#ff5400","#ff6000","#ff6d00","#ff7900","#ff8500","#ff9100","#ff9e00","#ffaa00","#ffb600","#90e0ef","#caf0f8","#000000",
  41. "#143642","#263c41","#38413f","#4a473e","#5c4d3c","#6f523b","#815839","#935e38","#a56336","#b76935","#000000","#ffffff","#ffffff"
  42. ]
  43. ];
  44. let palettes = JSON.parse(localStorage.getItem('palettes')) || defaultPalettes;
  45. let paletteIndex = parseInt(localStorage.getItem("paletteIndex")) || 0;
  46. let lockedPalettes = JSON.parse(localStorage.getItem('lockedPalettes')) || [0];
  47. let activeColor = {
  48. node: null,
  49. index: null
  50. };
  51.  
  52. const canvas = document.querySelector("#canvas");
  53. const ctx = canvas.getContext("2d");
  54. const gameTools = document.querySelector("#gameTools");
  55. const chatBox = document.querySelector("#gameChat");
  56. const colorButtons = document.querySelectorAll(".gameToolsColor");
  57. const colorsDiv = document.querySelector("#gameToolsColors");
  58. const colorButton = document.querySelector("#gameToolsColors > div:nth-child(1) > div:nth-child(1)");
  59.  
  60. const colorPickerWrapper = document.createElement("div");
  61. const colorInput = document.createElement("input");
  62. const colorPicker = document.createElement("input");
  63. const inputStyle = `margin: 5px 0; height: 20px; width: 35%; text-align: center; border: none;font-weight: 800; border-radius: 5px; background-color: #CBCBCB;`;
  64. const wrapperStyle = `position: absolute; margin: 5px 35%; height: 20px; width: 37px; border-radius: 5px;`;
  65.  
  66. (function init() {
  67. addPicker();
  68. updatePageStyle();
  69. addObservers();
  70. addListeners();
  71. changePalette(paletteIndex);
  72. })();
  73.  
  74. function addPicker() {
  75. colorPicker.type = "color";
  76. colorPicker.setAttribute("style", "opacity: 0; width: 37px; cursor: pointer;");
  77. colorPicker.oninput = updatePicker;
  78.  
  79. colorPickerWrapper.setAttribute("style", wrapperStyle);
  80. colorPickerWrapper.style.backgroundColor = colorPicker.value;
  81. colorPickerWrapper.appendChild(colorPicker);
  82. gameTools.appendChild(colorPickerWrapper);
  83.  
  84. colorInput.oninput = updateInput;
  85. colorInput.addEventListener("click", selectInputText, false);
  86. colorInput.setAttribute("style", inputStyle);
  87. colorInput.setAttribute("spellcheck", "false");
  88. colorInput.value = colorPicker.value;
  89. gameTools.appendChild(colorInput);
  90. addButtons();
  91. }
  92.  
  93. function addObservers() {
  94. const heightObserver = new MutationObserver(adjustChatSize);
  95. const config = {
  96. attributes: true,
  97. childList: false,
  98. subtree: false
  99. };
  100. heightObserver.observe(gameTools, config);
  101. heightObserver.observe(chatBox, config);
  102. }
  103.  
  104. function addListeners() {
  105. canvas.addEventListener('pointerdown', pickCanvasColor, false);
  106. colorsDiv.addEventListener("click", editColor, false);
  107. let saveBtn = document.querySelector("#savePalette");
  108. saveBtn.addEventListener("dragenter", highlight, false);
  109. saveBtn.addEventListener("dragleave", unhighlight, false);
  110. saveBtn.addEventListener("drop", handleDrop, false);
  111. saveBtn.addEventListener("dragover", e => { e.preventDefault(); }, false);
  112. }
  113.  
  114. function updatePageStyle() {
  115. document.querySelector("#gameToolsSlider").style.top = "77px";
  116. gameTools.style.height = "200px";
  117. }
  118.  
  119. function toggleLock() {
  120. let lockBtn = document.querySelector("#lockButton");
  121. if (lockBtn.getAttribute("state") === "unlocked") {
  122. lockPalette(lockBtn);
  123. } else {
  124. unlockPalette(lockBtn);
  125. }
  126. updateLock();
  127. }
  128.  
  129. function lockPalette(lockBtn) {
  130. lockedPalettes.push(paletteIndex);
  131. localStorage.setItem("lockedPalettes", JSON.stringify(lockedPalettes));
  132. }
  133.  
  134. function unlockPalette(lockBtn) {
  135. let index = lockedPalettes.indexOf(paletteIndex);
  136. if (index < 0) return;
  137. lockedPalettes.splice(index, 1);
  138. localStorage.setItem("lockedPalettes", JSON.stringify(lockedPalettes));
  139. }
  140.  
  141. function updateLock() {
  142. let lockBtn = document.querySelector("#lockButton");
  143. if (isPaletteLocked()) {
  144. lockBtn.classList.remove("fa-unlock-alt");
  145. lockBtn.classList.add("fa-lock");
  146. lockBtn.setAttribute("state", "locked");
  147. } else {
  148. lockBtn.classList.add("fa-unlock-alt");
  149. lockBtn.classList.remove("fa-lock");
  150. lockBtn.setAttribute("state", "unlocked");
  151. }
  152. resetActiveColor();
  153. }
  154.  
  155. function addButtons() {
  156. let prevPaletteBtn = document.createElement("button");
  157. let saveColorBtn = document.createElement("button");
  158. let nextPaletteBtn = document.createElement("button");
  159. let lockBtn = document.createElement("button");
  160. addButton(prevPaletteBtn, "arrow-left", "5px 5px 5px 45px;");
  161. addButton(saveColorBtn, "save", "5px 5px 5px 75px;", "savePalette");
  162. addButton(nextPaletteBtn, "arrow-right", "5px 5px 5px 105px;");
  163. addButton(lockBtn, "unlock-alt", "5px 5px 5px 135px;", "lockButton");
  164. lockBtn.setAttribute("state", "unlocked");
  165.  
  166. prevPaletteBtn.addEventListener("click", prevPalette, false);
  167. saveColorBtn.addEventListener("click", saveColor, false);
  168. nextPaletteBtn.addEventListener("click", nextPalette, false);
  169. lockBtn.addEventListener("click", toggleLock, false);
  170. }
  171.  
  172. function nextPalette() {
  173. paletteIndex < (palettes.length - 1) && paletteIndex++;
  174. localStorage.setItem("paletteIndex", paletteIndex);
  175. changePalette();
  176. }
  177.  
  178. function prevPalette() {
  179. paletteIndex > 0 && paletteIndex--;
  180. localStorage.setItem("paletteIndex", paletteIndex);
  181. changePalette();
  182. }
  183.  
  184. function saveColor(e) {
  185. if (e.shiftKey) {
  186. downloadPalettes();
  187. return;
  188. }
  189. let currentPalette = palettes[paletteIndex];
  190. if (activeColor.index) {
  191. currentPalette[activeColor.index] = colorPicker.value;
  192. } else {
  193. while (currentPalette.length >= 39 || isPaletteLocked()) {
  194. paletteIndex++;
  195. if (paletteIndex === palettes.length) {
  196. palettes.push([]);
  197. }
  198. currentPalette = palettes[paletteIndex];
  199. }
  200. currentPalette.push(colorPicker.value);
  201. }
  202. changePalette();
  203. savePalettes();
  204. }
  205.  
  206. function savePalettes() {
  207. localStorage.setItem("palettes", JSON.stringify(palettes));
  208. }
  209.  
  210. function downloadPalettes() {
  211. let formattedPaletteData = JSON.stringify(palettes).replace(/\]\,/g, "],\n\n");
  212. download("palettes.txt", formattedPaletteData);
  213. }
  214.  
  215. function download(filename, text) {
  216. let pom = document.createElement('a');
  217. pom.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));
  218. pom.setAttribute('download', filename);
  219. if (document.createEvent) {
  220. let event = document.createEvent('MouseEvents');
  221. event.initEvent('click', true, true);
  222. pom.dispatchEvent(event);
  223. }
  224. else {
  225. pom.click();
  226. }
  227. }
  228.  
  229. function isPaletteLocked() {
  230. return lockedPalettes.includes(paletteIndex);
  231. }
  232.  
  233. function editColor(event) {
  234. if (isPaletteLocked() || !event.target.classList.contains("gameToolsColor")) return;
  235. event.preventDefault();
  236. let color = {
  237. node: event.target,
  238. index: Array.prototype.indexOf.call(colorButtons, event.target)
  239. };
  240. if (event.altKey) {
  241. if (color.index >= 0 && paletteIndex >= 0) {
  242. let palette = palettes[paletteIndex];
  243. palette.splice(color.index, 1);
  244. if (isPaletteEmpty(palette)) {
  245. palettes.splice(paletteIndex, 1);
  246. paletteIndex--;
  247. }
  248. changePalette();
  249. savePalettes();
  250. }
  251. } else if (event.shiftKey) {
  252. setActiveColor(color);
  253. }
  254. }
  255.  
  256. function changePalette() {
  257. if (paletteIndex < 0 || paletteIndex >= palettes.length) {
  258. paletteIndex = 0;
  259. localStorage.setItem("paletteIndex", paletteIndex);
  260. }
  261. colorButtons.forEach((button, idx) => {
  262. let color = palettes[paletteIndex][idx] || "#fff";
  263. button.style.backgroundColor = color;
  264. });
  265. resetActiveColor();
  266. updateLock();
  267. }
  268.  
  269. function isPaletteEmpty(palette) {
  270. if (!palette) return true;
  271. let empty = true;
  272. for (let color of palette) {
  273. if (color) {
  274. empty = false;
  275. break;
  276. }
  277. }
  278. return empty;
  279. }
  280.  
  281. function setActiveColor(color) {
  282. resetActiveColor();
  283. activeColor = color;
  284. console.log(activeColor);
  285. activeColor.node.style.border = "solid 2px red";
  286. }
  287.  
  288. function resetActiveColor() {
  289. if (activeColor.node) {
  290. activeColor.node.style.border = "";
  291. activeColor = {
  292. node: null,
  293. index: null
  294. };
  295. }
  296. }
  297.  
  298. function addButton(button, icon, pos, id = "") {
  299. let buttonStyle = `margin: ${pos}; position: absolute; height: 20px; border: none; background-color: #CBCBCB; border-radius: 5px;`;
  300. button.setAttribute("style", buttonStyle);
  301. button.setAttribute("class", `fas fa-${icon}`);
  302. button.id = id;
  303. gameTools.appendChild(button);
  304. }
  305.  
  306. function updatePicker(event) {
  307. let color = event.target.value;
  308. colorPickerWrapper.style.backgroundColor = color;
  309. colorInput.value = color;
  310. setColor(color);
  311. }
  312.  
  313. function updateInput(event) {
  314. let color = event.target.value;
  315. colorPickerWrapper.style.backgroundColor = color;
  316. colorPicker.value = color;
  317. setColor(color);
  318. }
  319.  
  320. function setColor(color) {
  321. let prevColor = colorButton.style.backgroundColor;
  322. colorButton.style.backgroundColor = color;
  323. colorButton.dispatchEvent(new Event("pointerdown"));
  324. colorButton.style.backgroundColor = prevColor;
  325. }
  326.  
  327. function selectInputText() {
  328. colorInput.select();
  329. }
  330.  
  331. function pickCanvasColor(event) {
  332. if (!event.altKey) return;
  333. event.stopImmediatePropagation();
  334. let pos = getPos(event);
  335. let [r, g, b, a] = ctx.getImageData(pos.x, pos.y, 1, 1).data;
  336. let color = `rgb(${r}, ${g}, ${b})`;
  337. setColor(color);
  338. }
  339.  
  340. function getPos(event) {
  341. let canvasRect = canvas.getBoundingClientRect();
  342. let canvasScale = canvas.width / canvasRect.width;
  343. return {
  344. x: (event.clientX - canvasRect.left) * canvasScale,
  345. y: (event.clientY - canvasRect.top) * canvasScale
  346. };
  347. }
  348.  
  349. function handleDrop(e) {
  350. e.preventDefault();
  351. colorsDiv.style.filter = "";
  352. let file = e.dataTransfer.files[0];
  353. console.log(file);
  354. if (file) {
  355. let reader = new FileReader();
  356. reader.readAsText(file);
  357. reader.onload = (e) => {
  358. loadPalettes(JSON.parse(e.target.result));
  359. };
  360. }
  361. }
  362.  
  363. function loadPalettes(loadedPalettes) {
  364. downloadPalettes();
  365. palettes = loadedPalettes;
  366. paletteIndex = 0;
  367. lockedPalettes = [];
  368. resetActiveColor();
  369. updateLock();
  370. changePalette();
  371. savePalettes();
  372. }
  373.  
  374. function highlight(e) {
  375. e.preventDefault();
  376. colorsDiv.style.filter = "brightness(0.8)";
  377. }
  378.  
  379. function unhighlight(e) {
  380. console.log("leave");
  381. e.preventDefault();
  382. colorsDiv.style.filter = "";
  383. }
  384.  
  385. function isDrawing() {
  386. return document.querySelector("#gameTools").style.display !== "none";
  387. }
  388.  
  389. function adjustChatSize() {
  390. chatBox.style.height = isDrawing() ? "calc(100% - 200px)" : "calc(100% - 180px)";
  391. }