Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

board.js 8.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. /**
  2. * WHITEBOPHIR
  3. *********************************************************
  4. * @licstart The following is the entire license notice for the
  5. * JavaScript code in this page.
  6. *
  7. * Copyright (C) 2013 Ophir LOJKINE
  8. *
  9. *
  10. * The JavaScript code in this page is free software: you can
  11. * redistribute it and/or modify it under the terms of the GNU
  12. * General Public License (GNU GPL) as published by the Free Software
  13. * Foundation, either version 3 of the License, or (at your option)
  14. * any later version. The code is distributed WITHOUT ANY WARRANTY;
  15. * without even the implied warranty of MERCHANTABILITY or FITNESS
  16. * FOR A PARTICULAR PURPOSE. See the GNU GPL for more details.
  17. *
  18. * As additional permission under GNU GPL version 3 section 7, you
  19. * may distribute non-source (e.g., minimized or compacted) forms of
  20. * that code without the copy of the GNU GPL normally required by
  21. * section 4, provided you include this license notice and a URL
  22. * through which recipients can access the Corresponding Source.
  23. *
  24. * @licend
  25. */
  26. var Tools = {};
  27. Tools.board = document.getElementById("board");
  28. Tools.svg = document.getElementById("canvas");
  29. Tools.socket = io.connect('');
  30. Tools.curTool = null;
  31. Tools.HTML = {
  32. template : new Minitpl("#tools > .tool"),
  33. addTool : function(toolName) {
  34. var callback = function () {
  35. Tools.change(toolName);
  36. };
  37. return this.template.add(function (elem) {
  38. elem.addEventListener("click", callback);
  39. elem.id = "toolID-"+toolName;
  40. return toolName;
  41. }
  42. );
  43. },
  44. changeTool : function(oldToolName, newToolName) {
  45. var oldTool = document.getElementById("toolID-"+oldToolName);
  46. var newTool = document.getElementById("toolID-"+newToolName);
  47. if (oldTool) oldTool.classList.remove("curTool");
  48. if (newTool) newTool.classList.add("curTool");
  49. },
  50. addStylesheet : function(href) {
  51. //Adds a css stylesheet to the html or svg document
  52. var link = document.createElement("link");
  53. link.href = href;
  54. link.rel = "stylesheet";
  55. link.type = "text/css";
  56. document.head.appendChild(link);
  57. }
  58. };
  59. Tools.list = {}; // An array of all known tools. {"toolName" : {toolObject}}
  60. Tools.add = function (newTool) {
  61. if (newTool.name in Tools.list) {
  62. console.log("Tools.add: The tool '"+newTool.name+"' is already" +
  63. "in the list. Updating it...");
  64. }
  65. //Format the new tool correctly
  66. Tools.applyHooks(Tools.toolHooks, newTool);
  67. //Add the tool to the list
  68. Tools.list[newTool.name] = newTool;
  69. if (newTool.stylesheet) {
  70. Tools.HTML.addStylesheet(newTool.stylesheet);
  71. }
  72. //Add the tool to the GUI
  73. Tools.HTML.addTool(newTool.name);
  74. }
  75. Tools.change = function (toolName){
  76. if (! (toolName in Tools.list)) {
  77. throw "Trying to select a tool that has never been added!";
  78. }
  79. var newtool = Tools.list[toolName];
  80. //Update the GUI
  81. var curToolName = (Tools.curTool) ? Tools.curTool.name : "";
  82. Tools.HTML.changeTool(curToolName, toolName);
  83. Tools.svg.style.cursor = newtool.mouseCursor || "auto";
  84. //There is not necessarily already a curTool
  85. if (Tools.curTool !== null) {
  86. //It's useless to do anything if the new tool is already selected
  87. if (newtool === Tools.curTool) return;
  88. //Remove the old event listeners
  89. for (var event in Tools.curTool.compiledListeners) {
  90. var listener = Tools.curTool.compiledListeners[event];
  91. Tools.board.removeEventListener(event, listener);
  92. }
  93. //Call the callbacks of the old tool
  94. Tools.curTool.onquit(newtool);
  95. }
  96. //Add the new event listeners
  97. for (var event in newtool.compiledListeners) {
  98. var listener = newtool.compiledListeners[event];
  99. Tools.board.addEventListener(event, listener);
  100. }
  101. //Call the start callback of the new tool
  102. newtool.onstart(Tools.curTool);
  103. Tools.curTool = newtool;
  104. };
  105. Tools.send = function(data, toolName){
  106. var toolName = toolName || Tools.curTool.name;
  107. var message = {
  108. 'tool' : toolName,
  109. 'data' : data
  110. };
  111. Tools.applyHooks(Tools.messageHooks, message);
  112. Tools.socket.emit('broadcast', message);
  113. };
  114. Tools.drawAndSend = function (data) {
  115. Tools.curTool.draw(data, true);
  116. Tools.send(data);
  117. };
  118. Tools.socket.on("broadcast", function (message){
  119. //Check if the message is in the expected format
  120. Tools.applyHooks(Tools.messageHooks, message);
  121. if (message.tool && message.data) {
  122. var tool = Tools.list[message.tool];
  123. if (!tool) throw "Received a message for an unknown tool!";
  124. tool.draw(message.data, false); //draw the received data
  125. } else {
  126. throw "Received a badly formatted message";
  127. }
  128. });
  129. //List of hook functions that will be applied to messages before sending or drawing them
  130. Tools.messageHooks = [
  131. function resizeCanvas (m) {
  132. if (m.data && m.data.x && m.data.y) {
  133. var svg = Tools.svg, x=m.data.x, y=m.data.y;
  134. if (x > svg.width.baseVal.value - 1000) {
  135. svg.width.baseVal.value = x + 2000;
  136. }
  137. if (y > svg.height.baseVal.value - 500) {
  138. svg.height.baseVal.value = y + 2000;
  139. }
  140. }
  141. }
  142. ];
  143. //List of hook functions that will be applied to tools before adding them
  144. Tools.toolHooks = [
  145. function checkToolAttributes(tool) {
  146. if (typeof(tool.name)!=="string") throw "A tool must have a name";
  147. if (typeof(tool.listeners)!=="object") {
  148. tool.listeners = {};
  149. }
  150. if (typeof(tool.onstart)!=="function") {
  151. tool.onstart = new Function();
  152. }
  153. if (typeof(tool.onquit)!=="function") {
  154. tool.onquit = new Function();
  155. }
  156. },
  157. function compileListeners (tool) {
  158. //compile listeners into compiledListeners
  159. var listeners = tool.listeners;
  160. var compiled = tool.compiledListeners || {};
  161. tool.compiledListeners = compiled;
  162. function compile (listener) { //closure
  163. return (function listen (evt){
  164. var x = evt.pageX,
  165. y = evt.pageY;
  166. return listener(x,y,evt,false);
  167. });
  168. }
  169. function compileTouch (listener) { //closure
  170. return (function touchListen (evt) {
  171. //Currently, we don't handle multitouch
  172. if (evt.changedTouches.length === 1) {
  173. //evt.preventDefault();
  174. var touch = evt.changedTouches[0];
  175. var x = touch.pageX,
  176. y = touch.pageY;
  177. return listener(x,y,evt,true);
  178. }
  179. return true;
  180. });
  181. }
  182. if (listeners.press) {
  183. compiled["mousedown"] = compile(listeners.press);
  184. compiled["touchstart"] = compileTouch(listeners.press);
  185. }
  186. if (listeners.move) {
  187. compiled["mousemove"] = compile(listeners.move);
  188. compiled["touchmove"] = compileTouch(listeners.move);
  189. }
  190. if (listeners.release) {
  191. var release = compile(listeners.release),
  192. releaseTouch = compileTouch(listeners.release);
  193. compiled["mouseup"] = release;
  194. compiled["mouseleave"] = release;
  195. compiled["touchleave"] = releaseTouch;
  196. compiled["touchend"] = releaseTouch;
  197. compiled["touchcancel"] = releaseTouch;
  198. }
  199. }
  200. ];
  201. Tools.applyHooks = function(hooks, object) {
  202. //Apply every hooks on the object
  203. hooks.forEach(function(hook) {
  204. hook(object);
  205. });
  206. };
  207. // Utility functions
  208. Tools.generateUID = function (prefix, suffix) {
  209. var rndStr = (Math.round(Math.random()*1e19)).toString(36);
  210. if (prefix) rndStr = prefix + rndStr;
  211. if (suffix) rndStr = rndStr + suffix;
  212. return rndStr;
  213. };
  214. Tools.createSVGElement = function (name) {
  215. return document.createElementNS(Tools.svg.namespaceURI, name);
  216. };
  217. Tools.positionElement = function (elem, x, y) {
  218. elem.style.top = y+"px";
  219. elem.style.left = x+"px";
  220. };
  221. (function color (){
  222. var chooser = document.getElementById("chooseColor");
  223. if (chooser.type == "text") {
  224. //The browser doesn't support <input type='color'>, use jsColor instead
  225. new jscolor.color(chooser, {
  226. "required" : false,
  227. "adjust" : false,
  228. "hash" : true,
  229. });
  230. }
  231. Tools.getColor = function(){
  232. return chooser.value;
  233. };
  234. })();
  235. (function size (){
  236. var chooser = document.getElementById("chooseSize");
  237. function update (){
  238. if (chooser.value<1 || chooser.value > 50) {
  239. chooser.value=3;
  240. }
  241. }
  242. update();
  243. chooser.onchange = update;
  244. Tools.getSize = function(){
  245. return chooser.value;
  246. };
  247. })();
  248. //Scale the canvas on load
  249. Tools.svg.width.baseVal.value = document.body.clientWidth;
  250. Tools.svg.height.baseVal.value = document.body.clientHeight;
  251. (function menu () {
  252. var menu = document.getElementById("menu");
  253. tog = document.getElementById("toggleMenu");
  254. tog.onclick = function(e){
  255. menu.classList.toggle("closed");
  256. };
  257. })();
  258. //tools may use performance.now, but Safari doesn't support it
  259. if (!window.performance) {
  260. window.performance = {
  261. "now" : Date.now
  262. }
  263. }
  264. /**
  265. What does a "tool" object look like?
  266. newtool = {
  267. "name" : "SuperTool",
  268. "listeners" : {
  269. "press" : function(x,y,evt){...},
  270. "move" : function(x,y,evt){...},
  271. "release" : function(x,y,evt){...},
  272. },
  273. "draw" : function(data, isLocal){
  274. //Print the data on Tools.svg
  275. },
  276. "onstart" : function(oldTool){...},
  277. "onquit" : function(newTool){...},
  278. "stylesheet" : "style.css",
  279. }
  280. */