mirror of
https://github.com/lospec/pixel-editor.git
synced 2023-08-10 21:12:51 +03:00
Introduce ellipse tool (which draws rectangle for now)
This commit is contained in:
parent
07f36cf7cb
commit
6cc60c00e8
6
_ext/svg/ellipse.svg
Normal file
6
_ext/svg/ellipse.svg
Normal file
@ -0,0 +1,6 @@
|
||||
<svg width="512" height="512" viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg">
|
||||
<g>
|
||||
<ellipse stroke="#000" stroke-width="32" fill="none" cx="255.50001" cy="255.5" id="svg_20" rx="239" ry="187.5"/>
|
||||
</g>
|
||||
|
||||
</svg>
|
After Width: | Height: | Size: 221 B |
22
_ext/svg/filledellipse.svg
Normal file
22
_ext/svg/filledellipse.svg
Normal file
@ -0,0 +1,22 @@
|
||||
<svg width="512" height="512" viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg">
|
||||
<g>
|
||||
<title>Layer 1</title>
|
||||
<g id="svg_4"/>
|
||||
<g id="svg_5"/>
|
||||
<g id="svg_6"/>
|
||||
<g id="svg_7"/>
|
||||
<g id="svg_8"/>
|
||||
<g id="svg_9"/>
|
||||
<g id="svg_10"/>
|
||||
<g id="svg_11"/>
|
||||
<g id="svg_12"/>
|
||||
<g id="svg_13"/>
|
||||
<g id="svg_14"/>
|
||||
<g id="svg_15"/>
|
||||
<g id="svg_16"/>
|
||||
<g id="svg_17"/>
|
||||
<g id="svg_18"/>
|
||||
<ellipse stroke="#000" stroke-width="32" fill="#000000" cx="255.50001" cy="255.5" id="svg_20" rx="239" ry="187.5"/>
|
||||
</g>
|
||||
|
||||
</svg>
|
After Width: | Height: | Size: 528 B |
@ -688,6 +688,7 @@ svg {
|
||||
#tools-menu li button#zoom-in-button,
|
||||
#tools-menu li button#eraser-bigger-button,
|
||||
#tools-menu li button#rectangle-bigger-button,
|
||||
#tools-menu li button#ellipse-bigger-button,
|
||||
#tools-menu li button#line-bigger-button {
|
||||
left: 0;
|
||||
}
|
||||
@ -696,6 +697,7 @@ svg {
|
||||
#tools-menu li button#zoom-out-button,
|
||||
#tools-menu li button#eraser-smaller-button,
|
||||
#tools-menu li button#rectangle-smaller-button,
|
||||
#tools-menu li button#ellipse-smaller-button,
|
||||
#tools-menu li button#line-smaller-button {
|
||||
right: 0;
|
||||
}
|
||||
@ -708,6 +710,8 @@ svg {
|
||||
#tools-menu li.selected button#eraser-smaller-button,
|
||||
#tools-menu li.selected button#rectangle-bigger-button,
|
||||
#tools-menu li.selected button#rectangle-smaller-button,
|
||||
#tools-menu li.selected button#ellipse-bigger-button,
|
||||
#tools-menu li.selected button#ellipse-smaller-button,
|
||||
#tools-menu li.selected button#line-bigger-button,
|
||||
#tools-menu li.selected button#line-smaller-button {
|
||||
display: block;
|
||||
|
@ -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
146
js/_ellipse.js
Normal 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');
|
||||
}
|
||||
}
|
@ -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()
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
|
@ -73,6 +73,7 @@
|
||||
//=include _rectSelect.js
|
||||
//=include _move.js
|
||||
//=include _rectangle.js
|
||||
//=include _ellipse.js
|
||||
|
||||
/**onload**/
|
||||
//=include _onLoad.js
|
||||
|
@ -41,6 +41,10 @@ new Tool('rectangle', {
|
||||
cursor: 'crosshair',
|
||||
brushPreview: true,
|
||||
});
|
||||
new Tool('ellipse', {
|
||||
cursor: 'crosshair',
|
||||
brushPreview: true,
|
||||
});
|
||||
new Tool('resizerectangle', {
|
||||
cursor: 'default',
|
||||
});
|
||||
|
@ -33,6 +33,7 @@
|
||||
<img src="/pixel-editor/zoom-in.png" />
|
||||
<img src = "/pixel-editor/eraser.png"/>
|
||||
<img src = "/pixel-editor/rectselect.png"/>
|
||||
<!-- TODO: [ELLIPSE] Where is this icon used? Do we need similar one for ellipsis? -->
|
||||
<img src= "/pixel-editor/rectangle.png">
|
||||
</div>
|
||||
|
||||
@ -119,12 +120,23 @@
|
||||
</li>
|
||||
|
||||
<li class="expanded">
|
||||
<button title="Rectangle Tool (U)" id="rectangle-button">{{svg "rectangle.svg" width="32" height="32" id = "empty-button-svg"}}
|
||||
{{svg "fullrect.svg" width="32" height="32" id = "full-button-svg" display = "none"}}</button>
|
||||
<button title="Rectangle Tool (U)" id="rectangle-button">{{svg "rectangle.svg" width="32" height="32" id = "rectangle-empty-button-svg"}}
|
||||
{{svg "fullrect.svg" width="32" height="32" id = "rectangle-full-button-svg" display = "none"}}</button>
|
||||
<button title="Increase Rectangle Size" id="rectangle-bigger-button" class="tools-menu-sub-button">{{svg "plus.svg" width="12" height="12"}}</button>
|
||||
<button title="Decrease Rectangle Size" id="rectangle-smaller-button" class="tools-menu-sub-button">{{svg "minus.svg" width="12" height="12"}}</button>
|
||||
</li>
|
||||
|
||||
<li class="expanded">
|
||||
<!-- TODO: [ELLIPSE] Decide on a shortcut to use. "S" was chosen without any in-team consultation. -->
|
||||
<!-- TODO: [ELLIPSE] Decide on icons to use. Current ones are quickly prepared drafts and display with incorrect color. -->
|
||||
<button title="Ellipse Tool (S)" id="ellipse-button">
|
||||
{{svg "ellipse.svg" width="32" height="32" id = "ellipse-empty-button-svg"}}
|
||||
{{svg "filledellipse.svg" width="32" height="32" id = "ellipse-full-button-svg" display = "none"}}
|
||||
</button>
|
||||
<button title="Increase Ellipse Size" id="ellipse-bigger-button" class="tools-menu-sub-button">{{svg "plus.svg" width="12" height="12"}}</button>
|
||||
<button title="Decrease Ellipse Size" id="ellipse-smaller-button" class="tools-menu-sub-button">{{svg "minus.svg" width="12" height="12"}}</button>
|
||||
</li>
|
||||
|
||||
<li><button title="Fill Tool (F)" id="fill-button">{{svg "fill.svg" width="32" height="32"}}</button></li>
|
||||
|
||||
<li><button title="Eyedropper Tool (E)" id="eyedropper-button">{{svg "eyedropper.svg" width="32" height="32"}}</button></li>
|
||||
|
Loading…
Reference in New Issue
Block a user