Mobile support
parent
92c6d12e90
commit
df0218a3c4
|
@ -45,12 +45,13 @@ You can also install it as a Chrome app.
|
||||||
It isn't perfectly seamless, and you may lose your drawing or be interrupted.
|
It isn't perfectly seamless, and you may lose your drawing or be interrupted.
|
||||||
* Load many different palette formats with Colors > Get Colors
|
* Load many different palette formats with Colors > Get Colors
|
||||||
(I made a [library](https://github.com/1j01/palette.js/) for this)
|
(I made a [library](https://github.com/1j01/palette.js/) for this)
|
||||||
|
* Mobile support
|
||||||
|
* Click/tap the selected colors area to swap the foreground and background colors
|
||||||
|
|
||||||
|
|
||||||
#### Possible improvements include:
|
#### Possible improvements include:
|
||||||
|
|
||||||
* [Extended Editing](#extended-editing)
|
* [Extended Editing](#extended-editing)
|
||||||
* Mobile support
|
|
||||||
* Proportionally resize the selection or canvas by holding <kbd>Shift</kbd>
|
* Proportionally resize the selection or canvas by holding <kbd>Shift</kbd>
|
||||||
* After adding text, save as SVG or HTML with selectable text
|
* After adding text, save as SVG or HTML with selectable text
|
||||||
* <kbd>Alt</kbd> as a shortcut for the eyedropper, as long as it doesn't conflict with keyboard navigation of menus
|
* <kbd>Alt</kbd> as a shortcut for the eyedropper, as long as it doesn't conflict with keyboard navigation of menus
|
||||||
|
|
16
TODO.md
16
TODO.md
|
@ -88,15 +88,13 @@
|
||||||
|
|
||||||
### Device support
|
### Device support
|
||||||
|
|
||||||
* Use pointer events polyfill...
|
* Multi-touch devices
|
||||||
* Multi-touch devices
|
* Two-finger drag to pan (the second touch cancels the default action just like normal)
|
||||||
* Second touch cancels current action just like a second button does on the desktop
|
* Single-touch devices
|
||||||
* Two-finger drag to pan
|
* Pan tool
|
||||||
* Single-touch devices
|
|
||||||
* Pan tool
|
|
||||||
|
|
||||||
|
|
||||||
* Tap (or click) the selected colors area to swap background/foreground colors
|
* Enlarge GUI elements on touch devices
|
||||||
|
|
||||||
|
|
||||||
* You can't use the Eraser/Color Eraser tool as a "Color Eraser" without a secondary mouse button
|
* You can't use the Eraser/Color Eraser tool as a "Color Eraser" without a secondary mouse button
|
||||||
|
@ -104,15 +102,13 @@
|
||||||
|
|
||||||
|
|
||||||
* Access to functionality that would normally require a keyboard (with a numpad!)
|
* Access to functionality that would normally require a keyboard (with a numpad!)
|
||||||
|
* Slide pointer between menu buttons and menu items
|
||||||
* Numpad +/-: Increase/Decrease brush size, Double/Half selection size, ...
|
* Numpad +/-: Increase/Decrease brush size, Double/Half selection size, ...
|
||||||
* Shift (toggle): Proportional, Smear / Trail Selection, "Snap to 8 directions" / "Octosnap"?
|
* Shift (toggle): Proportional, Smear / Trail Selection, "Snap to 8 directions" / "Octosnap"?
|
||||||
* Ctrl+Select: Crop tool
|
* Ctrl+Select: Crop tool
|
||||||
* Ctrl+Shift+G: "Render GIF"
|
* Ctrl+Shift+G: "Render GIF"
|
||||||
|
|
||||||
|
|
||||||
* Add Pan and Color Eraser tools to the toolbox
|
|
||||||
|
|
||||||
|
|
||||||
### Tools
|
### Tools
|
||||||
|
|
||||||
* Free-Form Select
|
* Free-Form Select
|
||||||
|
|
|
@ -17,6 +17,10 @@
|
||||||
<body>
|
<body>
|
||||||
<script src="lib/jquery.min.js"></script>
|
<script src="lib/jquery.min.js"></script>
|
||||||
<script src="lib/pep.js"></script>
|
<script src="lib/pep.js"></script>
|
||||||
|
<script>
|
||||||
|
$.event.props.push("button", "buttons", "clientX", "clientY", "offsetX", "offsetY", "pageX", "pageY", "screenX", "screenY", "toElement");
|
||||||
|
$.event.props.push("pointerType", "pointerId", "width", "height", "pressure", "tiltX", "tiltY", "hwTimestamp", "isPrimary");
|
||||||
|
</script>
|
||||||
<script src="lib/canvas.toBlob.js"></script>
|
<script src="lib/canvas.toBlob.js"></script>
|
||||||
<script src="lib/gif.js/gif.js"></script>
|
<script src="lib/gif.js/gif.js"></script>
|
||||||
<script src="lib/palette.js"></script>
|
<script src="lib/palette.js"></script>
|
||||||
|
|
|
@ -63,6 +63,13 @@ html, body, .jspaint {
|
||||||
display: none !important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.jspaint-component-area,
|
||||||
|
.jspaint-menus {
|
||||||
|
-webkit-user-select: none;
|
||||||
|
-moz-user-select: none;
|
||||||
|
-ms-user-select: none;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
.jspaint-status-area,
|
.jspaint-status-area,
|
||||||
.jspaint-component-area,
|
.jspaint-component-area,
|
||||||
.jspaint-menus {
|
.jspaint-menus {
|
||||||
|
|
|
@ -32,6 +32,13 @@ function $ColorBox(){
|
||||||
$current_colors.css({background: colors.ternary});
|
$current_colors.css({background: colors.ternary});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$current_colors.on("pointerdown", function(){
|
||||||
|
var new_bg = colors.foreground;
|
||||||
|
colors.foreground = colors.background;
|
||||||
|
colors.background = new_bg;
|
||||||
|
$G.triggerHandler("option-changed");
|
||||||
|
});
|
||||||
|
|
||||||
// the only color editted by Colors > Edit Colors...
|
// the only color editted by Colors > Edit Colors...
|
||||||
var $last_fg_color_button;
|
var $last_fg_color_button;
|
||||||
var build_palette = function(){
|
var build_palette = function(){
|
||||||
|
@ -60,7 +67,7 @@ function $ColorBox(){
|
||||||
$i.val(rgb2hex($b.css("background-color")));
|
$i.val(rgb2hex($b.css("background-color")));
|
||||||
|
|
||||||
var button, ctrl;
|
var button, ctrl;
|
||||||
$b.on("mousedown", function(e){
|
$b.on("pointerdown", function(e){
|
||||||
ctrl = e.ctrlKey;
|
ctrl = e.ctrlKey;
|
||||||
button = e.button;
|
button = e.button;
|
||||||
if(button === 0){
|
if(button === 0){
|
||||||
|
@ -76,7 +83,7 @@ function $ColorBox(){
|
||||||
$i.prop("enabled", false);
|
$i.prop("enabled", false);
|
||||||
}, 400);
|
}, 400);
|
||||||
});
|
});
|
||||||
$i.on("mousedown", function(e){
|
$i.on("pointerdown", function(e){
|
||||||
if(e.button === button && $i.prop("enabled")){
|
if(e.button === button && $i.prop("enabled")){
|
||||||
$i.trigger("click", "synthetic");
|
$i.trigger("click", "synthetic");
|
||||||
}
|
}
|
||||||
|
@ -117,7 +124,7 @@ function $ColorBox(){
|
||||||
$c.edit_last_color = function(){
|
$c.edit_last_color = function(){
|
||||||
// Edit the last color cell that's been selected as the foreground color.
|
// Edit the last color cell that's been selected as the foreground color.
|
||||||
$input.click().one("change", function(){
|
$input.click().one("change", function(){
|
||||||
$last_fg_color_button.trigger({type: "mousedown", ctrlKey: false, button: 0});
|
$last_fg_color_button.trigger({type: "pointerdown", ctrlKey: false, button: 0});
|
||||||
$last_fg_color_button.find("input").val($input.val()).triggerHandler("change");
|
$last_fg_color_button.find("input").val($input.val()).triggerHandler("change");
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
@ -59,15 +59,15 @@ function $Component(name, orientation, $el){
|
||||||
var $last_docked_to;
|
var $last_docked_to;
|
||||||
var $dock_to;
|
var $dock_to;
|
||||||
var $ghost;
|
var $ghost;
|
||||||
$c.on("mousedown", function(e){
|
$c.on("pointerdown", function(e){
|
||||||
// Only start a drag via a left click directly on the component element
|
// Only start a drag via a left click directly on the component element
|
||||||
if(e.button !== 0){ return; }
|
if(e.button !== 0){ return; }
|
||||||
if(!$c.is(e.target)){ return; }
|
if(!$c.is(e.target)){ return; }
|
||||||
|
|
||||||
$G.on("mousemove", drag_onmousemove);
|
$G.on("pointermove", drag_onpointermove);
|
||||||
$G.one("mouseup", function(e){
|
$G.one("pointerup", function(e){
|
||||||
$G.off("mousemove", drag_onmousemove);
|
$G.off("pointermove", drag_onpointermove);
|
||||||
drag_onmouseup(e);
|
drag_onpointerup(e);
|
||||||
});
|
});
|
||||||
|
|
||||||
var rect = $c[0].getBoundingClientRect();
|
var rect = $c[0].getBoundingClientRect();
|
||||||
|
@ -93,7 +93,7 @@ function $Component(name, orientation, $el){
|
||||||
// Prevent text selection anywhere within the component
|
// Prevent text selection anywhere within the component
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
});
|
});
|
||||||
var drag_onmousemove = function(e){
|
var drag_onpointermove = function(e){
|
||||||
|
|
||||||
$ghost.css({
|
$ghost.css({
|
||||||
left: e.clientX + ox,
|
left: e.clientX + ox,
|
||||||
|
@ -134,7 +134,7 @@ function $Component(name, orientation, $el){
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
};
|
};
|
||||||
|
|
||||||
var drag_onmouseup = function(e){
|
var drag_onpointerup = function(e){
|
||||||
|
|
||||||
$w.hide();
|
$w.hide();
|
||||||
|
|
||||||
|
|
|
@ -69,14 +69,14 @@ function $Handles($container, element, options){
|
||||||
height: magnification * height,
|
height: magnification * height,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
$h.on("mousedown", function(e){
|
$h.on("pointerdown", function(e){
|
||||||
dragged = false;
|
dragged = false;
|
||||||
if(e.button === 0){
|
if(e.button === 0){
|
||||||
$G.on("mousemove", drag);
|
$G.on("pointermove", drag);
|
||||||
$("body").css({cursor: cursor}).addClass("jspaint-cursor-bully");
|
$("body").css({cursor: cursor}).addClass("jspaint-cursor-bully");
|
||||||
}
|
}
|
||||||
$G.one("mouseup", function(e){
|
$G.one("pointerup", function(e){
|
||||||
$G.off("mousemove", drag);
|
$G.off("pointermove", drag);
|
||||||
$("body").css({cursor: ""}).removeClass("jspaint-cursor-bully");
|
$("body").css({cursor: ""}).removeClass("jspaint-cursor-bully");
|
||||||
|
|
||||||
$resize_ghost.remove();
|
$resize_ghost.remove();
|
||||||
|
@ -86,7 +86,7 @@ function $Handles($container, element, options){
|
||||||
$container.trigger("update");
|
$container.trigger("update");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
$h.on("mousedown selectstart", function(e){
|
$h.on("pointerdown selectstart", function(e){
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
});
|
});
|
||||||
|
|
|
@ -5,7 +5,7 @@ function $ToolBox(){
|
||||||
var $tool_options = $(E("div")).addClass("jspaint-tool-options");
|
var $tool_options = $(E("div")).addClass("jspaint-tool-options");
|
||||||
|
|
||||||
var showing_tooltips = false;
|
var showing_tooltips = false;
|
||||||
$tools.on("mouseleave", function(){
|
$tools.on("pointerleave", function(){
|
||||||
showing_tooltips = false;
|
showing_tooltips = false;
|
||||||
$status_text.default();
|
$status_text.default();
|
||||||
});
|
});
|
||||||
|
@ -44,7 +44,7 @@ function $ToolBox(){
|
||||||
$c.update_selected_tool();
|
$c.update_selected_tool();
|
||||||
});
|
});
|
||||||
|
|
||||||
$b.on("mouseenter", function(){
|
$b.on("pointerenter", function(){
|
||||||
var show_tooltip = function(){
|
var show_tooltip = function(){
|
||||||
showing_tooltips = true;
|
showing_tooltips = true;
|
||||||
$status_text.text(tool.description);
|
$status_text.text(tool.description);
|
||||||
|
@ -53,7 +53,7 @@ function $ToolBox(){
|
||||||
show_tooltip();
|
show_tooltip();
|
||||||
}else{
|
}else{
|
||||||
var tid = setTimeout(show_tooltip, 300);
|
var tid = setTimeout(show_tooltip, 300);
|
||||||
$b.on("mouseleave", function(){
|
$b.on("pointerleave", function(){
|
||||||
clearTimeout(tid);
|
clearTimeout(tid);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,8 @@ function $Window($component){
|
||||||
});
|
});
|
||||||
$w.$x.on("mousedown", function(e){
|
$w.$x.on("mousedown", function(e){
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
});
|
||||||
|
$w.$x.on("pointerdown", function(e){
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -26,7 +28,7 @@ function $Window($component){
|
||||||
position: "absolute",
|
position: "absolute",
|
||||||
zIndex: $Window.Z_INDEX++
|
zIndex: $Window.Z_INDEX++
|
||||||
});
|
});
|
||||||
$w.on("mousedown", function(){
|
$w.on("pointerdown", function(){
|
||||||
$w.css({
|
$w.css({
|
||||||
zIndex: $Window.Z_INDEX++
|
zIndex: $Window.Z_INDEX++
|
||||||
});
|
});
|
||||||
|
@ -118,13 +120,13 @@ function $Window($component){
|
||||||
top: e.clientY - my,
|
top: e.clientY - my,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
$w.$titlebar.on("mousedown", function(e){
|
$w.$titlebar.on("pointerdown", function(e){
|
||||||
mx = e.clientX - $w[0].getBoundingClientRect().left;
|
mx = e.clientX - $w[0].getBoundingClientRect().left;
|
||||||
my = e.clientY - $w[0].getBoundingClientRect().top;
|
my = e.clientY - $w[0].getBoundingClientRect().top;
|
||||||
$G.on("mousemove", drag);
|
$G.on("pointermove", drag);
|
||||||
});
|
});
|
||||||
$G.on("mouseup", function(e){
|
$G.on("pointerup", function(e){
|
||||||
$G.off("mousemove", drag);
|
$G.off("pointermove", drag);
|
||||||
});
|
});
|
||||||
$w.$titlebar.on("dblclick", function(e){
|
$w.$titlebar.on("dblclick", function(e){
|
||||||
if($component){
|
if($component){
|
||||||
|
@ -195,7 +197,7 @@ function $FormWindow(title){
|
||||||
// this should really not be needed @TODO
|
// this should really not be needed @TODO
|
||||||
$b.addClass("jspaint-button jspaint-dialogue-button");
|
$b.addClass("jspaint-button jspaint-dialogue-button");
|
||||||
|
|
||||||
$b.on("mousedown", function(){
|
$b.on("pointerdown", function(){
|
||||||
$b.focus();
|
$b.focus();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
var close_menus = function(){
|
var close_menus = function(){
|
||||||
|
// console.log("close menus");
|
||||||
$menus.find(".jspaint-menu-button").trigger("release");
|
$menus.find(".jspaint-menu-button").trigger("release");
|
||||||
// Close any rogue floating submenus
|
// Close any rogue floating submenus
|
||||||
$(".jspaint-menu-popup").hide();
|
$(".jspaint-menu-popup").hide();
|
||||||
|
@ -58,7 +59,7 @@
|
||||||
$checkbox_area.text(item.checkbox.check() ? "✓" : "");
|
$checkbox_area.text(item.checkbox.check() ? "✓" : "");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
$item.on("mouseover", function(){
|
$item.on("pointerover", function(){
|
||||||
$menu_popup.triggerHandler("update");
|
$menu_popup.triggerHandler("update");
|
||||||
$item.focus();
|
$item.focus();
|
||||||
});
|
});
|
||||||
|
@ -84,26 +85,29 @@
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
var open_tid, close_tid;
|
var open_tid, close_tid;
|
||||||
$item.add($submenu_popup).on("mouseover", function(e){
|
$item.add($submenu_popup).on("pointerover", function(e){
|
||||||
if(open_tid){clearTimeout(open_tid);}
|
if(open_tid){clearTimeout(open_tid);}
|
||||||
if(close_tid){clearTimeout(close_tid);}
|
if(close_tid){clearTimeout(close_tid);}
|
||||||
});
|
});
|
||||||
$item.on("mouseover", function(e){
|
$item.on("pointerover", function(e){
|
||||||
if(open_tid){clearTimeout(open_tid);}
|
if(open_tid){clearTimeout(open_tid);}
|
||||||
if(close_tid){clearTimeout(close_tid);}
|
if(close_tid){clearTimeout(close_tid);}
|
||||||
open_tid = setTimeout(open_submenu, 200);
|
open_tid = setTimeout(open_submenu, 200);
|
||||||
});
|
});
|
||||||
$item.add($submenu_popup).on("mouseout", function(){
|
$item.add($submenu_popup).on("pointerout", function(){
|
||||||
if(open_tid){clearTimeout(open_tid);}
|
if(open_tid){clearTimeout(open_tid);}
|
||||||
if(close_tid){clearTimeout(close_tid);}
|
if(close_tid){clearTimeout(close_tid);}
|
||||||
close_tid = setTimeout(function(){
|
close_tid = setTimeout(function(){
|
||||||
$submenu_popup.hide();
|
$submenu_popup.hide();
|
||||||
}, 200);
|
}, 200);
|
||||||
});
|
});
|
||||||
$item.on("mousedown click", open_submenu);
|
$item.on("click pointerdown", open_submenu);
|
||||||
}
|
}
|
||||||
|
|
||||||
$item.on("click", function(){
|
$item.on("pointerup", function(e){
|
||||||
|
if(e.pointerType === "mouse" && e.button !== 0){
|
||||||
|
return;
|
||||||
|
}
|
||||||
if(item.checkbox){
|
if(item.checkbox){
|
||||||
if(item.checkbox.toggle){
|
if(item.checkbox.toggle){
|
||||||
item.checkbox.toggle();
|
item.checkbox.toggle();
|
||||||
|
@ -114,14 +118,14 @@
|
||||||
item.action();
|
item.action();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
$item.on("mouseenter", function(){
|
$item.on("pointerenter", function(){
|
||||||
if(item.submenu){
|
if(item.submenu){
|
||||||
$status_text.text("");
|
$status_text.text("");
|
||||||
}else{
|
}else{
|
||||||
$status_text.text(item.description || "");
|
$status_text.text(item.description || "");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
$item.on("mouseleave", function(){
|
$item.on("pointerleave", function(){
|
||||||
if($item.is(":visible")){
|
if($item.is(":visible")){
|
||||||
$status_text.text("");
|
$status_text.text("");
|
||||||
}
|
}
|
||||||
|
@ -162,14 +166,11 @@
|
||||||
$menu_popup.hide();
|
$menu_popup.hide();
|
||||||
$menu_button.html(_html(menus_key));
|
$menu_button.html(_html(menus_key));
|
||||||
$menu_button.attr("tabIndex", -1)
|
$menu_button.attr("tabIndex", -1)
|
||||||
$menu_button.on("mousedown", function(){
|
|
||||||
$menu_button.focus();
|
|
||||||
});
|
|
||||||
$menu_container.on("keydown", function(e){
|
$menu_container.on("keydown", function(e){
|
||||||
var $focused_item = $menu_popup.find(".jspaint-menu-item:focus");
|
var $focused_item = $menu_popup.find(".jspaint-menu-item:focus");
|
||||||
switch(e.keyCode){
|
switch(e.keyCode){
|
||||||
case 37: // Left
|
case 37: // Left
|
||||||
$menu_container.prev().find(".jspaint-menu-button").trigger("mousedown");
|
$menu_container.prev().find(".jspaint-menu-button").trigger("pointerdown");
|
||||||
break;
|
break;
|
||||||
case 39: // Right
|
case 39: // Right
|
||||||
if($focused_item.find(".jspaint-menu-item-submenu-area:not(:empty)").length){
|
if($focused_item.find(".jspaint-menu-item-submenu-area:not(:empty)").length){
|
||||||
|
@ -177,7 +178,7 @@
|
||||||
$(".jspaint-menu-popup .jspaint-menu-item").first().focus();
|
$(".jspaint-menu-popup .jspaint-menu-item").first().focus();
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
}else{
|
}else{
|
||||||
$menu_container.next().find(".jspaint-menu-button").trigger("mousedown");
|
$menu_container.next().find(".jspaint-menu-button").trigger("pointerdown");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 40: // Down
|
case 40: // Down
|
||||||
|
@ -188,7 +189,7 @@
|
||||||
}
|
}
|
||||||
$next.focus();
|
$next.focus();
|
||||||
}else{
|
}else{
|
||||||
$menu_button.mousedown();
|
$menu_button.pointerdown();
|
||||||
$menu_popup.find(".jspaint-menu-item").first().focus();
|
$menu_popup.find(".jspaint-menu-item").first().focus();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -200,7 +201,7 @@
|
||||||
}
|
}
|
||||||
$prev.focus();
|
$prev.focus();
|
||||||
}else{
|
}else{
|
||||||
$menu_button.mousedown(); // or maybe do nothing?
|
$menu_button.pointerdown(); // or maybe do nothing?
|
||||||
$menu_popup.find(".jspaint-menu-item").last().focus();
|
$menu_popup.find(".jspaint-menu-item").last().focus();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -216,21 +217,20 @@
|
||||||
if(e.altKey){
|
if(e.altKey){
|
||||||
if(String.fromCharCode(e.keyCode) === _hotkey(menus_key)){
|
if(String.fromCharCode(e.keyCode) === _hotkey(menus_key)){
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
$menu_button.mousedown();
|
$menu_button.pointerdown();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
$menu_button.on("mousedown mousemove", function(e){
|
$menu_button.on("pointerdown pointerenter", function(e){
|
||||||
if(e.type === "mousemove" && !selecting_menus){
|
if(e.type === "pointerenter" && !selecting_menus){
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(e.type === "mousedown"){
|
if(!$menu_button.hasClass("active")){
|
||||||
if(!$menu_button.hasClass("active")){
|
this_click_opened_the_menu = true;
|
||||||
this_click_opened_the_menu = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
close_menus();
|
close_menus();
|
||||||
|
// console.log("open menu");
|
||||||
|
|
||||||
$menu_button.focus();
|
$menu_button.focus();
|
||||||
$menu_button.addClass("active");
|
$menu_button.addClass("active");
|
||||||
|
@ -241,12 +241,13 @@
|
||||||
|
|
||||||
$status_text.text("");
|
$status_text.text("");
|
||||||
});
|
});
|
||||||
$menu_button.on("mouseup", function(e){
|
$menu_button.on("pointerup", function(e){
|
||||||
if(this_click_opened_the_menu){
|
if(this_click_opened_the_menu){
|
||||||
this_click_opened_the_menu = false;
|
this_click_opened_the_menu = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if($menu_button.hasClass("active")){
|
if($menu_button.hasClass("active")){
|
||||||
|
// console.log(e.type, "occurred and this click didn't open the menu, so...");
|
||||||
close_menus();
|
close_menus();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -264,9 +265,13 @@
|
||||||
close_menus();
|
close_menus();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
$G.on("blur", close_menus);
|
$G.on("blur", function(e){
|
||||||
$G.on("mousedown mouseup", function(e){
|
// console.log("blur", e.target, document.activeElement);
|
||||||
|
close_menus();
|
||||||
|
});
|
||||||
|
$G.on("pointerdown pointerup", function(e){
|
||||||
if($(e.target).closest(".jspaint-menus, .jspaint-menu-popup").length === 0){
|
if($(e.target).closest(".jspaint-menus, .jspaint-menu-popup").length === 0){
|
||||||
|
// console.log(e.type, "occurred outside of menus (on ", e.target, ") so...");
|
||||||
close_menus();
|
close_menus();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -60,7 +60,7 @@ Selection.prototype.instantiate = function(_img, _passive){
|
||||||
});
|
});
|
||||||
|
|
||||||
var mox, moy;
|
var mox, moy;
|
||||||
var mousemove = function(e){
|
var pointermove = function(e){
|
||||||
var m = e2c(e);
|
var m = e2c(e);
|
||||||
sel._x = Math.max(Math.min(m.x - mox, canvas.width), -sel._w);
|
sel._x = Math.max(Math.min(m.x - mox, canvas.width), -sel._w);
|
||||||
sel._y = Math.max(Math.min(m.y - moy, canvas.height), -sel._h);
|
sel._y = Math.max(Math.min(m.y - moy, canvas.height), -sel._h);
|
||||||
|
@ -71,7 +71,7 @@ Selection.prototype.instantiate = function(_img, _passive){
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
sel.canvas_mousedown = function(e){
|
sel.canvas_pointerdown = function(e){
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
var rect = sel.canvas.getBoundingClientRect();
|
var rect = sel.canvas.getBoundingClientRect();
|
||||||
|
@ -80,9 +80,9 @@ Selection.prototype.instantiate = function(_img, _passive){
|
||||||
mox = ~~(cx / rect.width * sel.canvas.width);
|
mox = ~~(cx / rect.width * sel.canvas.width);
|
||||||
moy = ~~(cy / rect.height * sel.canvas.height);
|
moy = ~~(cy / rect.height * sel.canvas.height);
|
||||||
|
|
||||||
$G.on("mousemove", mousemove);
|
$G.on("pointermove", pointermove);
|
||||||
$G.one("mouseup", function(){
|
$G.one("pointerup", function(){
|
||||||
$G.off("mousemove", mousemove);
|
$G.off("pointermove", pointermove);
|
||||||
});
|
});
|
||||||
|
|
||||||
if(e.shiftKey){
|
if(e.shiftKey){
|
||||||
|
@ -90,7 +90,7 @@ Selection.prototype.instantiate = function(_img, _passive){
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
$(sel.canvas).on("mousedown", sel.canvas_mousedown);
|
$(sel.canvas).on("pointerdown", sel.canvas_pointerdown);
|
||||||
$canvas_area.trigger("resize");
|
$canvas_area.trigger("resize");
|
||||||
$status_position.text("");
|
$status_position.text("");
|
||||||
$status_size.text("");
|
$status_size.text("");
|
||||||
|
@ -157,7 +157,7 @@ Selection.prototype.replace_canvas = function(new_canvas){
|
||||||
$(sel.canvas).replaceWith(new_canvas);
|
$(sel.canvas).replaceWith(new_canvas);
|
||||||
sel.canvas = new_canvas;
|
sel.canvas = new_canvas;
|
||||||
|
|
||||||
$(sel.canvas).on("mousedown", sel.canvas_mousedown);
|
$(sel.canvas).on("pointerdown", sel.canvas_pointerdown);
|
||||||
sel.$ghost.triggerHandler("new-element", [sel.canvas]);
|
sel.$ghost.triggerHandler("new-element", [sel.canvas]);
|
||||||
sel.$ghost.triggerHandler("resize");//?
|
sel.$ghost.triggerHandler("resize");//?
|
||||||
};
|
};
|
||||||
|
|
|
@ -13,7 +13,7 @@ function TextBox(x, y, w, h){
|
||||||
|
|
||||||
tb.$ghost = $(E("div")).addClass("jspaint-textbox").appendTo($canvas_area);
|
tb.$ghost = $(E("div")).addClass("jspaint-textbox").appendTo($canvas_area);
|
||||||
tb.$editor = $(E("textarea")).addClass("jspaint-textbox-editor");
|
tb.$editor = $(E("textarea")).addClass("jspaint-textbox-editor");
|
||||||
tb.$editor.on("mousedown dragover dragenter drop contextmenu", function(e){
|
tb.$editor.on("pointerdown dragover dragenter drop contextmenu", function(e){
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -100,7 +100,7 @@ TextBox.prototype.instantiate = function(){
|
||||||
});
|
});
|
||||||
|
|
||||||
var mox, moy;
|
var mox, moy;
|
||||||
var mousemove = function(e){
|
var pointermove = function(e){
|
||||||
var m = e2c(e);
|
var m = e2c(e);
|
||||||
tb._x = Math.max(Math.min(m.x - mox, canvas.width), -tb._w);
|
tb._x = Math.max(Math.min(m.x - mox, canvas.width), -tb._w);
|
||||||
tb._y = Math.max(Math.min(m.y - moy, canvas.height), -tb._h);
|
tb._y = Math.max(Math.min(m.y - moy, canvas.height), -tb._h);
|
||||||
|
@ -110,7 +110,7 @@ TextBox.prototype.instantiate = function(){
|
||||||
tb.draw();
|
tb.draw();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
tb.$ghost.on("mousedown", function(e){
|
tb.$ghost.on("pointerdown", function(e){
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
var rect = tb.$ghost[0].getBoundingClientRect();
|
var rect = tb.$ghost[0].getBoundingClientRect();
|
||||||
|
@ -119,9 +119,9 @@ TextBox.prototype.instantiate = function(){
|
||||||
mox = ~~(cx);
|
mox = ~~(cx);
|
||||||
moy = ~~(cy);
|
moy = ~~(cy);
|
||||||
|
|
||||||
$G.on("mousemove", mousemove);
|
$G.on("pointermove", pointermove);
|
||||||
$G.one("mouseup", function(){
|
$G.one("pointerup", function(){
|
||||||
$G.off("mousemove", mousemove);
|
$G.off("pointermove", pointermove);
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
97
src/app.js
97
src/app.js
|
@ -62,6 +62,7 @@ var $canvas_area = $(E("div")).addClass("jspaint-canvas-area").appendTo($H);
|
||||||
var canvas = new Canvas();
|
var canvas = new Canvas();
|
||||||
var ctx = canvas.ctx;
|
var ctx = canvas.ctx;
|
||||||
var $canvas = $(canvas).appendTo($canvas_area);
|
var $canvas = $(canvas).appendTo($canvas_area);
|
||||||
|
$canvas.attr("touch-action", "none");
|
||||||
|
|
||||||
var $canvas_handles = $Handles($canvas_area, canvas, {outset: 4, offset: 4, size_only: true});
|
var $canvas_handles = $Handles($canvas_area, canvas, {outset: 4, offset: 4, size_only: true});
|
||||||
|
|
||||||
|
@ -344,7 +345,7 @@ $G.on("cut copy paste", function(e){
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
var mouse, mouse_start, mouse_previous;
|
var pointer, pointer_start, pointer_previous;
|
||||||
var reverse, ctrl, button;
|
var reverse, ctrl, button;
|
||||||
function e2c(e){
|
function e2c(e){
|
||||||
var rect = canvas.getBoundingClientRect();
|
var rect = canvas.getBoundingClientRect();
|
||||||
|
@ -392,75 +393,75 @@ function tool_go(event_name){
|
||||||
ctx.strokeStyle = stroke_color = colors[stroke_color_k];
|
ctx.strokeStyle = stroke_color = colors[stroke_color_k];
|
||||||
}
|
}
|
||||||
if(selected_tool.shape){
|
if(selected_tool.shape){
|
||||||
selected_tool.shape(ctx, mouse_start.x, mouse_start.y, mouse.x-mouse_start.x, mouse.y-mouse_start.y);
|
selected_tool.shape(ctx, pointer_start.x, pointer_start.y, pointer.x-pointer_start.x, pointer.y-pointer_start.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(selected_tool[event_name]){
|
if(selected_tool[event_name]){
|
||||||
selected_tool[event_name](ctx, mouse.x, mouse.y);
|
selected_tool[event_name](ctx, pointer.x, pointer.y);
|
||||||
}
|
}
|
||||||
if(selected_tool.paint){
|
if(selected_tool.paint){
|
||||||
if(selected_tool.continuous === "space"){
|
if(selected_tool.continuous === "space"){
|
||||||
var ham = brush_shape.match(/diagonal/) ? brosandham_line : bresenham_line;
|
var ham = brush_shape.match(/diagonal/) ? brosandham_line : bresenham_line;
|
||||||
ham(mouse_previous.x, mouse_previous.y, mouse.x, mouse.y, function(x, y){
|
ham(pointer_previous.x, pointer_previous.y, pointer.x, pointer.y, function(x, y){
|
||||||
selected_tool.paint(ctx, x, y);
|
selected_tool.paint(ctx, x, y);
|
||||||
});
|
});
|
||||||
}else{
|
}else{
|
||||||
selected_tool.paint(ctx, mouse.x, mouse.y);
|
selected_tool.paint(ctx, pointer.x, pointer.y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function canvas_mouse_move(e){
|
function canvas_pointer_move(e){
|
||||||
ctrl = e.ctrlKey;
|
ctrl = e.ctrlKey;
|
||||||
mouse = e2c(e);
|
pointer = e2c(e);
|
||||||
if(e.shiftKey){
|
if(e.shiftKey){
|
||||||
if(selected_tool.name.match(/Line|Curve/)){
|
if(selected_tool.name.match(/Line|Curve/)){
|
||||||
var dist = Math.sqrt(
|
var dist = Math.sqrt(
|
||||||
(mouse.y - mouse_start.y) * (mouse.y - mouse_start.y) +
|
(pointer.y - pointer_start.y) * (pointer.y - pointer_start.y) +
|
||||||
(mouse.x - mouse_start.x) * (mouse.x - mouse_start.x)
|
(pointer.x - pointer_start.x) * (pointer.x - pointer_start.x)
|
||||||
);
|
);
|
||||||
var octurn = (TAU / 8);
|
var octurn = (TAU / 8);
|
||||||
var dir08 = Math.atan2(mouse.y - mouse_start.y, mouse.x - mouse_start.x) / octurn;
|
var dir08 = Math.atan2(pointer.y - pointer_start.y, pointer.x - pointer_start.x) / octurn;
|
||||||
var dir = Math.round(dir08) * octurn;
|
var dir = Math.round(dir08) * octurn;
|
||||||
mouse.x = Math.round(mouse_start.x + Math.cos(dir) * dist);
|
pointer.x = Math.round(pointer_start.x + Math.cos(dir) * dist);
|
||||||
mouse.y = Math.round(mouse_start.y + Math.sin(dir) * dist);
|
pointer.y = Math.round(pointer_start.y + Math.sin(dir) * dist);
|
||||||
}else if(selected_tool.shape){
|
}else if(selected_tool.shape){
|
||||||
var w = Math.abs(mouse.x - mouse_start.x);
|
var w = Math.abs(pointer.x - pointer_start.x);
|
||||||
var h = Math.abs(mouse.y - mouse_start.y);
|
var h = Math.abs(pointer.y - pointer_start.y);
|
||||||
if(w < h){
|
if(w < h){
|
||||||
if(mouse.y > mouse_start.y){
|
if(pointer.y > pointer_start.y){
|
||||||
mouse.y = mouse_start.y + w;
|
pointer.y = pointer_start.y + w;
|
||||||
}else{
|
}else{
|
||||||
mouse.y = mouse_start.y - w;
|
pointer.y = pointer_start.y - w;
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
if(mouse.x > mouse_start.x){
|
if(pointer.x > pointer_start.x){
|
||||||
mouse.x = mouse_start.x + h;
|
pointer.x = pointer_start.x + h;
|
||||||
}else{
|
}else{
|
||||||
mouse.x = mouse_start.x - h;
|
pointer.x = pointer_start.x - h;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tool_go();
|
tool_go();
|
||||||
mouse_previous = mouse;
|
pointer_previous = pointer;
|
||||||
}
|
}
|
||||||
$canvas.on("mousemove", function(e){
|
$canvas.on("pointermove", function(e){
|
||||||
mouse = e2c(e);
|
pointer = e2c(e);
|
||||||
$status_position.text(mouse.x + "," + mouse.y);
|
$status_position.text(pointer.x + "," + pointer.y);
|
||||||
});
|
});
|
||||||
$canvas.on("mouseleave", function(e){
|
$canvas.on("pointerleave", function(e){
|
||||||
$status_position.text("");
|
$status_position.text("");
|
||||||
});
|
});
|
||||||
|
|
||||||
var mouse_was_pressed = false;
|
var pointer_was_pressed = false;
|
||||||
$canvas.on("mousedown", function(e){
|
$canvas.on("pointerdown", function(e){
|
||||||
if(mouse_was_pressed && (reverse ? (button === 2) : (button === 0))){
|
if(pointer_was_pressed && (reverse ? (button === 2) : (button === 0))){
|
||||||
mouse_was_pressed = false;
|
pointer_was_pressed = false;
|
||||||
return cancel();
|
return cancel();
|
||||||
}
|
}
|
||||||
mouse_was_pressed = true;
|
pointer_was_pressed = true;
|
||||||
$G.one("mouseup", function(e){
|
$G.one("pointerup", function(e){
|
||||||
mouse_was_pressed = false;
|
pointer_was_pressed = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
if(e.button === 0){
|
if(e.button === 0){
|
||||||
|
@ -472,32 +473,30 @@ $canvas.on("mousedown", function(e){
|
||||||
}
|
}
|
||||||
button = e.button;
|
button = e.button;
|
||||||
ctrl = e.ctrlKey;
|
ctrl = e.ctrlKey;
|
||||||
mouse_start = mouse_previous = mouse = e2c(e);
|
pointer_start = pointer_previous = pointer = e2c(e);
|
||||||
|
|
||||||
var mousedown_action = function(){
|
var pointerdown_action = function(){
|
||||||
if(selected_tool.paint || selected_tool.mousedown){
|
if(selected_tool.paint || selected_tool.pointerdown){
|
||||||
tool_go("mousedown");
|
tool_go("pointerdown");
|
||||||
}
|
}
|
||||||
|
|
||||||
$G.on("mousemove", canvas_mouse_move);
|
$G.on("pointermove", canvas_pointer_move);
|
||||||
if(selected_tool.continuous === "time"){
|
if(selected_tool.continuous === "time"){
|
||||||
var iid = setInterval(function(){
|
var iid = setInterval(tool_go, 5);
|
||||||
tool_go();
|
|
||||||
}, 5);
|
|
||||||
}
|
}
|
||||||
$G.one("mouseup", function(e, canceling){
|
$G.one("pointerup", function(e, canceling){
|
||||||
button = undefined;
|
button = undefined;
|
||||||
if(canceling){
|
if(canceling){
|
||||||
selected_tool.cancel && selected_tool.cancel();
|
selected_tool.cancel && selected_tool.cancel();
|
||||||
}else{
|
}else{
|
||||||
mouse = e2c(e);
|
pointer = e2c(e);
|
||||||
selected_tool.mouseup && selected_tool.mouseup(ctx, mouse.x, mouse.y);
|
selected_tool.pointerup && selected_tool.pointerup(ctx, pointer.x, pointer.y);
|
||||||
}
|
}
|
||||||
if(selected_tool.deselect){
|
if(selected_tool.deselect){
|
||||||
selected_tool = previous_tool;
|
selected_tool = previous_tool;
|
||||||
$toolbox && $toolbox.update_selected_tool();
|
$toolbox && $toolbox.update_selected_tool();
|
||||||
}
|
}
|
||||||
$G.off("mousemove", canvas_mouse_move);
|
$G.off("pointermove", canvas_pointer_move);
|
||||||
if(iid){
|
if(iid){
|
||||||
clearInterval(iid);
|
clearInterval(iid);
|
||||||
}
|
}
|
||||||
|
@ -509,13 +508,13 @@ $canvas.on("mousedown", function(e){
|
||||||
// (Or in OOPLiE, `If the selected tool is passive`)
|
// (Or in OOPLiE, `If the selected tool is passive`)
|
||||||
// Or it could use a getter
|
// Or it could use a getter
|
||||||
if((typeof selected_tool.passive === "function") ? selected_tool.passive() : selected_tool.passive){
|
if((typeof selected_tool.passive === "function") ? selected_tool.passive() : selected_tool.passive){
|
||||||
mousedown_action();
|
pointerdown_action();
|
||||||
}else{
|
}else{
|
||||||
undoable(mousedown_action);
|
undoable(pointerdown_action);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$canvas_area.on("mousedown", function(e){
|
$canvas_area.on("pointerdown", function(e){
|
||||||
if(e.button === 0){
|
if(e.button === 0){
|
||||||
if($canvas_area.is(e.target)){
|
if($canvas_area.is(e.target)){
|
||||||
if(selection){
|
if(selection){
|
||||||
|
@ -525,7 +524,7 @@ $canvas_area.on("mousedown", function(e){
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$("body").on("mousedown contextmenu", function(e){
|
$("body").on("mousedown selectstart contextmenu", function(e){
|
||||||
if(
|
if(
|
||||||
e.target instanceof HTMLSelectElement ||
|
e.target instanceof HTMLSelectElement ||
|
||||||
e.target instanceof HTMLTextAreaElement ||
|
e.target instanceof HTMLTextAreaElement ||
|
||||||
|
@ -539,5 +538,5 @@ $("body").on("mousedown contextmenu", function(e){
|
||||||
|
|
||||||
// Stop drawing (or dragging or whatver) if you Alt+Tab or whatever
|
// Stop drawing (or dragging or whatver) if you Alt+Tab or whatever
|
||||||
$G.on("blur", function(e){
|
$G.on("blur", function(e){
|
||||||
$G.triggerHandler("mouseup");
|
$G.triggerHandler("pointerup");
|
||||||
});
|
});
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
|
|
||||||
$canvas.on("user-resized.ugly-hook", may_be_changed);
|
$canvas.on("user-resized.ugly-hook", may_be_changed);
|
||||||
|
|
||||||
$canvas_area.on("mousedown.ugly-hook", "*", function(e, synthetic){
|
$canvas_area.on("pointerdown.ugly-hook", "*", function(e, synthetic){
|
||||||
debug_event(e, synthetic);
|
debug_event(e, synthetic);
|
||||||
if(synthetic){ return; }
|
if(synthetic){ return; }
|
||||||
|
|
||||||
|
@ -28,19 +28,19 @@
|
||||||
may_be_changed();
|
may_be_changed();
|
||||||
}else{
|
}else{
|
||||||
// Changes may occur when you release from a stroke
|
// Changes may occur when you release from a stroke
|
||||||
mouse_operations = [e];
|
pointer_operations = [e];
|
||||||
var mousemove = function(e, synthetic){
|
var pointermove = function(e, synthetic){
|
||||||
debug_event(e, synthetic);
|
debug_event(e, synthetic);
|
||||||
if(synthetic){ return; }
|
if(synthetic){ return; }
|
||||||
|
|
||||||
mouse_operations.push(e);
|
pointer_operations.push(e);
|
||||||
};
|
};
|
||||||
$G.on("mousemove.ugly-hook", mousemove);
|
$G.on("pointermove.ugly-hook", pointermove);
|
||||||
$G.one("mouseup.ugly-hook", function(e, synthetic){
|
$G.one("pointerup.ugly-hook", function(e, synthetic){
|
||||||
debug_event(e, synthetic);
|
debug_event(e, synthetic);
|
||||||
if(synthetic){ return; }
|
if(synthetic){ return; }
|
||||||
|
|
||||||
$G.off("mousemove.ugly-hook", mousemove);
|
$G.off("pointermove.ugly-hook", pointermove);
|
||||||
|
|
||||||
may_be_changed();
|
may_be_changed();
|
||||||
});
|
});
|
||||||
|
|
|
@ -429,12 +429,12 @@ function redo(){
|
||||||
}
|
}
|
||||||
function cancel(){
|
function cancel(){
|
||||||
if(!selected_tool.passive){ undo(); }
|
if(!selected_tool.passive){ undo(); }
|
||||||
$G.triggerHandler("mouseup", "cancel");
|
$G.triggerHandler("pointerup", "cancel");
|
||||||
}
|
}
|
||||||
function this_ones_a_frame_changer(){
|
function this_ones_a_frame_changer(){
|
||||||
deselect();
|
deselect();
|
||||||
saved = false;
|
saved = false;
|
||||||
$G.triggerHandler("mouseup", "cancel");
|
$G.triggerHandler("pointerup", "cancel");
|
||||||
$G.triggerHandler("session-update");
|
$G.triggerHandler("session-update");
|
||||||
}
|
}
|
||||||
function deselect(){
|
function deselect(){
|
||||||
|
@ -558,7 +558,7 @@ function image_attributes(){
|
||||||
|
|
||||||
$main.find("input")
|
$main.find("input")
|
||||||
.css({width: "40px"})
|
.css({width: "40px"})
|
||||||
.on("change keyup keydown keypress mousedown mousemove paste drop", function(){
|
.on("change keyup keydown keypress pointerdown pointermove paste drop", function(){
|
||||||
if($(this).is($width)){
|
if($(this).is($width)){
|
||||||
width_in_px = $width.val() * unit_sizes_in_px[current_unit];
|
width_in_px = $width.val() * unit_sizes_in_px[current_unit];
|
||||||
}
|
}
|
||||||
|
@ -653,7 +653,7 @@ function image_flip_and_rotate(){
|
||||||
// Select the radio for this field
|
// Select the radio for this field
|
||||||
$label.find("input[type='radio']").prop("checked", true);
|
$label.find("input[type='radio']").prop("checked", true);
|
||||||
});
|
});
|
||||||
// @TODO: enable all controls that are accessable to the mouse
|
// @TODO: enable all controls that are accessable to the pointer
|
||||||
|
|
||||||
$fieldset.find("label").css({display: "block"});
|
$fieldset.find("label").css({display: "block"});
|
||||||
|
|
||||||
|
|
|
@ -145,7 +145,7 @@
|
||||||
var other_user = snap.val();
|
var other_user = snap.val();
|
||||||
|
|
||||||
// @TODO: display other cursor types?
|
// @TODO: display other cursor types?
|
||||||
// @TODO: display mouse button state?
|
// @TODO: display pointer button state?
|
||||||
// @TODO: display selections
|
// @TODO: display selections
|
||||||
|
|
||||||
var cursor_canvas = new Canvas(32, 32);
|
var cursor_canvas = new Canvas(32, 32);
|
||||||
|
@ -204,14 +204,14 @@
|
||||||
});
|
});
|
||||||
|
|
||||||
var previous_uri;
|
var previous_uri;
|
||||||
var mouse_operations = [];
|
var pointer_operations = [];
|
||||||
|
|
||||||
var sync = function(){
|
var sync = function(){
|
||||||
// Sync the data from this client to the server (one-way)
|
// Sync the data from this client to the server (one-way)
|
||||||
var uri = canvas.toDataURL();
|
var uri = canvas.toDataURL();
|
||||||
if(previous_uri !== uri){
|
if(previous_uri !== uri){
|
||||||
debug(["clear mouse operations to set data", mouse_operations]);
|
debug(["clear pointer operations to set data", pointer_operations]);
|
||||||
mouse_operations = [];
|
pointer_operations = [];
|
||||||
debug("set data");
|
debug("set data");
|
||||||
session.fb_data.set(uri);
|
session.fb_data.set(uri);
|
||||||
previous_uri = uri;
|
previous_uri = uri;
|
||||||
|
@ -240,9 +240,9 @@
|
||||||
// Load the new image data
|
// Load the new image data
|
||||||
var img = new Image();
|
var img = new Image();
|
||||||
img.onload = function(){
|
img.onload = function(){
|
||||||
// Cancel any in-progress mouse operations
|
// Cancel any in-progress pointer operations
|
||||||
if(mouse_operations.length){
|
if(pointer_operations.length){
|
||||||
$G.triggerHandler("mouseup", "cancel");
|
$G.triggerHandler("pointerup", "cancel");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write the image data to the canvas
|
// Write the image data to the canvas
|
||||||
|
@ -252,10 +252,10 @@
|
||||||
// Perhaps a better way of syncing transparency
|
// Perhaps a better way of syncing transparency
|
||||||
// and other options will be established)
|
// and other options will be established)
|
||||||
|
|
||||||
// Playback recorded in-progress mouse operations
|
// Playback recorded in-progress pointer operations
|
||||||
console.log("playback", mouse_operations);
|
console.log("playback", pointer_operations);
|
||||||
for(var i=0; i<mouse_operations.length; i++){
|
for(var i=0; i<pointer_operations.length; i++){
|
||||||
var e = mouse_operations[i];
|
var e = pointer_operations[i];
|
||||||
// Trigger the event at each place it is listened for
|
// Trigger the event at each place it is listened for
|
||||||
$canvas.triggerHandler(e, ["synthetic"]);
|
$canvas.triggerHandler(e, ["synthetic"]);
|
||||||
$G.triggerHandler(e, ["synthetic"]);
|
$G.triggerHandler(e, ["synthetic"]);
|
||||||
|
@ -267,7 +267,7 @@
|
||||||
|
|
||||||
// Update the cursor status
|
// Update the cursor status
|
||||||
|
|
||||||
$G.on("mousemove.session-hook", function(e){
|
$G.on("pointermove.session-hook", function(e){
|
||||||
var m = e2c(e);
|
var m = e2c(e);
|
||||||
session.fb_user.child("cursor").update({
|
session.fb_user.child("cursor").update({
|
||||||
x: m.x,
|
x: m.x,
|
||||||
|
@ -282,7 +282,7 @@
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// @FIXME: the cursor can come back from "away" via a mouse event
|
// @FIXME: the cursor can come back from "away" via a pointer event
|
||||||
// while the window is blurred and stay there when the user goes away
|
// while the window is blurred and stay there when the user goes away
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -70,12 +70,12 @@ var $Choose = function(things, display, choose, is_chosen){
|
||||||
$chooser.on("redraw", update);
|
$chooser.on("redraw", update);
|
||||||
$G.on("option-changed", update);
|
$G.on("option-changed", update);
|
||||||
|
|
||||||
$option_container.on("mousedown click", choose_thing);
|
$option_container.on("pointerdown click", choose_thing);
|
||||||
$chooser.on("mousedown", function(){
|
$chooser.on("pointerdown", function(){
|
||||||
$option_container.on("mouseenter", choose_thing);
|
$option_container.on("pointerenter", choose_thing);
|
||||||
});
|
});
|
||||||
$G.on("mouseup", function(){
|
$G.on("pointerup", function(){
|
||||||
$option_container.off("mouseenter", choose_thing);
|
$option_container.off("pointerenter", choose_thing);
|
||||||
});
|
});
|
||||||
|
|
||||||
})(things[i]);
|
})(things[i]);
|
||||||
|
|
144
src/tools.js
144
src/tools.js
|
@ -14,12 +14,12 @@ tools = [{
|
||||||
y_min: +Infinity,
|
y_min: +Infinity,
|
||||||
y_max: -Infinity,
|
y_max: -Infinity,
|
||||||
|
|
||||||
mousedown: function(){
|
pointerdown: function(){
|
||||||
var tool = this;
|
var tool = this;
|
||||||
tool.x_min = mouse.x;
|
tool.x_min = pointer.x;
|
||||||
tool.x_max = mouse.x+1;
|
tool.x_max = pointer.x+1;
|
||||||
tool.y_min = mouse.y;
|
tool.y_min = pointer.y;
|
||||||
tool.y_max = mouse.y+1;
|
tool.y_max = pointer.y+1;
|
||||||
tool.points = [];
|
tool.points = [];
|
||||||
|
|
||||||
if(selection){
|
if(selection){
|
||||||
|
@ -28,26 +28,26 @@ tools = [{
|
||||||
selection = null;
|
selection = null;
|
||||||
}
|
}
|
||||||
// The inverty brush is continuous in space which means
|
// The inverty brush is continuous in space which means
|
||||||
// paint(ctx, x, y) will be called for each pixel the mouse moves
|
// paint(ctx, x, y) will be called for each pixel the pointer moves
|
||||||
// and we only need to record individual mouse events to make the polygon
|
// and we only need to record individual pointer events to make the polygon
|
||||||
var onmousemove = function(e){
|
var onpointermove = function(e){
|
||||||
var mouse = e2c(e);
|
var pointer = e2c(e);
|
||||||
// Constrain the mouse to the canvas
|
// Constrain the pointer to the canvas
|
||||||
mouse.x = Math.min(canvas.width, mouse.x);
|
pointer.x = Math.min(canvas.width, pointer.x);
|
||||||
mouse.x = Math.max(0, mouse.x);
|
pointer.x = Math.max(0, pointer.x);
|
||||||
mouse.y = Math.min(canvas.height, mouse.y);
|
pointer.y = Math.min(canvas.height, pointer.y);
|
||||||
mouse.y = Math.max(0, mouse.y);
|
pointer.y = Math.max(0, pointer.y);
|
||||||
// Add the point
|
// Add the point
|
||||||
tool.points.push(mouse);
|
tool.points.push(pointer);
|
||||||
// Update the boundaries of the polygon
|
// Update the boundaries of the polygon
|
||||||
tool.x_min = Math.min(mouse.x, tool.x_min);
|
tool.x_min = Math.min(pointer.x, tool.x_min);
|
||||||
tool.x_max = Math.max(mouse.x, tool.x_max);
|
tool.x_max = Math.max(pointer.x, tool.x_max);
|
||||||
tool.y_min = Math.min(mouse.y, tool.y_min);
|
tool.y_min = Math.min(pointer.y, tool.y_min);
|
||||||
tool.y_max = Math.max(mouse.y, tool.y_max);
|
tool.y_max = Math.max(pointer.y, tool.y_max);
|
||||||
};
|
};
|
||||||
$G.on("mousemove", onmousemove);
|
$G.on("pointermove", onpointermove);
|
||||||
$G.one("mouseup", function(){
|
$G.one("pointerup", function(){
|
||||||
$G.off("mousemove", onmousemove);
|
$G.off("pointermove", onpointermove);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
continuous: "space",
|
continuous: "space",
|
||||||
|
@ -87,7 +87,7 @@ tools = [{
|
||||||
ctx.putImageData(id_dest, rect_x, rect_y);
|
ctx.putImageData(id_dest, rect_x, rect_y);
|
||||||
|
|
||||||
},
|
},
|
||||||
mouseup: function(){
|
pointerup: function(){
|
||||||
// Revert the inverty brush paint
|
// Revert the inverty brush paint
|
||||||
ctx.copy(undos[undos.length-1]);
|
ctx.copy(undos[undos.length-1]);
|
||||||
|
|
||||||
|
@ -116,40 +116,40 @@ tools = [{
|
||||||
description: "Selects a rectangular part of the picture to move, copy, or edit.",
|
description: "Selects a rectangular part of the picture to move, copy, or edit.",
|
||||||
cursor: ["precise", [16, 16], "crosshair"],
|
cursor: ["precise", [16, 16], "crosshair"],
|
||||||
passive: true,
|
passive: true,
|
||||||
mousedown: function(){
|
pointerdown: function(){
|
||||||
if(selection){
|
if(selection){
|
||||||
selection.draw();
|
selection.draw();
|
||||||
selection.destroy();
|
selection.destroy();
|
||||||
selection = null;
|
selection = null;
|
||||||
}
|
}
|
||||||
var mouse_has_moved = false;
|
var pointer_has_moved = false;
|
||||||
$G.one("mousemove", function(){
|
$G.one("pointermove", function(){
|
||||||
mouse_has_moved = true;
|
pointer_has_moved = true;
|
||||||
});
|
});
|
||||||
$G.one("mouseup", function(){
|
$G.one("pointerup", function(){
|
||||||
if(!mouse_has_moved && selection){
|
if(!pointer_has_moved && selection){
|
||||||
selection.draw();//?
|
selection.draw();//?
|
||||||
selection.destroy();
|
selection.destroy();
|
||||||
selection = null;
|
selection = null;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
selection = new Selection(mouse.x, mouse.y, 1, 1);
|
selection = new Selection(pointer.x, pointer.y, 1, 1);
|
||||||
},
|
},
|
||||||
paint: function(){
|
paint: function(){
|
||||||
if(!selection){ return; }
|
if(!selection){ return; }
|
||||||
selection.w = selection.x - mouse.x;
|
selection.w = selection.x - pointer.x;
|
||||||
selection.h = selection.y - mouse.y;
|
selection.h = selection.y - pointer.y;
|
||||||
var x1 = Math.max(0, Math.min(selection.x, mouse.x));
|
var x1 = Math.max(0, Math.min(selection.x, pointer.x));
|
||||||
var y1 = Math.max(0, Math.min(selection.y, mouse.y));
|
var y1 = Math.max(0, Math.min(selection.y, pointer.y));
|
||||||
var x2 = Math.min(canvas.width, Math.max(selection.x, mouse.x));
|
var x2 = Math.min(canvas.width, Math.max(selection.x, pointer.x));
|
||||||
var y2 = Math.min(canvas.height, Math.max(selection.y, mouse.y));
|
var y2 = Math.min(canvas.height, Math.max(selection.y, pointer.y));
|
||||||
selection._x = x1;
|
selection._x = x1;
|
||||||
selection._y = y1;
|
selection._y = y1;
|
||||||
selection._w = Math.max(1, x2 - x1);
|
selection._w = Math.max(1, x2 - x1);
|
||||||
selection._h = Math.max(1, y2 - y1);
|
selection._h = Math.max(1, y2 - y1);
|
||||||
selection.position();
|
selection.position();
|
||||||
},
|
},
|
||||||
mouseup: function(){
|
pointerup: function(){
|
||||||
if(!selection){ return; }
|
if(!selection){ return; }
|
||||||
|
|
||||||
if(ctrl){
|
if(ctrl){
|
||||||
|
@ -219,7 +219,7 @@ tools = [{
|
||||||
name: "Fill With Color",
|
name: "Fill With Color",
|
||||||
description: "Fills an area with the selected drawing color.",
|
description: "Fills an area with the selected drawing color.",
|
||||||
cursor: ["fill-bucket", [8, 22], "crosshair"],
|
cursor: ["fill-bucket", [8, 22], "crosshair"],
|
||||||
mousedown: function(ctx, x, y){
|
pointerdown: function(ctx, x, y){
|
||||||
|
|
||||||
// Get the rgba values of the selected fill color
|
// Get the rgba values of the selected fill color
|
||||||
var rgba = get_rgba_from_color(fill_color);
|
var rgba = get_rgba_from_color(fill_color);
|
||||||
|
@ -241,9 +241,9 @@ tools = [{
|
||||||
background: this.current_color
|
background: this.current_color
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
mousedown: function(){
|
pointerdown: function(){
|
||||||
var _this = this;
|
var _this = this;
|
||||||
$G.one("mouseup", function(){
|
$G.one("pointerup", function(){
|
||||||
_this.$options.css({
|
_this.$options.css({
|
||||||
background: ""
|
background: ""
|
||||||
});
|
});
|
||||||
|
@ -262,7 +262,7 @@ tools = [{
|
||||||
}
|
}
|
||||||
this.display_current_color();
|
this.display_current_color();
|
||||||
},
|
},
|
||||||
mouseup: function(){
|
pointerup: function(){
|
||||||
colors[fill_color_k] = this.current_color;
|
colors[fill_color_k] = this.current_color;
|
||||||
$G.trigger("option-changed");
|
$G.trigger("option-changed");
|
||||||
},
|
},
|
||||||
|
@ -276,7 +276,7 @@ tools = [{
|
||||||
deselect: true,
|
deselect: true,
|
||||||
passive: true,
|
passive: true,
|
||||||
// @TODO: choose and preview viewport with rectangular cursor
|
// @TODO: choose and preview viewport with rectangular cursor
|
||||||
mousedown: function(){
|
pointerdown: function(){
|
||||||
if(magnification > 1){
|
if(magnification > 1){
|
||||||
reset_magnification();
|
reset_magnification();
|
||||||
}else{
|
}else{
|
||||||
|
@ -343,39 +343,39 @@ tools = [{
|
||||||
description: "Inserts text into the picture.",
|
description: "Inserts text into the picture.",
|
||||||
cursor: ["precise", [16, 16], "crosshair"],
|
cursor: ["precise", [16, 16], "crosshair"],
|
||||||
passive: true,
|
passive: true,
|
||||||
mousedown: function(){
|
pointerdown: function(){
|
||||||
if(textbox){
|
if(textbox){
|
||||||
textbox.draw();
|
textbox.draw();
|
||||||
textbox.destroy();
|
textbox.destroy();
|
||||||
}
|
}
|
||||||
var mouse_has_moved = false;
|
var pointer_has_moved = false;
|
||||||
$G.one("mousemove", function(){
|
$G.one("pointermove", function(){
|
||||||
mouse_has_moved = true;
|
pointer_has_moved = true;
|
||||||
});
|
});
|
||||||
$G.one("mouseup", function(){
|
$G.one("pointerup", function(){
|
||||||
if(!mouse_has_moved && textbox){
|
if(!pointer_has_moved && textbox){
|
||||||
textbox.draw();
|
textbox.draw();
|
||||||
textbox.destroy();
|
textbox.destroy();
|
||||||
textbox = null;
|
textbox = null;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
textbox = new TextBox(mouse.x, mouse.y, 1, 1);
|
textbox = new TextBox(pointer.x, pointer.y, 1, 1);
|
||||||
},
|
},
|
||||||
paint: function(){
|
paint: function(){
|
||||||
if(!textbox){ return; }
|
if(!textbox){ return; }
|
||||||
textbox.w = textbox.x - mouse.x;
|
textbox.w = textbox.x - pointer.x;
|
||||||
textbox.h = textbox.y - mouse.y;
|
textbox.h = textbox.y - pointer.y;
|
||||||
var x1 = Math.max(0, Math.min(textbox.x, mouse.x));
|
var x1 = Math.max(0, Math.min(textbox.x, pointer.x));
|
||||||
var y1 = Math.max(0, Math.min(textbox.y, mouse.y));
|
var y1 = Math.max(0, Math.min(textbox.y, pointer.y));
|
||||||
var x2 = Math.min(canvas.width, Math.max(textbox.x, mouse.x));
|
var x2 = Math.min(canvas.width, Math.max(textbox.x, pointer.x));
|
||||||
var y2 = Math.min(canvas.height, Math.max(textbox.y, mouse.y));
|
var y2 = Math.min(canvas.height, Math.max(textbox.y, pointer.y));
|
||||||
textbox._x = x1;
|
textbox._x = x1;
|
||||||
textbox._y = y1;
|
textbox._y = y1;
|
||||||
textbox._w = Math.max(1, x2 - x1);
|
textbox._w = Math.max(1, x2 - x1);
|
||||||
textbox._h = Math.max(1, y2 - y1);
|
textbox._h = Math.max(1, y2 - y1);
|
||||||
textbox.position();
|
textbox.position();
|
||||||
},
|
},
|
||||||
mouseup: function(){
|
pointerup: function(){
|
||||||
if(!textbox){ return; }
|
if(!textbox){ return; }
|
||||||
textbox.instantiate();
|
textbox.instantiate();
|
||||||
},
|
},
|
||||||
|
@ -405,12 +405,12 @@ tools = [{
|
||||||
// but the first action should be undoable / cancelable
|
// but the first action should be undoable / cancelable
|
||||||
return this.points.length > 0;
|
return this.points.length > 0;
|
||||||
},
|
},
|
||||||
mouseup: function(ctx, x, y){
|
pointerup: function(ctx, x, y){
|
||||||
if(this.points.length >= 4){
|
if(this.points.length >= 4){
|
||||||
this.points = [];
|
this.points = [];
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mousedown: function(ctx, x, y){
|
pointerdown: function(ctx, x, y){
|
||||||
if(this.points.length < 1){
|
if(this.points.length < 1){
|
||||||
// This would be so much better in CoffeeScript
|
// This would be so much better in CoffeeScript
|
||||||
var thine = this;
|
var thine = this;
|
||||||
|
@ -483,10 +483,10 @@ tools = [{
|
||||||
cursor: ["precise", [16, 16], "crosshair"],
|
cursor: ["precise", [16, 16], "crosshair"],
|
||||||
|
|
||||||
// Record the last click for double-clicking
|
// Record the last click for double-clicking
|
||||||
// A double click happens on mousedown of a second click
|
// A double click happens on pointerdown of a second click
|
||||||
// (within a cylindrical volume in 2d space + 1d time)
|
// (within a cylindrical volume in 2d space + 1d time)
|
||||||
last_click_mousedown: {x: -Infinity, y: -Infinity, time: -Infinity},
|
last_click_pointerdown: {x: -Infinity, y: -Infinity, time: -Infinity},
|
||||||
last_click_mouseup: {x: -Infinity, y: -Infinity, time: -Infinity},
|
last_click_pointerup: {x: -Infinity, y: -Infinity, time: -Infinity},
|
||||||
|
|
||||||
// The vertices of the polygon
|
// The vertices of the polygon
|
||||||
points: [],
|
points: [],
|
||||||
|
@ -503,7 +503,7 @@ tools = [{
|
||||||
return this.points.length > 0;
|
return this.points.length > 0;
|
||||||
// In other words, it's supposed to be one undoable action
|
// In other words, it's supposed to be one undoable action
|
||||||
},
|
},
|
||||||
mouseup: function(ctx, x, y){
|
pointerup: function(ctx, x, y){
|
||||||
if(this.points.length < 1){ return; }
|
if(this.points.length < 1){ return; }
|
||||||
|
|
||||||
var i = this.points.length - 1;
|
var i = this.points.length - 1;
|
||||||
|
@ -516,9 +516,9 @@ tools = [{
|
||||||
this.complete(ctx, x, y);
|
this.complete(ctx, x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.last_click_mouseup = {x: x, y: y, time: +(new Date)};
|
this.last_click_pointerup = {x: x, y: y, time: +(new Date)};
|
||||||
},
|
},
|
||||||
mousedown: function(ctx, x, y){
|
pointerdown: function(ctx, x, y){
|
||||||
var tool = this;
|
var tool = this;
|
||||||
|
|
||||||
if(tool.points.length < 1){
|
if(tool.points.length < 1){
|
||||||
|
@ -541,18 +541,18 @@ tools = [{
|
||||||
tool.points.push({x: x, y: y});
|
tool.points.push({x: x, y: y});
|
||||||
});
|
});
|
||||||
}else{
|
}else{
|
||||||
var lx = tool.last_click_mousedown.x;
|
var lx = tool.last_click_pointerdown.x;
|
||||||
var ly = tool.last_click_mousedown.y;
|
var ly = tool.last_click_pointerdown.y;
|
||||||
var lt = tool.last_click_mousedown.time;
|
var lt = tool.last_click_pointerdown.time;
|
||||||
var dx = x - lx;
|
var dx = x - lx;
|
||||||
var dy = y - ly;
|
var dy = y - ly;
|
||||||
var dt = +(new Date) - lt;
|
var dt = +(new Date) - lt;
|
||||||
var d = Math.sqrt(dx*dx + dy*dy);
|
var d = Math.sqrt(dx*dx + dy*dy);
|
||||||
if(d < 4.1010101 && dt < 250){ // arbitrary 101
|
if(d < 4.1010101 && dt < 250){ // arbitrary 101
|
||||||
tool.complete(ctx, x, y);
|
tool.complete(ctx, x, y);
|
||||||
// Release the mouse to prevent tool.paint()
|
// Release the pointer to prevent tool.paint()
|
||||||
// being called and clearing the canvas
|
// being called and clearing the canvas
|
||||||
$canvas.trigger("mouseup");
|
$canvas.trigger("pointerup");
|
||||||
}else{
|
}else{
|
||||||
// Add the point
|
// Add the point
|
||||||
tool.points.push({x: x, y: y});
|
tool.points.push({x: x, y: y});
|
||||||
|
@ -564,7 +564,7 @@ tools = [{
|
||||||
tool.y_max = Math.max(y, tool.y_max);
|
tool.y_max = Math.max(y, tool.y_max);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tool.last_click_mousedown = {x: x, y: y, time: +new Date};
|
tool.last_click_pointerdown = {x: x, y: y, time: +new Date};
|
||||||
},
|
},
|
||||||
paint: function(ctx, x, y){
|
paint: function(ctx, x, y){
|
||||||
if(this.points.length < 1){ return; }
|
if(this.points.length < 1){ return; }
|
||||||
|
@ -670,8 +670,8 @@ tools = [{
|
||||||
},
|
},
|
||||||
reset: function(){
|
reset: function(){
|
||||||
this.points = [];
|
this.points = [];
|
||||||
this.last_click_mousedown = {x: -Infinity, y: -Infinity, time: -Infinity};
|
this.last_click_pointerdown = {x: -Infinity, y: -Infinity, time: -Infinity};
|
||||||
this.last_click_mouseup = {x: -Infinity, y: -Infinity, time: -Infinity};
|
this.last_click_pointerup = {x: -Infinity, y: -Infinity, time: -Infinity};
|
||||||
},
|
},
|
||||||
shape_colors: true,
|
shape_colors: true,
|
||||||
$options: $ChooseShapeStyle()
|
$options: $ChooseShapeStyle()
|
||||||
|
|
Loading…
Reference in New Issue