Introduce ellipse tool (which draws rectangle for now)

This commit is contained in:
nkoder
2021-04-28 22:35:26 +02:00
parent 07f36cf7cb
commit 6cc60c00e8
12 changed files with 269 additions and 17 deletions

View File

@ -9,7 +9,7 @@ function line(x0,y0,x1,y1, brushSize) {
while (true) {
//set pixel
// If the current tool is the brush
if (currentTool.name == 'pencil' || currentTool.name == 'rectangle') {
if (currentTool.name == 'pencil' || currentTool.name == 'rectangle' || currentTool.name == 'ellipse') {
// I fill the rect
currentLayer.context.fillRect(x0-Math.floor(brushSize/2), y0-Math.floor(brushSize/2), brushSize, brushSize);
} else if (currentTool.name == 'eraser') {

146
js/_ellipse.js Normal file
View File

@ -0,0 +1,146 @@
// Saving the empty rect svg
var emptyEllipseSVG = document.getElementById("ellipse-empty-button-svg");
// and the full rect svg so that I can change them when the user changes rect modes
var fullEllipseSVG = document.getElementById("ellipse-full-button-svg");
// The start mode is empty ellipse
var ellipseDrawMode = 'empty';
// I'm not drawing a ellipse at the beginning
var isDrawingEllipse = false;
// Ellipse coordinates
let startEllipseX;
let startEllipseY;
let endEllipseX;
let endEllipseY;
// TODO: [ELLIPSE] Make it draw ellipse instead of copy-pasted rectangle
/** Starts drawing the ellipse, saves the start coordinates
*
* @param {*} mouseEvent
*/
function startEllipseDrawing(mouseEvent) {
// Putting the vfx layer on top of everything
VFXCanvas.style.zIndex = parseInt(currentLayer.canvas.style.zIndex, 10) + 1;;
// Updating flag
isDrawingEllipse = true;
// Saving the start coords of the ellipse
let cursorPos = getCursorPosition(mouseEvent);
startEllipseX = Math.floor(cursorPos[0] / zoom) + 0.5;
startEllipseY = Math.floor(cursorPos[1] / zoom) + 0.5;
drawEllipse(startEllipseX, startEllipseY);
}
// TODO: [ELLIPSE] Make it draw ellipse instead of copy-pasted rectangle
/** Updates the ellipse preview depending on the position of the mouse
*
* @param {*} mouseEvent The mouseEvent from which we'll get the mouse position
*/
function updateEllipseDrawing(mouseEvent) {
let pos = getCursorPosition(mouseEvent);
// Drawing the ellipse at the right position
drawEllipse(Math.round(pos[0] / zoom) + 0.5, Math.round(pos[1] / zoom) + 0.5);
}
// TODO: [ELLIPSE] Make it draw ellipse instead of copy-pasted rectangle
/** Finishes drawing the ellipse, decides the end coordinates and moves the preview ellipse to the
* current layer
*
* @param {*} mouseEvent event from which we'll get the mouse position
*/
function endEllipseDrawing(mouseEvent) {
// Getting the end position
let currentPos = getCursorPosition(mouseEvent);
let vfxContext = VFXCanvas.getContext("2d");
endEllipseX = Math.round(currentPos[0] / zoom) + 0.5;
endEllipseY = Math.round(currentPos[1] / zoom) + 0.5;
// Inverting end and start (start must always be the top left corner)
if (endEllipseX < startEllipseX) {
let tmp = endEllipseX;
endEllipseX = startEllipseX;
startEllipseX = tmp;
}
// Same for the y
if (endEllipseY < startEllipseY) {
let tmp = endEllipseY;
endEllipseY = startEllipseY;
startEllipseY = tmp;
}
// Resetting this
isDrawingEllipse = false;
// Drawing the ellipse
startEllipseY -= 0.5;
endEllipseY -= 0.5;
endEllipseX -= 0.5;
startEllipseX -= 0.5;
// Setting the correct linewidth and colour
currentLayer.context.lineWidth = tool.ellipse.brushSize;
currentLayer.context.fillStyle = currentGlobalColor;
// Drawing the ellipse using 4 lines
line(startEllipseX, startEllipseY, endEllipseX, startEllipseY, tool.ellipse.brushSize);
line(endEllipseX, startEllipseY, endEllipseX, endEllipseY, tool.ellipse.brushSize);
line(endEllipseX, endEllipseY, startEllipseX, endEllipseY, tool.ellipse.brushSize);
line(startEllipseX, endEllipseY, startEllipseX, startEllipseY, tool.ellipse.brushSize);
// If I have to fill it, I do so
if (ellipseDrawMode == 'fill') {
currentLayer.context.fillRect(startEllipseX, startEllipseY, endEllipseX - startEllipseX, endEllipseY - startEllipseY);
}
// Clearing the vfx canvas
vfxContext.clearRect(0, 0, VFXCanvas.width, VFXCanvas.height);
}
// TODO: [ELLIPSE] Make it draw ellipse instead of copy-pasted rectangle
/** Draws a ellipse with end coordinates given by x and y on the VFX layer (draws
* the preview for the ellipse tool)
*
* @param {*} x The current end x of the ellipse
* @param {*} y The current end y of the ellipse
*/
function drawEllipse(x, y) {
// Getting the vfx context
let vfxContext = VFXCanvas.getContext("2d");
// Clearing the vfx canvas
vfxContext.clearRect(0, 0, VFXCanvas.width, VFXCanvas.height);
// Drawing the ellipse
vfxContext.lineWidth = tool.ellipse.brushSize;
vfxContext.strokeStyle = currentGlobalColor;
// Drawing the ellipse
vfxContext.beginPath();
if ((tool.ellipse.brushSize % 2 ) == 0) {
vfxContext.rect(startEllipseX - 0.5, startEllipseY - 0.5, x - startEllipseX, y - startEllipseY);
}
else {
vfxContext.rect(startEllipseX, startEllipseY, x - startEllipseX, y - startEllipseY);
}
vfxContext.setLineDash([]);
vfxContext.stroke();
}
/** Sets the correct tool icon depending on its mode
*
*/
function setEllipseToolSvg() {
console.log("set eilipse svg");
if (ellipseDrawMode == 'empty') {
emptyEllipseSVG.setAttribute('display', 'visible');
fullEllipseSVG.setAttribute('display', 'none');
}
else {
emptyEllipseSVG.setAttribute('display', 'none');
fullEllipseSVG.setAttribute('display', 'visible');
}
}

View File

@ -65,6 +65,11 @@ function KeyPress(e) {
case 77: case 109:
tool.rectselect.switchTo()
break;
// TODO: [ELLIPSE] Decide on a shortcut to use. "s" was chosen without any in-team consultation.
// ellipse tool, s
case 83:
tool.ellipse.switchTo()
break;
// rectangle tool, u
case 85:
tool.rectangle.switchTo()

View File

@ -22,7 +22,7 @@ window.addEventListener("mousedown", function (mouseEvent) {
else if (mouseEvent.altKey)
currentTool = tool.eyedropper;
else if (mouseEvent.target.className == 'drawingCanvas' &&
(currentTool.name == 'pencil' || currentTool.name == 'eraser' || currentTool.name == 'rectangle' || currentTool.name === 'line'))
(currentTool.name == 'pencil' || currentTool.name == 'eraser' || currentTool.name == 'rectangle' || currentTool.name == 'ellipse' || currentTool.name === 'line'))
new HistoryStateEditCanvas();
else if (currentTool.name == 'moveselection') {
if (!cursorInSelectedArea() &&
@ -46,6 +46,7 @@ window.addEventListener("mousedown", function (mouseEvent) {
currentTool = tool.resizeeraser;
tool.eraser.previousBrushSize = tool.eraser.brushSize;
}
// TODO: [ELLIPSE] Do we need similar logic related to ellipse?
else if (currentTool.name == 'rectangle' && mouseEvent.which == 3) {
currentTool = tool.resizerectangle;
tool.rectangle.previousBrushSize = tool.rectangle.brushSize;
@ -160,6 +161,10 @@ window.addEventListener("mouseup", function (mouseEvent) {
endRectDrawing(mouseEvent);
currentLayer.updateLayerPreview();
}
else if (currentTool.name == 'ellipse' && isDrawingEllipse) {
endEllipseDrawing(mouseEvent);
currentLayer.updateLayerPreview();
}
dragging = false;
currentTool = currentToolTemp;
@ -269,6 +274,21 @@ function draw (mouseEvent) {
updateRectDrawing(mouseEvent);
}
}
else if (currentTool.name == 'ellipse')
{
//hide brush preview outside of canvas / canvas view
if (mouseEvent.target.className == 'drawingCanvas'|| mouseEvent.target.className == 'drawingCanvas')
brushPreview.style.visibility = 'visible';
else
brushPreview.style.visibility = 'hidden';
if (!isDrawingEllipse && dragging) {
startEllipseDrawing(mouseEvent);
}
else if (dragging){
updateEllipseDrawing(mouseEvent);
}
}
else if (currentTool.name == 'pan' && dragging) {
// Setting first layer position
layers[0].setCanvasOffset(layers[0].canvas.offsetLeft + (cursorLocation[0] - lastMouseClickPos[0]), layers[0].canvas.offsetTop + (cursorLocation[1] - lastMouseClickPos[1]));
@ -328,12 +348,15 @@ function draw (mouseEvent) {
//var roundingAmount = 20 - Math.round(distanceFromClick/10);
//this doesnt work in reverse... because... it's not basing it off of the brush size which it should be
var rectangleSizeChange = Math.round(distanceFromClick/10);
// TODO: [ELLIPSE] Do we need similar logic related to ellipse?
var newRectangleSize = tool.rectangle.previousBrushSize + rectangleSizeChange;
//set the brush to the new size as long as its bigger than 1
// TODO: [ELLIPSE] Do we need similar logic related to ellipse?
tool.rectangle.brushSize = Math.max(1,newRectangleSize);
//fix offset so the cursor stays centered
// TODO: [ELLIPSE] Do we need similar logic related to ellipse?
tool.rectangle.moveBrushPreview(lastMouseClickPos);
currentTool.updateCursor();
}

View File

@ -1,10 +1,10 @@
// Saving the empty rect svg
var emptySVG = document.getElementById("empty-button-svg");
var emptyRectangleSVG = document.getElementById("rectangle-empty-button-svg");
// and the full rect svg so that I can change them when the user changes rect modes
var fullSVG = document.getElementById("full-button-svg");
var fullRectangleSVG = document.getElementById("rectangle-full-button-svg");
// The start mode is empty rectangle
var drawMode = 'empty';
var rectangleDrawMode = 'empty';
// I'm not drawing a rectangle at the beginning
var isDrawingRect = false;
@ -19,7 +19,7 @@ let endRectY;
* @param {*} mouseEvent
*/
function startRectDrawing(mouseEvent) {
// Putting the vfx layer on top of everything
// Putting the vfx layer on top of everything
VFXCanvas.style.zIndex = parseInt(currentLayer.canvas.style.zIndex, 10) + 1;;
// Updating flag
isDrawingRect = true;
@ -88,7 +88,7 @@ function endRectDrawing(mouseEvent) {
line(startRectX, endRectY, startRectX, startRectY, tool.rectangle.brushSize);
// If I have to fill it, I do so
if (drawMode == 'fill') {
if (rectangleDrawMode == 'fill') {
currentLayer.context.fillRect(startRectX, startRectY, endRectX - startRectX, endRectY - startRectY);
}
@ -130,13 +130,13 @@ function drawRectangle(x, y) {
*
*/
function setRectToolSvg() {
if (drawMode == 'empty') {
emptySVG.setAttribute('display', 'visible');
fullSVG.setAttribute('display', 'none');
if (rectangleDrawMode == 'empty') {
emptyRectangleSVG.setAttribute('display', 'visible');
fullRectangleSVG.setAttribute('display', 'none');
}
else {
emptySVG.setAttribute('display', 'none');
fullSVG.setAttribute('display', 'visible');
emptyRectangleSVG.setAttribute('display', 'none');
fullRectangleSVG.setAttribute('display', 'visible');
}
}

View File

@ -35,12 +35,12 @@ on('click',"eraser-smaller-button", function(e){
on('click','rectangle-button', function(e){
// If the user clicks twice on the button, they change the draw mode
if (currentTool.name == 'rectangle') {
if (drawMode == 'empty') {
drawMode = 'fill';
if (rectangleDrawMode == 'empty') {
rectangleDrawMode = 'fill';
setRectToolSvg();
}
else {
drawMode = 'empty';
rectangleDrawMode = 'empty';
setRectToolSvg();
}
}
@ -49,6 +49,24 @@ on('click','rectangle-button', function(e){
}
}, false);
// ellipse
on('click','ellipse-button', function(e){
// If the user clicks twice on the button, they change the draw mode
if (currentTool.name == 'ellipse') {
if (ellipseDrawMode == 'empty') {
ellipseDrawMode = 'fill';
setEllipseToolSvg();
}
else {
ellipseDrawMode = 'empty';
setEllipseToolSvg();
}
}
else {
tool.ellipse.switchTo();
}
}, false);
// rectangle bigger
on('click',"rectangle-bigger-button", function(){
tool.rectangle.brushSize++;
@ -60,6 +78,17 @@ on('click',"rectangle-smaller-button", function(e){
tool.rectangle.brushSize--;
}, false);
// ellipse bigger
on('click',"ellipse-bigger-button", function(){
tool.ellipse.brushSize++;
}, false);
// ellipse smaller
on('click',"ellipse-smaller-button", function(e){
if(tool.ellipse.brushSize > 1)
tool.ellipse.brushSize--;
}, false);
//fill
on('click',"fill-button", function(){
tool.fill.switchTo();

View File

@ -73,6 +73,7 @@
//=include _rectSelect.js
//=include _move.js
//=include _rectangle.js
//=include _ellipse.js
/**onload**/
//=include _onLoad.js

View File

@ -41,6 +41,10 @@ new Tool('rectangle', {
cursor: 'crosshair',
brushPreview: true,
});
new Tool('ellipse', {
cursor: 'crosshair',
brushPreview: true,
});
new Tool('resizerectangle', {
cursor: 'default',
});