Add a whiteout tool as the secondary function of the pencil tool (#47)

* added whiteout icon made by Freeplk on flaticon.com

* added whiteout fluid icon (public domain).

* Added whiteout tool as secondary function of pencil tool.

Co-authored-by: Robert Beach <rdbeach@gmail.com>

* shrink icon width using stroke

* shrink whiteout icon properly

* shrink whiteout fluid icon

* reduce number of allowed messages

* simplify

* remove layer code

* renmove show/hide marker code

* change white to #ffffff

* make toggle function compatible with current implementation

* Revert changes unrelated to the whiteout tool

* Refactor secondary tool logic between ellipse and pencil

* Add translations for the whiteout pen

* Fix tests

Co-authored-by: Robert Beach <rdbeach@gmail.com>
Co-authored-by: ophir <pere.jobs@gmail.com>

(@rdbeach)
This commit is contained in:
finnboeger 2020-05-13 22:15:11 +02:00 committed by GitHub
parent 7cc186be80
commit 740246528f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 132 additions and 48 deletions

View file

@ -122,7 +122,7 @@ Tools.HTML = {
Tools.i18n.t(toolName) + " (" +
Tools.i18n.t("keyboard shortcut") + ": " +
toolShortcut + ")" +
(Tools.list[toolName].toggle ? " [" + Tools.i18n.t("click_to_toggle") + "]" : "");
(Tools.list[toolName].secondary ? " [" + Tools.i18n.t("click_to_toggle") + "]" : "");
});
},
changeTool: function (oldToolName, newToolName) {
@ -131,6 +131,11 @@ Tools.HTML = {
if (oldTool) oldTool.classList.remove("curTool");
if (newTool) newTool.classList.add("curTool");
},
toggle: function (toolName, name, icon) {
var elem = document.getElementById("toolID-" + toolName);
elem.getElementsByClassName("tool-icon")[0].src = icon;
elem.getElementsByClassName("tool-name")[0].textContent = Tools.i18n.t(name);
},
addStylesheet: function (href) {
//Adds a css stylesheet to the html or svg document
var link = document.createElement("link");
@ -214,7 +219,12 @@ Tools.change = function (toolName) {
var oldTool = Tools.curTool;
if (!newTool) throw new Error("Trying to select a tool that has never been added!");
if (newTool === oldTool) {
if (newTool.toggle) newTool.toggle();
if (newTool.secondary) {
newTool.secondary.active = !newTool.secondary.active;
var props = newTool.secondary.active ? newTool.secondary : newTool;
Tools.HTML.toggle(newTool.name, props.name, props.icon);
if (newTool.secondary.switch) newTool.secondary.switch();
}
return;
}
if (!newTool.oneTouch) {
@ -267,6 +277,17 @@ Tools.removeToolListeners = function removeToolListeners(tool) {
}
};
(function () {
// Handle secondary tool switch with shift (key code 16)
function handleShift(active, evt) {
if (evt.keyCode === 16 && Tools.curTool.secondary && Tools.curTool.secondary.active !== active) {
Tools.change(Tools.curTool.name);
}
}
window.addEventListener("keydown", handleShift.bind(null, true));
window.addEventListener("keyup", handleShift.bind(null, false));
})();
Tools.send = function (data, toolName) {
toolName = toolName || Tools.curTool.name;
var d = data;
@ -513,7 +534,7 @@ Tools.generateUID = function (prefix, suffix) {
Tools.createSVGElement = function createSVGElement(name, attrs) {
var elem = document.createElementNS(Tools.svg.namespaceURI, name);
if (typeof(attrs) !== "object") return elem;
if (typeof (attrs) !== "object") return elem;
Object.keys(attrs).forEach(function (key, i) {
elem.setAttributeNS(null, key, attrs[key]);
});

View file

@ -25,11 +25,6 @@
*/
(function () { //Code isolation
//Indicates the id of the shape the user is currently drawing or an empty string while the user is not drawing
var isCircle = false; // current state: true for a circle, false for an ellipse
var isShifted = false; // whether shift is pressed. When it is, the ellipse and circle functions are reversed
var icons = ["tools/ellipse/icon-ellipse.svg", "tools/ellipse/icon-circle.svg"];
var toolNames = ["Ellipse", "Circle"];
var curUpdate = { //The data of the message that will be sent for every new point
'type': 'update',
'id': "",
@ -68,8 +63,8 @@
function move(x, y, evt) {
if (!curUpdate.id) return; // Not currently drawing
if (evt) {
evt.preventDefault();
switchTool(isCircle, evt.shiftKey);
circleTool.secondary.active = circleTool.secondary.active || evt.shiftKey;
evt.preventDefault();
}
lastPos.x = x;
lastPos.y = y;
@ -150,49 +145,26 @@
}
function drawingCircle() {
return !!(isCircle ^ isShifted);
return circleTool.secondary.active;
}
function toggle() {
switchTool(!isCircle, isShifted);
}
// Switch between ellipse and circle
function switchTool(switchToCircle, switchtoShifted) {
if (isCircle === switchToCircle &&
isShifted === switchtoShifted) return; // The tool was already in the correct state
isCircle = switchToCircle;
isShifted = switchtoShifted;
var index = drawingCircle() ? 1 : 0;
var elem = document.getElementById("toolID-" + circleTool.name);
elem.getElementsByClassName("tool-icon")[0].src = icons[index];
elem.getElementsByClassName("tool-name")[0].textContent = Tools.i18n.t(toolNames[index]);
doUpdate(true);
}
function keyToggle(e) {
if (e.keyCode !== 16) return; // 16 = Shift
if (e.type === "keydown") switchTool(isCircle, true);
if (e.type === "keyup") switchTool(isCircle, false);
}
keyToggle.target = window;
var circleTool = { //The new tool
"name": toolNames[0],
"name": "Ellipse",
"icon": "tools/ellipse/icon-ellipse.svg",
"secondary": {
"name": "Circle",
"icon": "tools/ellipse/icon-circle.svg",
"active": false,
"switch": doUpdate,
},
"shortcut": "c",
"listeners": {
"press": start,
"move": move,
"release": stop,
},
"compiledListeners": {
"keydown": keyToggle,
"keyup": keyToggle,
},
"draw": draw,
"toggle": toggle,
"mouseCursor": "crosshair",
"icon": icons[0],
"stylesheet": "tools/ellipse/ellipse.css"
};
Tools.add(circleTool);

View file

@ -48,9 +48,9 @@
Tools.drawAndSend({
'type': 'line',
'id': curLineId,
'color': Tools.getColor(),
'color': (pencilTool.secondary.active ? "#ffffff" : Tools.getColor()),
'size': Tools.getSize(),
'opacity': Tools.getOpacity()
'opacity': (pencilTool.secondary.active ? 1 : Tools.getOpacity()),
});
//Immediatly add a point to the line
@ -67,14 +67,19 @@
if (evt) evt.preventDefault();
}
function stopLine(x, y) {
function stopLineAt(x, y) {
//Add a last point to the line
continueLine(x, y);
stopLine();
}
function stopLine() {
curLineId = "";
}
var renderingLine = {};
function draw(data) {
Tools.drawingEvent = true;
switch (data.type) {
case "line":
renderingLine = createLine(data);
@ -126,18 +131,26 @@
return line;
}
Tools.add({
var pencilTool = {
"name": "Pencil",
"shortcut": "p",
"listeners": {
"press": startLine,
"move": continueLine,
"release": stopLine,
"release": stopLineAt,
},
"draw": draw,
"secondary": {
"name": "White-out",
"icon": "tools/pencil/whiteout_tape.svg",
"active": false,
"switch": stopLine,
},
"mouseCursor": "url('tools/pencil/cursor.svg'), crosshair",
"icon": "tools/pencil/icon.svg",
"stylesheet": "tools/pencil/pencil.css"
});
};
Tools.add(pencilTool);
})(); //End of code isolation

View file

@ -0,0 +1,39 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" x="0px" y="0px" viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;">
<path d="m 100.76367,41.789062 c -0.32301,6.791517 -8.676,7.017847 -13.622085,5.795571 -2.546951,-0.40692
-0.07076,4.253566 -0.864241,6.200523 0.322244,4.132609 -0.788102,8.756323 0.203125,12.53711 5.311344,-1.166656
14.109981,-0.84218 14.375001,6.396484 0.19432,6.098269 1.47934,15.703559 -6.556642,17.394531 -2.711323,0.766861
-5.831157,-1.648914 -8.160156,-0.785156 0.182017,6.08727 0.294665,13.168585 -0.03906,18.871095 5.635363,-1.47621
13.863687,-0.53042 15.183591,6.37695 -0.0327,3.286 0.15573,6.40669 -0.0918,9.70508 -1.09011,6.58132 -8.662821,8.73969
-14.362969,7.2776 -18.489628,-0.49827 -36.986183,-0.0405 -55.478832,-0.17799 0.250273,113.24245 -0.525971,226.50395
0.41211,339.73437 2.913239,21.72403 25.173061,37.853 46.765616,34.87479 68.228255,-0.32404 136.486875,0.72673
204.695325,-0.56619 21.41392,-3.3677 36.90164,-25.57351 33.96484,-46.61133 0,-109.14844 0,-218.29687 0,-327.44531
-23.6901,0 -47.38021,0 -71.07031,0 5.08931,-6.70941 -2.69559,-16.86869 4.86914,-22.41992 3.49765,-2.45311
8.72875,0.65703 11.71875,-1.34571 -0.76973,-6.03761 -0.21882,-12.131408 -0.37696,-18.193357 -5.33651,1.164124
-14.37765,1.072704 -14.57031,-6.302734 -0.30409,-6.017898 -1.58644,-15.220806 6.03125,-17.326172 2.84102,-1.060068
6.1359,1.530576 8.60742,0.675781 -0.18201,-6.08727 -0.29466,-13.168586 0.0391,-18.871094 -5.58535,1.438877
-13.74268,0.575212 -15.16407,-6.230468 0.11096,-7.515863 0.87174,-15.180999 0.51056,-22.81248 C 247.76662,14.36074
247.7307,10.180313 247.76172,6 c -48.99935,0 -97.9987,0 -146.99805,0 0,11.929688 0,23.859375 0,35.789062 z m
24.41602,-17.371093 c 35.27734,0 70.55469,0 105.83203,0 -5.07632,6.733704 2.63191,16.749089 -4.79492,22.4375
-9.73323,2.650279 -19.94128,-0.1125 -29.86328,0.933593 -26.21289,0 -52.42579,0 -78.63868,0 4.64436,-6.894539
-2.79455,-17.135446 4.8711,-22.65039 0.8005,-0.416054 1.6849,-0.710354 2.59375,-0.720703 z m 0,41.787109 c
35.27604,0 70.55208,0 105.82812,0 -5.05772,6.739826 2.62212,16.73808 -4.78711,22.4375 -9.73374,2.654454
-19.94403,-0.111536 -29.86718,0.935547 -26.21289,0 -52.42579,0 -78.63868,0 4.64434,-6.895217 -2.79444,-17.136767
4.8711,-22.652344 0.8005,-0.416054 1.6849,-0.710354 2.59375,-0.720703 z m 0,41.789062 c 35.27604,0 70.55208,0
105.82812,0 -5.05772,6.73983 2.62212,16.73808 -4.78711,22.4375 -9.73374,2.65445 -19.94403,-0.11154 -29.86718,0.93555
-26.21289,0 -52.42579,0 -78.63868,0 4.64434,-6.89522 -2.79444,-17.13677 4.8711,-22.65235 0.80003,-0.41718
1.68544,-0.7071 2.59375,-0.7207 z m -73.414065,41.79102 c 82.335285,0 164.670575,0 247.005855,0 -0.22195,106.41378
0.44501,212.85072 -0.3496,319.25 -2.10752,13.33106 -17.11199,21.09199 -29.69922,18.54178 -67.16878,-0.3476
-134.38403,0.74511 -201.523441,-0.57889 -12.802543,-2.71153 -19.783085,-17.23301 -17.433594,-29.44336 0,-102.58985
0,-205.17969 0,-307.76953 h 1 z" />
<path d="m 392.43555,89.216797 c 7.57617,0 15.15234,0 22.72851,0 -0.34096,51.710933 -0.67827,103.421883 -1.01953,155.132813
-15.30859,0 -30.61719,0 -45.92578,0 0.39476,71.57202 -0.8816,143.1804 0.6875,214.72851 4.41665,30.6783
37.64851,53.37426 67.90625,45.67969 26.21053,-5.90511 46.40184,-31.94655 43.66861,-58.87887 0.41091,-67.17512
0.0168,-134.35166 0.16928,-201.52738 -16.0293,0 -32.05859,0 -48.08789,0 0.34096,-51.71158 0.67827,-103.42318
1.01953,-155.134763 7.61524,0 15.23047,0 22.8457,0 0,-27.738932 0,-55.477865 0,-83.216797 -21.33072,0 -42.66145,0
-63.99218,0 0,27.738932 0,55.477865 0,83.216797 z m 36.72656,-64.978516 c 4.67986,-0.567803 10.95203,3.098207
8.84766,8.490235 0,12.690104 0,25.380208 0,38.070312 -9.05209,0 -18.10417,0 -27.15625,0 0,-15.479167 0,-30.958333
0,-46.4375 6.13174,0.270978 12.22003,0.104054 18.30859,-0.123047 z M 388.62695,262.76758 c 24.53841,0 49.07683,0
73.61524,0 -0.36935,64.60621 0.70713,129.24844 -0.5586,193.83203 -3.48924,22.94954 -31.22967,38.11674 -52.3125,27.94727
-15.93991,-6.82379 -25.1706,-25.02944 -22.74414,-41.97266 0,-59.93555 0,-119.87109 0,-179.80664 h 1 z" />
</svg>

After

Width:  |  Height:  |  Size: 4.1 KiB

View file

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns="http://www.w3.org/2000/svg"
height="512pt"
viewBox="0 0 511 512"
width="512pt"
version="1.1">
<path d="m 345.08008,125.98828 c -24.89726,0.73484 -44.1674,29.55872 -34.22461,52.79688 7.70594,20.99702
35.18297,32.36562 54.90234,20.76562 18.88488,-9.8306 27.24873,-35.94244 15.37362,-54.18016 -7.34367,-12.48294
-21.53357,-20.46516 -36.05135,-19.38234 z m 3.13476,17.89844 c 16.22278,-0.20548 26.79771,21.93191 15.85743,34.20898
-9.47233,13.12663 -33.60569,8.7097 -36.94922,-7.47265 -3.64415,-12.97473 7.35532,-27.64996 21.09179,-26.73633 z" />
<path d="M 342.4375,6.0566406 C 290.19086,7.4079629 242.35927,38.176593 212.42969,79.859375 172.0509,133.32565 151.6073,198.75524
139.05581,263.62731 c -11.0666,60.66577 -15.57746,123.65855 -2.59982,184.26864 3.18909,13.80335 7.59242,27.16891
13.48737,40.06694 -46.23636,0.71324 -92.60616,-1.19943 -138.757813,0.96875 -7.1679152,3.47864 -5.410118,16.97256
3.162109,16.73047 13.023959,1.13909 26.085166,-0.50886 39.160156,0.26172 39.107849,-0.35237 78.454368,1.21505
117.408208,-0.91797 11.62403,-6.4845 20.6696,-16.67658 31.82443,-23.97279 C 288.28553,414.05988 375.11489,348.62649
458.40039,278.83594 504.83041,234.27343 520.0166,160.66869 494.06641,101.66406 480.21113,69.208258 454.04807,42.773832
422.67383,26.75 398.07551,13.570622 370.36066,5.6740618 342.4375,6.0566406 Z M 348.85352,24 c 44.63846,2.483085
88.26507,24.942344 115.23828,60.738281 36.71253,50.940449 31.28826,126.334659 -10.41407,172.794919 -15.994,18.11801
-36.4534,31.41775 -54.72089,47.04015 -55.05329,43.79021 -110.39742,87.24271 -166.20498,130.06884 -3.72222,2.23748
-9.07682,8.72329 -13.16983,3.76406 -3.75188,-5.31875 2.30416,-10.35216 4.49646,-14.7625 13.42866,-22.34815 29.28176,-43.43994
40.47424,-67.01094 4.64981,-19.32452 0.35659,-39.20475 1.94336,-58.80078 0,-25.10872 0,-50.21745 0,-75.32617
27.26176,39.01383 84.277,53.47018 126.29297,30.65234 39.00097,-19.83374 62.13191,-67.20229 51.33064,-110.09176
-8.90693,-39.8821 -44.74436,-72.933336 -85.57282,-76.496128 -38.41872,-4.477176 -78.69119,15.465072 -97.16116,49.663138
-11.52851,19.93348 -14.48995,43.20794 -12.88963,65.78999 0,43.29752 0,86.59505 0,129.89258 -20.87317,-14.37821
-53.45386,-1.35833 -58.89453,23.32226 -6.06475,21.81707 10.85837,47.22737 33.78516,48.49414 4.83775,2.49928
-0.36425,8.00621 -2.14063,10.73438 -18.24321,29.05876 -36.4886,58.11617 -54.73047,87.17578 C 143.26543,428.02403
143.95411,367.86646 150.1924,310.83561 158.88876,236.25068 178.63809,160.96371 221.23047,98.173828 245.82544,62.859165
282.05659,32.802931 325.59375,25.908203 333.27466,24.615349 341.06518,23.988733 348.85352,24 Z m -0.17188,59.941406
c 42.61748,-0.335194 81.14427,38.442654 79.95508,81.179684 0.21285,38.53195 -30.27574,75.18815 -68.87305,80.06055
-35.24954,5.4699 -73.28159,-14.60202 -86.72461,-48.05273 -13.79996,-31.86015 -5.05109,-72.49697 22.5327,-94.23297
14.7417,-12.309901 33.87846,-19.259655 53.10988,-18.954534 z M 228.21875,323.88281 c 16.19696,-0.19704 26.78048,21.87394
15.89648,34.16602 -9.43643,13.15366 -33.57823,8.79654 -36.97265,-7.36914 -3.69471,-12.97578 7.32341,-27.72066 21.07617,-26.79688 z" />
</svg>

After

Width:  |  Height:  |  Size: 3.3 KiB

View file

@ -22,6 +22,7 @@
"opacity": "Opacity",
"color": "Color",
"eraser": "Eraser",
"White-out": "White-out",
"index_title": "Welcome to WBO !",
"introduction_paragraph": "WBO is a <a href=\"https://github.com/lovasoa/whitebophir\" title=\"Free as in free speech, not free beer. This software is released under the GPL license\">free and open-source</a> online collaborative whiteboard that allows many users to draw simultaneously on a large virtual board. The board is updated in real time for all connected users, and its state is always persisted. It can be used for many different purposes, including art, entertainment, design and teaching.",
"share_instructions": "To collaborate on a drawing in real time with someone, just send them its URL.",
@ -48,6 +49,7 @@
"ellipse": "Ellipse",
"click_to_toggle": "cliquer pour changer",
"eraser": "Gomme",
"white-out": "Blanco",
"hand": "Main",
"straight_line": "Ligne droite",
"keyboard_shortcut": "raccourci clavier",
@ -88,6 +90,7 @@
"opacity": "Deckkraft",
"color": "Farbe",
"eraser": "Radierer",
"white-out": "Korrekturflüssigkeit",
"index_title": "Wilkommen bei WBO!",
"introduction_paragraph": "WBO ist ein <a href=\"https://github.com/lovasoa/whitebophir\" title=\"Frei im Sinne von Redefreiheit, nicht Freibier. Diese Software wird unter der GPL Lizenz veröffentlicht.\">freies und quelloffenes</a> kollaboratives Online-Whiteboard das vielen Nutzern erlaubt gleichzeitig auf einem großen virtuellen Whiteboard zu zeichnen. Das Whiteboard wird in Echtzeit für alle Nutzer aktualisiert und sein Inhalt wird gespeichert. Es kann für verschiedenste Anwendungen genutzt werden, z.B. Kunst, Unterhaltung, Design, Unterricht und Lehre.",
"share_instructions": "Um mit jemanden zusammen an einem Whiteboard zu arbeiten teile einfach die jeweilige URL.",
@ -122,6 +125,7 @@
"opacity": "透明度",
"color": "色",
"eraser": "消去",
"white-out": "修正液",
"index_title": "WBOへようこそ!",
"introduction_paragraph": "WBOは<a href=\"https://github.com/lovasoa/whitebophir\" title=\"ビール飲み放題ではなく言論の自由。このソフトウェアはGPLライセンスで公開しています。\">無料かつオープンソース</a>の協同作業できるオンラインホワイトボードです。多くのユーザーが大きな仮想ホワイトボードに図などを書くことができ、接続しているすべてのユーザーの更新をリアルタイムに反映され、その状態を常に保存します。これはアート、エンタテインメント、デザインや教育など、様々な用途で使用できます。",
"share_instructions": "URLを送るだけで、リアルタイムな共同作業ができます。",
@ -144,6 +148,7 @@
"pencil": "Карандаш",
"text": "Текст",
"eraser": "Ластик",
"white-out": "Корректор",
"hand": "Движение",
"straight_line": "Прямая линия",
"rectangle": "Прямоугольник",
@ -182,6 +187,7 @@
"zoom": "放大",
"text": "文本",
"eraser": "橡皮",
"white-out": "修正液",
"hand": "移动",
"straight_line": "直线",
"configuration": "刷设置",