my canvas drawing app won't work on mobile - javascript

I've been learning about HTML canvas lately and made a simple drawing app that works perfect on desktop. But on mobile I can't get a continuous line to draw, only single dots. any idea what I'm doing wrong? link to my codepen build
https://codepen.io/ryan-rigley/pen/oNXEvwm?fbclid=IwAR0rekoc1wcT2d4of0vCW32F0bzQDX1kW8DsJKiDq8t0ymLky1IkHyu8ozc
let color = "black";
let strokeSize = 10;
function changeColorAndSize(data, width) {
color = data;
strokeSize = width;
}
window.addEventListener("load", () => {
const canvas = document.querySelector("#canvas");
const ctx = canvas.getContext("2d");
//resizing
canvas.height = window.innerHeight;
canvas.width = window.innerWidth;
//variables
let painting = false;
//functions
function startPosition(e) {
painting = true;
draw(e);
}
function endPosition() {
painting = false;
ctx.beginPath();
}
function draw(e) {
if (!painting) {
return;
}
e.preventDefault();
ctx.lineWidth = strokeSize;
ctx.lineCap = "round";
ctx.lineTo(e.clientX, e.clientY);
ctx.stroke();
ctx.strokeStyle = color;
ctx.beginPath();
ctx.moveTo(e.clientX, e.clientY);
}
//event listeners
canvas.addEventListener("mousedown", startPosition);
canvas.addEventListener("touchstart", startPosition);
canvas.addEventListener("mouseup", endPosition);
canvas.addEventListener("touchend", endPosition);
canvas.addEventListener("mousemove", draw);
canvas.addEventListener("touchmove", draw);
});

mousemove and touchmove events have clientX and clientY differently. For mousemove event (e):
X = e.clientX and Y = e.clientY
And for touchmove event:
X = e.touches[0].clientX and Y = e.touches[0].clientY
Thus, you need to use conditional statement to find the type of event and use find X and Y accordingly. The updated code can be found below and on codepen
let color = "black";
let strokeSize = 10;
function changeColorAndSize(data, width) {
color = data;
strokeSize = width;
}
window.addEventListener("load", () => {
const canvas = document.querySelector("#canvas");
const ctx = canvas.getContext("2d");
//resizing
canvas.height = window.innerHeight;
canvas.width = window.innerWidth;
//variables
let painting = false;
//functions
function startPosition(e) {
painting = true;
draw(e);
}
function endPosition() {
painting = false;
ctx.beginPath();
}
function draw(e) {
if (!painting) {
return;
}
e.preventDefault();
ctx.lineWidth = strokeSize;
ctx.lineCap = "round";
// ctx.lineTo(e.clientX, e.clientY);
if (e.type == 'touchmove'){
ctx.lineTo(e.touches[0].clientX, e.touches[0].clientY);
} else if (e.type == 'mousemove'){
ctx.lineTo(e.clientX, e.clientY);
}
ctx.stroke();
ctx.strokeStyle = color;
ctx.beginPath();
// ctx.moveTo(e.clientX, e.clientY);
if (e.type == 'touchmove'){
ctx.moveTo(e.touches[0].clientX, e.touches[0].clientY);
} else if (e.type == 'mousemove'){
ctx.moveTo(e.clientX, e.clientY);
}
}
//event listeners
canvas.addEventListener("mousedown", startPosition);
canvas.addEventListener("touchstart", startPosition);
canvas.addEventListener("mouseup", endPosition);
canvas.addEventListener("touchend", endPosition);
canvas.addEventListener("mousemove", draw);
canvas.addEventListener("touchmove", draw);
});
body{
margin:0;
padding:0;
}
#colorButtonBox{
position:absolute;
background:rgb(210,210,210);
padding:5px;
margin:5px;
border-radius:10px;
bottom:0;
}
#colorButton {
transition: .1s linear;
position: relative;
float:left;
margin:5px;
border-radius:5px;
width: 40px;
height: 40px;
z-index: 3;
}
#eraserButton {
transition: .1s linear;
position: relative;
float:left;
margin:5px;
border-radius:50%;
width: 40px;
height: 40px;
z-index: 3;
background:white;
}
#eraserButton:hover {
width:30px;
height:30px;
margin:10px;
}
#colorButton:hover {
transition: .1s linear;
width:45px;
height:45px;
margin:2.5px;
}
.black {
background:black;
}
.blue {
background:blue;
}
.red {
background:red;
}
.green {
background:green;
}
.yellow {
background:yellow;
}
<META name="viewport" content="initial-scale=0.66, user-scalable=no">
<body>
<div id="colorButtonBox">
<div id="colorButton" class="black" onclick='changeColorAndSize("black",10)'></div>
<div id="colorButton" class="red" onclick="changeColorAndSize('red',10)"></div>
<div id="colorButton" class="green" onclick="changeColorAndSize('green',10)"></div>
<div id="colorButton" class="blue" onclick="changeColorAndSize('blue',10)"></div>
<div id="colorButton" class="yellow" onclick="changeColorAndSize('yellow',10)"></div>
<div id="eraserButton" onclick="changeColorAndSize('white',100)"></div>
</div>
<canvas id="canvas"></canvas>
</body>

I'm not sure what you mean by your app isn't working on mobile apps, so I'm going to make the assumption that you mean it isn't drawing.
My answer is based on a question answered here. It takes the touchmove event and manually creates a mousemove event with a clientX based on the touch clientX and a clientY the same way.
Here is the new code pen
Below is the altered code:
let color = "black";
let strokeSize = 10;
function changeColorAndSize(data, width) {
color = data;
strokeSize = width;
}
window.addEventListener("load", () => {
const canvas = document.querySelector("#canvas");
const ctx = canvas.getContext("2d");
//resizing
canvas.height = window.innerHeight;
canvas.width = window.innerWidth;
//variables
let painting = false;
//functions
function startPosition(e) {
painting = true;
draw(e);
}
function endPosition() {
painting = false;
ctx.beginPath();
}
function draw(e) {
if (!painting) {
return;
}
e.preventDefault();
e.stopPropagation();
ctx.lineWidth = strokeSize;
ctx.lineCap = "round";
ctx.lineTo(e.clientX, e.clientY);
ctx.stroke();
ctx.strokeStyle = color;
ctx.beginPath();
ctx.moveTo(e.clientX, e.clientY);
}
//event listeners
canvas.addEventListener("mousedown", startPosition);
canvas.addEventListener("touchstart", startPosition);
canvas.addEventListener("mouseup", endPosition);
canvas.addEventListener("touchend", endPosition);
canvas.addEventListener("mousemove", draw);
canvas.addEventListener("touchmove", function (e) {
var touch = e.touches[0];
var mouseEvent = new MouseEvent("mousemove", {
clientX: touch.clientX,
clientY: touch.clientY
});
draw(mouseEvent);
}, false);
});
body{
margin:0;
padding:0;
}
#colorButtonBox{
position:absolute;
background:rgb(210,210,210);
padding:5px;
margin:5px;
border-radius:10px;
bottom:0;
}
#colorButton {
transition: .1s linear;
position: relative;
float:left;
margin:5px;
border-radius:5px;
width: 40px;
height: 40px;
z-index: 3;
}
#eraserButton {
transition: .1s linear;
position: relative;
float:left;
margin:5px;
border-radius:50%;
width: 40px;
height: 40px;
z-index: 3;
background:white;
}
#eraserButton:hover {
width:30px;
height:30px;
margin:10px;
}
#colorButton:hover {
transition: .1s linear;
width:45px;
height:45px;
margin:2.5px;
}
.black {
background:black;
}
.blue {
background:blue;
}
.red {
background:red;
}
.green {
background:green;
}
.yellow {
background:yellow;
}
<META name="viewport" content="initial-scale=0.66, user-scalable=no">
<body>
<div id="colorButtonBox">
<div id="colorButton" class="black" onclick='changeColorAndSize("black",10)'></div>
<div id="colorButton" class="red" onclick="changeColorAndSize('red',10)"></div>
<div id="colorButton" class="green" onclick="changeColorAndSize('green',10)"></div>
<div id="colorButton" class="blue" onclick="changeColorAndSize('blue',10)"></div>
<div id="colorButton" class="yellow" onclick="changeColorAndSize('yellow',10)"></div>
<div id="eraserButton" onclick="changeColorAndSize('white',100)"></div>
</div>
<canvas id="canvas"></canvas>
</body>
I hope this helps, if you have any more questions please don't hesitate to ask : )

Related

Replicate Canvas resize in a Div

There's any way to replicate this scale behavior in a div ?
Here's an example of the behavior I wanted to reproduce within the div. I already have the movement part, and I just wanted to know about the resizing.
<!DOCTYPE HTML>
<html>
<head>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.js"></script>
<style>
body {
margin: 0px;
padding: 0px;
}
#wrapper {
position: relative;
border: 1px solid #9C9898;
width: 578px;
height: 200px;
}
#buttonWrapper {
position: absolute;
width: 30px;
top: 2px;
right: 2px;
}
input[type="button"] {
padding: 5px;
width: 30px;
margin: 0px 0px 2px 0px;
}
</style>
<script>
function draw(scale, translatePos) {
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
// clear canvas
context.clearRect(0, 0, canvas.width, canvas.height);
context.save();
context.translate(translatePos.x, translatePos.y);
context.scale(scale, scale);
context.beginPath(); // begin custom shape
context.moveTo(-119, -20);
context.bezierCurveTo(-159, 0, -159, 50, -59, 50);
context.bezierCurveTo(-39, 80, 31, 80, 51, 50);
context.bezierCurveTo(131, 50, 131, 20, 101, 0);
context.bezierCurveTo(141, -60, 81, -70, 51, -50);
context.bezierCurveTo(31, -95, -39, -80, -39, -50);
context.bezierCurveTo(-89, -95, -139, -80, -119, -20);
context.closePath(); // complete custom shape
var grd = context.createLinearGradient(-59, -100, 81, 100);
grd.addColorStop(0, "#8ED6FF"); // light blue
grd.addColorStop(1, "#004CB3"); // dark blue
context.fillStyle = grd;
context.fill();
context.lineWidth = 5;
context.strokeStyle = "#0000ff";
context.stroke();
context.restore();
}
window.onload = function() {
var canvas = document.getElementById("myCanvas");
var translatePos = {
x: canvas.width / 2,
y: canvas.height / 2
};
var scale = 1.0;
var scaleMultiplier = 0.8;
var startDragOffset = {};
var mouseDown = false;
// add button event listeners
document.getElementById("plus").addEventListener("click", function() {
scale /= scaleMultiplier;
draw(scale, translatePos);
}, false);
document.getElementById("minus").addEventListener("click", function() {
scale *= scaleMultiplier;
draw(scale, translatePos);
}, false);
// add event listeners to handle screen drag
canvas.addEventListener("mousedown", function(evt) {
mouseDown = true;
startDragOffset.x = evt.clientX - translatePos.x;
startDragOffset.y = evt.clientY - translatePos.y;
});
canvas.addEventListener("mouseup", function(evt) {
mouseDown = false;
});
canvas.addEventListener("mouseover", function(evt) {
mouseDown = false;
});
canvas.addEventListener("mouseout", function(evt) {
mouseDown = false;
});
canvas.addEventListener("mousemove", function(evt) {
if (mouseDown) {
translatePos.x = evt.clientX - startDragOffset.x;
translatePos.y = evt.clientY - startDragOffset.y;
draw(scale, translatePos);
}
});
draw(scale, translatePos);
};
jQuery(document).ready(function() {
$("#wrapper").mouseover(function(e) {
$('#status').html(e.pageX + ', ' + e.pageY);
});
})
</script>
</head>
<body onmousedown="return false;">
<div id="wrapper">
<canvas id="myCanvas" width="578" height="200">
</canvas>
<div id="buttonWrapper">
<input type="button" id="plus" value="+"><input type="button" id="minus" value="-">
</div>
</div>
<h2 id="status">
0, 0
</h2>
</body>
</html>
I tried to use css scale, but it resizes the div too, I want to modify only the space and the elements inside it.

Issue with hovering over a button in JavaScript Canvas

```
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="style.css" />
<title>Paint, Inc.</title>
</head>
<body>
<div id="sideNav">
</div>
<canvas id="canvas"></canvas>
<script src="canvas.js"></script>
<button id="clear" title="Clear">X</button>
<section id="leftBumper"></section>
<section id="colorChoice">
<input id="color" type="color" value="#000000" />
<label id="colorLabel" for="color">Color</label>
</section>
<section id="strokeWeightChoice">
<input id="strokeWeight" type="range" min="1" max="51" step="5" value="1" list="tickmarks">
<label for="strokeWeight">Thickness</label>
<datalist id="tickmarks">
<option value="1"></option>
<option value="6"></option>
<option value="11"></option>
<option value="16"></option>
<option value="21"></option>
<option value="26"></option>
<option value="31"></option>
<option value="36"></option>
<option value="41"></option>
<option value="46"></option>
<option value="51"></option>
</datalist>
</section>
</body>
</html>
```
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
#canvas {
border: 0.0001px solid white;
}
html {
overflow: hidden;
}
#clear {
position: absolute;
top: 0;
left: 0;
bottom: -10px;
width: 30px;
background: rgba(70, 70, 70, 0.32);
border: rgba(70, 70, 70, 0.32);
border-width: 5px;
font-weight: bold;
font-family: Arial, Helvetica, sans-serif;
font-size: 28px;
color: red;
}
#clear:hover {
transition: 0.4s;
background: rgba(20, 20, 20, 0.4);
cursor: pointer;
font-size: 32px;
}
#clear:focus {
outline: 0;
}
#colorChoice {
position: absolute;
bottom: 0.5rem;
right: 50%;
transform: translateX(50%);
font-family: Impact, Haettenschweiler, 'Arial Narrow Bold', sans-serif;
font-weight: bold;
}
#colorChoice:hover {
cursor: pointer;
}
#strokeWeightChoice {
position: absolute;
bottom: 3rem;
right: 50%;
transform: translateX(50%);
font-family: Impact, Haettenschweiler, 'Arial Narrow Bold', sans-serif;
font-weight: bold;
}
#strokeWeight {
width: 200px;
}
```
window.addEventListener("load", () => {
const canvas = document.querySelector("#canvas");
const ctx = canvas.getContext("2d");
const color = document.querySelector("#color");
const strokeWeight = document.querySelector("#strokeWeight");
//variables
const clearButton = document.querySelector("#clear");
let painting = false;
function startPosition(e) {
painting = true;
draw(e);
}
function finishedPosition() {
painting = false;
ctx.beginPath();
}
function draw(e) {
if (!painting) return;
ctx.lineCap = "round";
ctx.lineTo(e.clientX, e.clientY);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(e.clientX, e.clientY);
}
function changeColor(e) {
const color = e.target.value;
ctx.strokeStyle = color;
}
function changeStrokeWeight(e) {
const strokeWeight = e.target.value;
ctx.lineWidth = strokeWeight;
}
//Event listeners
canvas.addEventListener("mousedown", startPosition);
canvas.addEventListener("mouseup", finishedPosition);
canvas.addEventListener("mousemove", draw);
color.addEventListener("input", changeColor);
strokeWeight.addEventListener("input", changeStrokeWeight);
//Buttons
clearButton.addEventListener("click", clearCanvas);
function clearCanvas() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
}
});
window.addEventListener("resize", resizeCanvas);
function resizeCanvas() {
//Resizing
canvas.height = window.innerHeight;
canvas.width = window.innerWidth;
}
resizeCanvas();
On my canvas whenever I draw while hovering over a button then moving my cursor back to the canvas causes me to draw without pressing until I press again. Could someone please tell me how to fix this glitch. This glitch occurs with my clear button, thickness slider, and my color changer. In addition how do I add something to stop drawing on the clear button.
Let me know if the following change to the javascript will work for you -
When draw() is called by a Mouse Move event it won't check if painting is set to true anymore rather it will check the status of the Mouse Event to see if they are holding down the left click that way when you go off the canvas and hover over one of the buttons and come back onto the canvas it will check to see if you have the left click held down and draw if that's true
Fiddle here if it helps
You can see more about those which properties here
window.addEventListener("load", () => {
const canvas = document.querySelector("#canvas");
const ctx = canvas.getContext("2d");
const color = document.querySelector("#color");
const strokeWeight = document.querySelector("#strokeWeight");
//variables
const clearButton = document.querySelector("#clear");
let painting = false;
function startPosition(e) {
painting = true;
draw(e);
}
function finishedPosition() {
painting = false;
ctx.beginPath();
}
function draw(e) {
//if (!painting) return;
if(e.which == 1){
ctx.lineCap = "round";
ctx.lineTo(e.clientX, e.clientY);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(e.clientX, e.clientY);
}else{
finishedPosition();
}
}
function changeColor(e) {
const color = e.target.value;
ctx.strokeStyle = color;
}
function changeStrokeWeight(e) {
const strokeWeight = e.target.value;
ctx.lineWidth = strokeWeight;
}
//Event listeners
canvas.addEventListener("mousedown", startPosition);
canvas.addEventListener("mouseup", finishedPosition);
canvas.addEventListener("mousemove", draw);
color.addEventListener("input", changeColor);
strokeWeight.addEventListener("input", changeStrokeWeight);
//Buttons
clearButton.addEventListener("click", clearCanvas);
function clearCanvas() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
}
});
window.addEventListener("resize", resizeCanvas);
function resizeCanvas() {
//Resizing
canvas.height = window.innerHeight;
canvas.width = window.innerWidth;
}
resizeCanvas();

Unable to get proper position in Canvas using ES6 (why isn't this code working properly?)

I am trying make an paint app using ES6. But i am not getting proper position and line in canvas.
This line is not drawn in correct position, like top-left is formed when i click and from 0,0 corner of canvas.
As you can see Line is not starting from the point Cursor is pointing and this difference increases as we move from TOP-LEFT cornor to BOTTOM-RIGHT cornor.
const TOOL_LINE = 'line';
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
}
class Paint {
constructor(canvasId) {
this.canvas = document.getElementById(canvasId);
this.context = canvas.getContext("2d");
}
set activeTool(tool) {
this.tool = tool;
}
init() {
this.canvas.onmousedown = e => this.onMouseDown(e);
}
onMouseDown(e) {
this.saveData = this.context.getImageData(0, 0, this.canvas.clientWidth, this.canvas.clientHeight);
this.canvas.onmousemove = e => this.onMouseMove(e);
document.onmouseup = e => this.onMouseUp(e);
this.startPos = this.getMouseCoordinatesCanvas(e, this.canvas);
}
onMouseMove(e) {
this.currentPos = this.getMouseCoordinatesCanvas(e, this.canvas);
switch (this.tool) {
case TOOL_LINE:
this.drawShape();
break;
default:
break;
}
}
onMouseUp(e) {
this.canvas.onmousemove = null;
document.onmouseup = null;
}
drawShape() {
this.context.putImageData(this.saveData, 0, 0);
this.context.beginPath();
this.context.moveTo(this.startPos.x, this.startPos.y);
this.context.lineTo(this.currentPos.x, this.currentPos.y);
this.context.stroke();
}
getMouseCoordinatesCanvas(e, canvas) {
let rect = canvas.getBoundingClientRect();
let x = e.clientX - rect.left;
let y = e.clientY - rect.top;
return new Point(x, y);
}
}
var paint = new Paint("canvas");
paint.activeTool = TOOL_LINE;
paint.init();
document.querySelectorAll("[data-tools]").forEach(
item => {
item.addEventListener("click", e => {
let selectedTool = item.getAttribute("data-tools");
paint.activeTool = selectedTool;
});
}
);
#Container {
background-color: lime;
height: 310px;
}
.toolbox,
#canvas {
display: inline-block;
}
.toolbox {
background-color: gray;
padding: 0px 15px 15px 15px;
left: 10px;
top: 11px;
}
.group {
margin: 5px 2px;
}
#line {
transform: rotate(-90deg);
}
.ico {
margin: 3px;
font-size: 23px;
}
.item:hover,
.item.active {
background-color: rgba(160, 160, 160, 0.5);
color: white;
}
#canvas {
background-color: white;
margin: 5px;
float: right;
width: 400px;
height: 300px;
}
<script src="https://kit.fontawesome.com/c1d28c00bc.js" crossorigin="anonymous"></script>
<div class="container">
<div id="Container">
<div class="toolbox">
<center>
<div class="group tools">
<div class="item active" data-tools="line">
<i class="ico far fa-window-minimize" id="line" title="Line"></i>
</div>
</div>
</center>
</div>
<canvas id="canvas"></canvas>
</div>
</div>
Here is link of code.
Thanks in advance.
The issue is 1 or both of 2 things
Your canvas is being displayed at 400x300 but it only has 300x150 pixels. Canvases have 2 sizes. One size is the size they are displayed set with CSS. The other is how many pixels which is usually set in code by setting canvas.width and canvas.height. The default number of pixels is 300x150
If you actually want them to be different sizes then you need to take that into account in your mouse code. The correct code is
getMouseCoordinatesCanvas(e, canvas) {
let rect = canvas.getBoundingClientRect();
let x = (e.clientX - rect.left) * canvas.width / rect.width;
let y = (e.clientY - rect.top) * canvas.height / rect.height;
return new Point(x, y);
}
const TOOL_LINE = 'line';
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
}
class Paint {
constructor(canvasId) {
this.canvas = document.getElementById(canvasId);
this.context = canvas.getContext("2d");
}
set activeTool(tool) {
this.tool = tool;
}
init() {
this.canvas.onmousedown = e => this.onMouseDown(e);
}
onMouseDown(e) {
this.saveData = this.context.getImageData(0, 0, this.canvas.width, this.canvas.height);
this.canvas.onmousemove = e => this.onMouseMove(e);
document.onmouseup = e => this.onMouseUp(e);
this.startPos = this.getMouseCoordinatesCanvas(e, this.canvas);
}
onMouseMove(e) {
this.currentPos = this.getMouseCoordinatesCanvas(e, this.canvas);
switch (this.tool) {
case TOOL_LINE:
this.drawShape();
break;
default:
break;
}
}
onMouseUp(e) {
this.canvas.onmousemove = null;
document.onmouseup = null;
}
drawShape() {
this.context.putImageData(this.saveData, 0, 0);
this.context.beginPath();
this.context.moveTo(this.startPos.x, this.startPos.y);
this.context.lineTo(this.currentPos.x, this.currentPos.y);
this.context.stroke();
}
getMouseCoordinatesCanvas(e, canvas) {
let rect = canvas.getBoundingClientRect();
let x = (e.clientX - rect.left) * canvas.width / rect.width;
let y = (e.clientY - rect.top) * canvas.height / rect.height;
return new Point(x, y);
}
}
var paint = new Paint("canvas");
paint.activeTool = TOOL_LINE;
paint.init();
document.querySelectorAll("[data-tools]").forEach(
item => {
item.addEventListener("click", e => {
let selectedTool = item.getAttribute("data-tools");
paint.activeTool = selectedTool;
});
}
);
#Container {
background-color: lime;
height: 310px;
}
.toolbox,
#canvas {
display: inline-block;
}
.toolbox {
background-color: gray;
padding: 0px 15px 15px 15px;
left: 10px;
top: 11px;
}
.group {
margin: 5px 2px;
}
#line {
transform: rotate(-90deg);
}
.ico {
margin: 3px;
font-size: 23px;
}
.item:hover,
.item.active {
background-color: rgba(160, 160, 160, 0.5);
color: white;
}
#canvas {
background-color: white;
margin: 5px;
float: right;
width: 400px;
height: 300px;
}
<script src="https://kit.fontawesome.com/c1d28c00bc.js" crossorigin="anonymous"></script>
<div class="container">
<div id="Container">
<div class="toolbox">
<center>
<div class="group tools">
<div class="item active" data-tools="line">
<i class="ico far fa-window-minimize" id="line" title="Line"></i>
</div>
</div>
</center>
</div>
<canvas id="canvas"></canvas>
</div>
</div>
If you don't want them to be different sizes then you need to make the sizes match. I always set the size using CSS and then use code to make the canvas match that size.
Something like this
function resizeCanvasToDisplaySize(canvas) {
const width = canvas.clientWidth;
const height = canvas.clientHeight;
const needResize = canvas.width !== width || canvas.height !== height;
if (needResize) {
canvas.width = width;
canvas.height = height;
}
return needResize;
}
Note that anytime you change the canvas size it will get cleared but in any case.
const TOOL_LINE = 'line';
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
}
function resizeCanvasToDisplaySize(canvas) {
const width = canvas.clientWidth;
const height = canvas.clientHeight;
const needResize = canvas.width !== width || canvas.height !== height;
if (needResize) {
canvas.width = width;
canvas.height = height;
}
return needResize;
}
class Paint {
constructor(canvasId) {
this.canvas = document.getElementById(canvasId);
this.context = canvas.getContext("2d");
resizeCanvasToDisplaySize(canvas);
}
set activeTool(tool) {
this.tool = tool;
}
init() {
this.canvas.onmousedown = e => this.onMouseDown(e);
}
onMouseDown(e) {
this.saveData = this.context.getImageData(0, 0, this.canvas.width, this.canvas.height);
this.canvas.onmousemove = e => this.onMouseMove(e);
document.onmouseup = e => this.onMouseUp(e);
this.startPos = this.getMouseCoordinatesCanvas(e, this.canvas);
}
onMouseMove(e) {
this.currentPos = this.getMouseCoordinatesCanvas(e, this.canvas);
switch (this.tool) {
case TOOL_LINE:
this.drawShape();
break;
default:
break;
}
}
onMouseUp(e) {
this.canvas.onmousemove = null;
document.onmouseup = null;
}
drawShape() {
this.context.putImageData(this.saveData, 0, 0);
this.context.beginPath();
this.context.moveTo(this.startPos.x, this.startPos.y);
this.context.lineTo(this.currentPos.x, this.currentPos.y);
this.context.stroke();
}
getMouseCoordinatesCanvas(e, canvas) {
let rect = canvas.getBoundingClientRect();
let x = (e.clientX - rect.left) * canvas.width / rect.width;
let y = (e.clientY - rect.top) * canvas.height / rect.height;
return new Point(x, y);
}
}
var paint = new Paint("canvas");
paint.activeTool = TOOL_LINE;
paint.init();
document.querySelectorAll("[data-tools]").forEach(
item => {
item.addEventListener("click", e => {
let selectedTool = item.getAttribute("data-tools");
paint.activeTool = selectedTool;
});
}
);
#Container {
background-color: lime;
height: 310px;
}
.toolbox,
#canvas {
display: inline-block;
}
.toolbox {
background-color: gray;
padding: 0px 15px 15px 15px;
left: 10px;
top: 11px;
}
.group {
margin: 5px 2px;
}
#line {
transform: rotate(-90deg);
}
.ico {
margin: 3px;
font-size: 23px;
}
.item:hover,
.item.active {
background-color: rgba(160, 160, 160, 0.5);
color: white;
}
#canvas {
background-color: white;
margin: 5px;
float: right;
width: 400px;
height: 300px;
}
<script src="https://kit.fontawesome.com/c1d28c00bc.js" crossorigin="anonymous"></script>
<div class="container">
<div id="Container">
<div class="toolbox">
<center>
<div class="group tools">
<div class="item active" data-tools="line">
<i class="ico far fa-window-minimize" id="line" title="Line"></i>
</div>
</div>
</center>
</div>
<canvas id="canvas"></canvas>
</div>
</div>
A common reason to make them different sizes is to support HI-DPI displays. In that case though the mouse code can go back to the way it was if you use the canvas transform.
function resizeCanvasToDisplaySize(canvas) {
const width = canvas.clientWidth * devicePixelRatio | 0;
const height = canvas.clientHeight * devicePixelRatio | 0;
const needResize = canvas.width !== width || canvas.height !== height;
if (needResize) {
canvas.width = width;
canvas.height = height;
}
return needResize;
}
and then set the transform before drawing
ctx.scale(devicePixelRatio, devicePixelRatio);
const TOOL_LINE = 'line';
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
}
function resizeCanvasToDisplaySize(canvas) {
const width = canvas.clientWidth * devicePixelRatio | 0;
const height = canvas.clientHeight * devicePixelRatio | 0;
const needResize = canvas.width !== width || canvas.height !== height;
if (needResize) {
canvas.width = width;
canvas.height = height;
}
return needResize;
}
class Paint {
constructor(canvasId) {
this.canvas = document.getElementById(canvasId);
this.context = canvas.getContext("2d");
resizeCanvasToDisplaySize(canvas);
}
set activeTool(tool) {
this.tool = tool;
}
init() {
this.canvas.onmousedown = e => this.onMouseDown(e);
}
onMouseDown(e) {
this.saveData = this.context.getImageData(0, 0, this.canvas.width, this.canvas.height);
this.canvas.onmousemove = e => this.onMouseMove(e);
document.onmouseup = e => this.onMouseUp(e);
this.startPos = this.getMouseCoordinatesCanvas(e, this.canvas);
}
onMouseMove(e) {
this.currentPos = this.getMouseCoordinatesCanvas(e, this.canvas);
switch (this.tool) {
case TOOL_LINE:
this.drawShape();
break;
default:
break;
}
}
onMouseUp(e) {
this.canvas.onmousemove = null;
document.onmouseup = null;
}
drawShape() {
this.context.setTransform(1, 0, 0, 1, 0, 0); // the default
this.context.putImageData(this.saveData, 0, 0);
this.context.scale(devicePixelRatio, devicePixelRatio);
this.context.beginPath();
this.context.moveTo(this.startPos.x, this.startPos.y);
this.context.lineTo(this.currentPos.x, this.currentPos.y);
this.context.stroke();
}
getMouseCoordinatesCanvas(e, canvas) {
let rect = canvas.getBoundingClientRect();
let x = (e.clientX - rect.left);
let y = (e.clientY - rect.top);
return new Point(x, y);
}
}
var paint = new Paint("canvas");
paint.activeTool = TOOL_LINE;
paint.init();
document.querySelectorAll("[data-tools]").forEach(
item => {
item.addEventListener("click", e => {
let selectedTool = item.getAttribute("data-tools");
paint.activeTool = selectedTool;
});
}
);
#Container {
background-color: lime;
height: 310px;
}
.toolbox,
#canvas {
display: inline-block;
}
.toolbox {
background-color: gray;
padding: 0px 15px 15px 15px;
left: 10px;
top: 11px;
}
.group {
margin: 5px 2px;
}
#line {
transform: rotate(-90deg);
}
.ico {
margin: 3px;
font-size: 23px;
}
.item:hover,
.item.active {
background-color: rgba(160, 160, 160, 0.5);
color: white;
}
#canvas {
background-color: white;
margin: 5px;
float: right;
width: 400px;
height: 300px;
}
<script src="https://kit.fontawesome.com/c1d28c00bc.js" crossorigin="anonymous"></script>
<div class="container">
<div id="Container">
<div class="toolbox">
<center>
<div class="group tools">
<div class="item active" data-tools="line">
<i class="ico far fa-window-minimize" id="line" title="Line"></i>
</div>
</div>
</center>
</div>
<canvas id="canvas"></canvas>
</div>
</div>
note this line
this.saveData = this.context.getImageData(0, 0, this.canvas.clientWidth, this.canvas.clientHeight);
was wrong too. It should be
this.saveData = this.context.getImageData(0, 0, this.canvas.width, this.canvas.height);
clientWidth and clientHeight are the display size. width and height are the resolution (number of pixels in the canvas)

HTML Canvas and a little issue displaying correctly?

I'm trying to adjust the size to correctly be position more in the middle and a larger div. I would like it to be 500x500. What I'm trying to do is do a classic version of what Windows Paint is.
The issue is adjusting the 'canvas' to the middle stops the paint brush to 'draw'.
Here is the code, I have so far.
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
width: 500px;
height: 500px;
margin: auto;
top: 50%;
left: 50%;
width: 90%;
border: 3px solid #73AD21;
padding: 10px;
}
</style>
</head>
<body>
<div id="paint" >
<canvas id="myCanvas"></canvas>
</div>
<script>
var canvas = document.getElementById('myCanvas');
var ctx = canvas.getContext('2d');
var painting = document.getElementById('paint');
var paint_style = getComputedStyle(painting);
canvas.width = parseInt(paint_style.getPropertyValue('width'));
canvas.height = parseInt(paint_style.getPropertyValue('height'));
var mouse = {x: 0, y: 0};
canvas.addEventListener('mousemove', function(e) {
mouse.x = e.pageX - this.offsetLeft;
mouse.y = e.pageY - this.offsetTop;
}, false);
ctx.lineWidth = 10;
ctx.lineJoin = 'round';
ctx.lineCap = 'round';
ctx.strokeStyle = '#00CC99';
canvas.addEventListener('mousedown', function(e) {
ctx.beginPath();
ctx.moveTo(mouse.x, mouse.y);
canvas.addEventListener('mousemove', onPaint, false);
}, false);
canvas.addEventListener('mouseup', function() {
canvas.removeEventListener('mousemove', onPaint, false);
}, false);
var onPaint = function() {
ctx.lineTo(mouse.x, mouse.y);
ctx.stroke();
};
</script>
</body>
</html>
Get rid of the styling on body and replace it with this:
#paint {
height: 500px;
margin: auto;
width: 90%; /* you also had width: 500px, which one did you want? */
border: 3px solid #73AD21;
padding: 10px;
}
Fiddle - Looks like it's working okay with that change.

Unable to use the full space of canvas

I need to use the full space of canvas to draw. But here unable to use the top and left of the canvas to draw. I try make some changes in css, still no luck. Please help.
p.s. By clicking the button the canvas will popup.
<button onClick="openPopup();">click here</button>
<div id="test" class="popup">
<div class="cancel" onclick="closePopup();"></div>
<canvas id="canvas1" width="750" height="720" style="border: 1px solid black"></canvas>
</div>
<style>
.popup{
position:absolute;
top:0px;
left:0px;
margin:0px;
width: 900px;
height: 750px;
font-family:verdana;
font-size:13px;
padding:2px;
background-color:white;
border:2px solid grey;
z-index:100000000000000000;
display:none;
opacity:0.6;
filter:alpha(opacity=60);
margin-left: 300px;
margin-top: 90px;
overflow: auto;
}
.cancel{
display:relative;
cursor:pointer;
margin:0;
float:right;
height:10px;
width:14px;
padding:0 0 5px 0;
background-color:red;
text-align:center;
font-weight:bold;
font-size:11px;
color:white;
border-radius:3px;
z-index:100000000000000000;
}
.cancel:hover{
background:rgb(255,50,50);
}
</style>
<script>
function openPopup() {
document.getElementById('test').style.display = 'block';
}
function closePopup() {
document.getElementById('test').style.display = 'none';
}
var can = document.getElementById('canvas1');
var ctx = can.getContext('2d');
var isPressed = false;
var mx = 4, my = 4;
function move(e) {
getMouse(e);
if (isPressed) {
ctx.lineTo(mx, my);
ctx.stroke()
}
}
function up(e) {
getMouse(e);
isPressed = false;
}
function down(e) {
getMouse(e);
ctx.beginPath();
ctx.moveTo(mx, my);
isPressed = true;
}
can.onmousemove = move;
can.onmousedown = down;
can.onmouseup = up;
// waaaay oversimplified:
function getMouse(e) {
var element = can, offsetX = 0, offsetY = 0;
mx = e.pageX;
my = e.pageY;
}
</script>
The drawing point is not synced with mouse pointer.
That is the reason why you can't draw at the left part and the top part of the canvas, because the mouse is already out of the canvas if you try to draw something nearby the left edge.
Notice that how you get the current position of the drawing point:
function getMouse(e) {
var element = can, offsetX = 0, offsetY = 0;
mx = e.pageX;
my = e.pageY;
}
the variable e refers to mouseEvent object. and e.pageX means the distance between the mouse and the left side of the page, NOT YOUR CANVAS. So you should minus the left offset of the canvas from mx and do the same to my, so that the drawing point is right on where you want.
One simple solution:
set the canvas's margin, border and padding to 0;
.popup{
//everything else..
boder: 0;
margin-left: 0px;
margin-top: 0px;
}
Better solution:
minus the left offset to mx and my
function getMouse(e) {
var element = can, offsetX = 0, offsetY = 0;
mx = e.pageX - 305;
my = e.pageY - 95;
//Dynamically getting those padding and margin and border would be better!
}

Categories