Drawing lines with (mouse + other key) - javascript

I am a newbie in javascript and canvas. I am using the following code to draw a line while the mouse is dragged. I am trying to add another drawing option with the original while I dragged the mouse with some other key (say mouse + p) but I didn't get it, how to add. So basically there will be two options for drawing 1) mouse drag with one color "green" 2) key "P" + mouse drag with another color "red". I searched a lot on different site but everywhere the option is "mouse:down", "mouse:move", "mouse:up".
function makeBackgroundDrawingFabricCanvas(myCanvasObj, appendToCol) {
let canvas_id = myCanvasObj.id
let canvas_html = $("<canvas>")
$(canvas_html).attr("id", canvas_id)
$(canvas_html).attr("height", canvas_height)
$(canvas_html).attr("width", canvas_width)
$(appendToCol).append(canvas_html)
var canvas = new fabric.Canvas(canvas_id);
canvas.isDrawingMode = true
canvas.freeDrawingBrush.color = "green";
canvas.freeDrawingBrush.width = 10;
let add_back_detail_button = $("<button class='btn btn-primary'>Add Back Detail</button>")
$(appendToCol).append(add_back_detail_button)
$(add_back_detail_button).click(function(){
somefunction(canvas_3_add, obj, canvas4_id, obj.image.original_image)
})
}
it will be a great help if you just point me where to add that option in my code.

Add the following code
document.addEventListener("keydown", event => {
if (event.key === "p") {
canvas.freeDrawingBrush.color = "red";
}
});
document.addEventListener("keyup", event => {
if (event.key === "p") {
canvas.freeDrawingBrush.color = "green";
}
});

Related

How do I create a Ctrl+z event on the canvas?

I am trying to make an 'undo' action like Ctrl + Z.
But I really don't know how to make it.
This is my code. I want to add a ctrl+z event, but I don't know what to do.
const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");
const modeBtn = document.querySelector("#mode-btn");
const CANVAS_WIDTH = 800;
const CANVAS_HEIGHT = 800;
canvas.width = CANVAS_WIDTH;
canvas.height = CANVAS_HEIGHT;
ctx.lineCap = "round";
let isPainting = false;
let isFilling = false;
function onMove(event) {
if (isPainting) {
ctx.lineTo(event.offsetX, event.offsetY);
ctx.stroke();
return;
}
ctx.moveTo(event.offsetX, event.offsetY);
}
function startPainting() {
isPainting = true;
}
function cancelPainting() {
isPainting = false;
ctx.beginPath();
}
function onModeClick() {
if (isFilling) {
isFilling = false;
} else {
isFilling = true;
}
}
function onCanvasClick() {
if (isFilling) {
ctx.fillRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
}
}
canvas.addEventListener("mousemove", onMove);
canvas.addEventListener("mousedown", startPainting);
canvas.addEventListener("mouseup", cancelPainting);
canvas.addEventListener("mouseleave", cancelPainting);
canvas.addEventListener("click", onCanvasClick);
modeBtn.addEventListener("click", onModeClick);
<canvas></canvas>
<div class="btns">
<button id="mode-btn">Draw</button>
</div>
<script src="app.js"></script>
I used split(-1,1), but it didn't work at all, or it was deleted completely, not undo.
I am a beginner. I don't know how to apply it. Help me, please.
For a beginner, the simplest approach you can take is to keep an array of the positions that you drew on in a stack, and during the undo operation, just pop those values and clear those positions on the canvas.
To listen for the ctrl+z keypress you can use something like this -
function onUndo() {
var evtobj = window.event ? event : e;
if (evtobj.keyCode == 90 && evtobj.ctrlKey) undo();
}
document.addEventListener("keydown", onUndo);
And to undo the operations, the simplest code could look something like this (note this basically the opposite of what you were doing during drawing) -
function undo() {
const color = ctx.strokeStyle;
ctx.strokeStyle = BG_COLOR;
if (actions.length === 0) {
ctx.strokeStyle = color;
return;
}
const action = actions.pop();
if (action.type === "move") {
ctx.lineTo(action.x, action.y);
ctx.stroke();
}
ctx.strokeStyle = color;
}
Here BG_COLOR is background color of your canvas
Also, this approach might work for now, but it would get difficult to manage and maintain as you add more kinds of drawing approaches to your canvas. To do this in a more maintainable way, I would suggest that you look into the memento pattern

event listener with Pointerup not firing when activated from touchscreen

I'm coding a simple javascript drawing program using an HTML canvas, it will allow you to draw a line, and change the color of said line via a button, and see which color you have selected using a element and some javascript involving innerText, and it works great, when used with a mouse or trackpad, however when it's used on touchscreen it draws a short bit of line then stops. I have tracked the problem to the pointerup event, but I have no idea what exactly is going wrong with it. See for yourself-
<canvas id='dr' width = '640' height = '480' ></canvas>
<div style = 'width: 35%; margin: auto; ' id = 'ClearAndColor'>
<button onclick = 'switchColor()'> Change color</button>
<button onclick = 'clean()' > clear drawing program</button>
<p id = 'color'>black</p>
</div>
<p id = 'p'></p>
<script>
var canvas = document.getElementById('dr');
var ctx = canvas.getContext('2d');
var line = false
function drawType() {
if (line === true) {
line = false;
} else {
line = true;
}
}
var drawing = false;
function Type() {}
//start the drawing if the mouse is down
canvas.addEventListener("pointerdown", () => {
drawing = true;
})
//stop the drawing if the mouse is up
canvas.addEventListener("pointerup", () => {
drawing = false;
});
//add an event listener to the canvas for when the user moves the
//mouse over it and the mouse is down
var colors = ['DarkRed', 'DarkOrange', 'Gold', 'Green',
'MediumBlue', 'Indigo', 'Violet', 'Black']
var displayColors = ['r', 'Red', 'Orange', 'Yellow', 'Green',
'Blue', 'Indigo', 'Violet', 'Black']
var selector = 0
var color = document.getElementById('color')
var selectedColor = colors[selector];
function switchColor() {
if (selector < 8) {
selector = selector + 1;
} else {
selector = 1;
}
color.innerText = displayColors[selector];
selectedColor = colors[selector];
}
canvas.addEventListener('pointermove', (event) => {
// this right here \/ is just for logging purposes.
var p = document.getElementById('p')
p.innerText = drawing;
//if the drawing mode is true (if the mouse button is down)
if (drawing == true) {
//put the rectangle on the canvas at the coordinates of the
//mouse
ctx.fillStyle = colors[selector-1];
ctx.fillRect(event.clientX, event.clientY, 4, 4)
}
});
//onMouseDown onMouseMove onMouseUp onTouchEnd
function clean() {
var canvas = document.getElementById('dr');
var ctx = canvas.getContext('2d');
ctx.clearRect(0, 0, 640, 480);
}
</script>

Keyboard input pause [duplicate]

This question already has answers here:
move element with keypress (multiple)
(3 answers)
Closed 3 years ago.
I made a pretty basic demo, you press an arrow key and the square moves in that direction. One problem: when I first press the key, the square moves a little, pauses, then continues moving. How do I get rid of or work around the pause?
Code:
var canvas = document.getElementById("canvas")
var ctx = canvas.getContext('2d');
var p1 = document.getElementById("p1");
var keys = [];
var x = 25
var y = 25
document.addEventListener("keydown", function(e) {
keys[e.keyCode] = true;
update();
});
document.addEventListener("keyup", function(e) {
keys[e.keyCode] = false;
update();
});
function update() {
ctx.clearRect(0, 0, 400, 400)
if(keys[40] == true) {
y += 5
}
if(keys[38] == true) {
y -= 5
}
if(keys[39] == true) {
x += 5
}
if(keys[37] == true) {
x -= 5
}
ctx.fillRect(x, y, 100, 100)
console.log(keys);
p1.innerText = "";
for (i = 0; i < keys.length; i++) {
if (keys[i]) {
p1.innerText += i + " | ";
}
}
}
<canvas id='canvas' width='400' height='400'></canvas>
<p id='p1'>testing</p>
This happens because the keydown event is continuously fired at different intervals in different browsers.
Instead of relying on the browser to send keydown from time to time, it's better to have your own update loop running at 60fps, using requestAnimationFrame and each frame moving the box based on the keys pressed.
var canvas = document.getElementById("canvas")
var ctx = canvas.getContext('2d');
var p1 = document.getElementById("p1");
var keys = [];
var x = 25
var y = 25
document.addEventListener("keydown", function(e) {
e.preventDefault(); // make sure this doesn't scroll the window
keys[e.keyCode] = true;
});
document.addEventListener("keyup", function(e) {
keys[e.keyCode] = false;
});
function update() {
// Tell the browser to run again update when it is "free",
// preferably at 60fps (actually your monitor's refresh rate)
requestAnimationFrame(update);
ctx.clearRect(0, 0, 400, 400)
if(keys[40] == true) {
y += 5
}
if(keys[38] == true) {
y -= 5
}
if(keys[39] == true) {
x += 5
}
if(keys[37] == true) {
x -= 5
}
ctx.fillRect(x, y, 100, 100)
p1.innerText = "";
for (i = 0; i < keys.length; i++) {
if (keys[i]) {
p1.innerText += i + " | ";
}
}
}
update(); // Start running the loop at 60fps
<canvas id='canvas' width='400' height='400'></canvas>
<p id='p1'>testing</p>
Note that the distance the box moves in a given amount of time depends on your framerate, so if the browser can't keep up at 60fps and only runs at 30fps, update will be only called half of the times, so the box will only move half of the distance it would otherwise move at 60fps. To learn more about animations and game update loops I recommend to read this fix your timestep article.

Stopping more than one instance of a function running at a time

I am fairly new to JavaScript and have searched everywhere for an answer to my question and cant seem to find anything related at all. This tells me that I'm missing something with my understanding of how my program works.
I have written a small game where the player navigates through a randomly generated maze using a gameloop that checks keydown events every x milliseconds. The game has a difficulty dropdown menu and then the game is started my clicking a button that calls a function to create a canvas where the game is drawn.
My problem is that when the button is clicked again to create a new maze without reloading the page, the gameloop for the original maze is still running and so key events are registered twice. This is causing some unexpected behavior. It's as though every time the button is clicked, a new instance of the function is running. Is there some way that each time the button is clicked I can set it to stop the previous game function?
var canvas;
var div;
var mazeGenButton;
$(document).ready(function () {
canvas = null;
div = document.getElementById('canvascontainer');;
mazeGenButton = document.getElementById("mazeGenButton");
mazeGenButton.onclick = createInstance;
});
function createInstance() {
if (canvas != null) {
div.removeChild(document.getElementById("myCanvas"));
}
canvas = document.createElement('canvas');
canvas.id = "myCanvas";
canvas.width = 1000;
canvas.height = 1000;
div.appendChild(canvas);
drawMaze();
};
var drawMaze = function () {
//code here to create the game(not posted)
//here is the Key listener - not sure if it's related
var keyState = {};
window.addEventListener('keydown', function (e) {
keyState[e.keyCode || e.which] = true;
}, true);
window.addEventListener('keyup', function (e) {
keyState[e.keyCode || e.which] = false;
}, true);
function gameLoop() {
//left
if (keyState[37] || keyState[65]) {
if (isLegalMove(playerXPos - 1, playerYPos)) {
grid[playerXPos][playerYPos].removePlayerCell();
playerXPos -= 1;
grid[playerXPos][playerYPos].setPlayerCell();
}
}
//right
if (keyState[39] || keyState[68]) {
if (isLegalMove(playerXPos + 1, playerYPos)) {
grid[playerXPos][playerYPos].removePlayerCell();
playerXPos += 1;
grid[playerXPos][playerYPos].setPlayerCell();
}
}
//up
if (keyState[38] || keyState[87]) {
if (isLegalMove(playerXPos, playerYPos - 1)) {
grid[playerXPos][playerYPos].removePlayerCell();
playerYPos -= 1;
grid[playerXPos][playerYPos].setPlayerCell();
}
}
//down
if (keyState[40] || keyState[83]) {
if (isLegalMove(playerXPos, playerYPos + 1)) {
grid[playerXPos][playerYPos].removePlayerCell();
playerYPos += 1;
grid[playerXPos][playerYPos].setPlayerCell();
}
}
drawSurroundingCells();
setTimeout(gameLoop, 50);
}
}

Canvas diagonal movement [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I'm trying to put together a simple "game" in HTML5. However I can't get diagonal movement working.
The "diagonal movement" only works when the two buttons are pressed at exactly the same time. Even then it moves once. Here's the code:
// Getting canvas, and canvas context
var c = document.getElementById("canvas");
var ctx = c.getContext("2d");
//Keymap, later passed as method parameter
var map = [false,false,false,false];
// Top, Right, Bottom, Left
// Function for resetting keymap
var resetMap = function() {
for(i=0;i<map.length;i++) {
map[i] = false;
};
};
//Function for clearing the screen before drawing
var clrScrn = function() {
ctx.clearRect(0,0,500,500);
};
// The player character
var character = function() {
this.x = 50;
this.y = 50;
this.h = 50;
this.w = 50;
};
// Draw method of the character class
character.prototype.draw = function() {
ctx.fillRect(this.x,this.y,this.h,this.w);
};
// The move method of the character class
character.prototype.move = function(map) {
if(map[0] === true) {
if(map[1] == true) {
this.x+=5;
this.y-=5;
console.log("Pressed at the same time");
}
else {
this.y-=5;
}
}
else if(map[1] === true) {
this.x+=5;
}
else if(map[2] === true) {
this.y+=5;
}
else if(map[3] === true) {
this.x-=5;
}
};
//Making a new character
var player = new character();
player.draw();
// Drawing everything on screen
var render = function() {
clrScrn();
player.move(map);
player.draw();
resetMap();
requestAnimFrame(render);
};
//Calling the render function
render();
//Binding event listener to window,checking key down, likely the source of the problem
window.addEventListener("keydown",function(e){
if(e.keyCode == 38 && e.keyCode == 39) {
map[0] = true;
map[1] = true;
}
else if(e.keyCode == 38) {
map[0] = true;
}
if(e.keyCode == 39) {
map[1] = true;
}
if(e.keyCode == 40) {
map[2] = true;
}
if(e.keyCode == 37) {
map[3] = true;
}
console.log(e.keyCode);
},false);
//Binding event listener to key up
window.addEventListener("keyup",function(e){
resetMap();
},false);
In your render function:
player.move(map); // you move the player
player.draw(); // you draw the player
resetMap(); // you forget all pressed keys
The resetMap() is the reason you need to press the keys again in order to move just one more step.
Note that horizontal and vertical motions may accidentally work due to keyboard repeat when a key is pressed for a long time. But you shouldn't depend on key repeats for a game. You should detect key down and key up individually for individual keys in order to figure out if a key is pressed or not.
try looking at:
JavaScript multiple keys pressed at once
and then re-work your if/else logic a little bit.

Categories