I am trying to create a painting app using HTML canvas. I want to implement zoom and panning functionality to the canvas.
The user should be able to paint on the canvas, then zoom in or out(which scales the already drawn elements) and pan(which translates the elements) and then draw over them.
Currently, I am stuck at implementing zoom properly.
Solutions explored:
ctx.scale will scale the canvas but not the already painted elements. New elements are drawn with a scaled effect and away from the cursor.
Storing the canvas in another temporary canvas. Then redrawing the original canvas with scaled temporary canvas. This results in pixelation when zoomed in and so is not desired.
tempCtx.drawImage(canvas, 0, 0);
ctx.drawImage(tempCanvas, 0, 0, cw, ch, 0, 0, cw *scaleFactor, ch * scaleFactor);
CODE:
window.addEventListener('load', () => {
const canvas = document.querySelector("#canvas");
const ctx = canvas.getContext("2d");
let penColor = "#2525c5";
let brushSize = 4;
const zoomInBtn = document.querySelector("#zoom-in");
const zoomOutBtn = document.querySelector("#zoom-out");
let scaleFactor = 1;
zoomInBtn.addEventListener("click", () => {
scaleFactor = scaleFactor * 1.1;
ctx.scale(scaleFactor, scaleFactor);
});
zoomOutBtn.addEventListener("click", () => {
scaleFactor = scaleFactor * 0.9;
ctx.scale(scaleFactor, scaleFactor);
});
let painting = false;
function startPosition(e) {
painting = true;
draw(e);
}
function finishedPosition() {
painting = false;
ctx.beginPath();
}
function draw(e) {
if (!painting) return;
ctx.lineWidth = brushSize;
ctx.strokeStyle = penColor;
ctx.lineCap = "round";
let rect = e.target.getBoundingClientRect();
let x = e.clientX - rect.left;
let y = e.clientY - rect.top;
ctx.lineTo(x, y);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(x, y);
}
canvas.addEventListener("mousedown", startPosition);
canvas.addEventListener("mouseup", finishedPosition);
canvas.addEventListener("mousemove", draw);
});
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
#toolbar {
display: flex;
}
.tool-group {
display: flex;
margin-right: 40px;
}
#canvas-container {
box-sizing: border-box;
margin-top: 50px;
margin-left: 50px;
width: 500px;
height: 500px;
border: 2px solid black;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<link rel="stylesheet" href="style.css" />
<title>Drawing App</title>
</head>
<body>
<div id="app">
<div id="toolbar">
<div class="tool-group">
<button id="zoom-in">Zoom in</button>
<button id="zoom-out">Zoom out</button>
</div>
</div>
<div id="canvas-container">
<canvas id="canvas" width="500" height="500"></canvas>
</div>
</div>
<script src="canvas2.js"></script>
</body>
</html>
Related
I have an image within a canvas, I want to be to click the image and drag the image(without lifting the left mouse button) and the image at the position where the left mouse button was released. For now as soon as the mouse icon hovers over the canvas, the image moves with it, I tried to add an onclick listener event but I am sure my newbie-ness got in the way of my progress.
Here is what I had come up with so far. How can I make this work with my existing code?
var canvas = document.getElementById('customCanvas');
var context = canvas.getContext('2d');
make_base();
function make_base()
{
upload_image = new Image();
upload_image.src = 'https://lh3.googleusercontent.com/-6Zw-hozuEUg/VRF7LlCjcLI/AAAAAAAAAKQ/A61C3bhuGDs/w126-h126-p/eagle.jpg';
upload_image.onload = function(){
context.drawImage(upload_image, 0, 0);
canvas.addEventListener('click', canvas.onmousemove = function(e) {
/// correct mouse position so its relative to canvas
var rect = canvas.getBoundingClientRect(),
constantX = 0, constantY = 0,
x = e.clientX - rect.left,
y = e.clientY - rect.top;
context.clearRect(0, 0, canvas.width, canvas.height);
context.drawImage(upload_image, x, y);
});
}
}
* {
margin: 0;
padding: 0;
}
html, body {
width: 100%;
height: 100%;
}
.sidepane {
height: 100%;
background: #E8E8EA;
}
.sidepane .form {
height: 80px;
margin: 10px 0;
}
.sidepane .assets {
width: 100%;
}
#assetText {
font-size: 24px;
}
.assets .text, .assets .image {
margin: 10px 0;
}
.assets .image ul li {
width: 50px;
height: 50px;
margin-right: 5px;
float: left;
overflow: hidden;
}
.assets .image ul li img {
width: 100%;
height: 100%;
}
.canvas .block {
position: relative;
width: 600px; height: 600px;
margin: 10px;
border: 1px solid;
box-shadow: 0px 0px 5px black;
}
.item {
border: 1px solid transparent;
position: absolute;
}
.item.selected {
border-color: blue;
}
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<link href="https://fonts.googleapis.com/css?family=Montserrat" rel="stylesheet">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.0/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<div class="sidepane col-sm-2 col-md-2 col-lg-2">
<form method="post" action="/images" enctype="multipart/form-data">
<!--<div class="form">-->
<h3>Form</h3>
<input type="file" class="form-control" placeholder="Upload Your Images" name="filefield">
<button id="submit" class="btn btn-default">upload</button>
<!-- Upload Form here -->
<!--</div>-->
<hr />
<div class="assets">
<h3>Assets</h3>
<div class="text">
<h4>Text</h4>
<input type="text" name="textfield">
<button id="addText" class="btn btn-default">Add Text</button>
</div>
<div class="image">
<h4>Images</h4>
<ul class="list-unstyled">
<!-- List of images here -->
<!-- <li><img src="images/sample.jpeg" class="img-rounded" /></li> -->
</ul>
</div>
</div>
<input type="submit" >
</form>
</div>
<!-- canvas -->
<div class="canvas col-sm-8 col-md-8 col-lg-8">
<div class="block">
<!-- Add images and texts to here -->
<canvas id="customCanvas" width="598" height="598" style="border: 1px solid #000000">
</canvas>
</div>
</div>
First, you have to check if your mouse is on the image, and then check if you are trying to drag the image. To do that, you need some events, mousedown, mouseup and mousemove. To check if your mouse pointer is on the image, you have to get the X, Y, width, height of that image. Final code below.
Edit
Some more changes. Image class has no X and Y properties so I had to define variables that will store that data and make some changes to isInside function.
var canvas = document.createElement('canvas');
document.body.appendChild(canvas);
var context = canvas.getContext('2d');
canvas.width = 300;
canvas.height = 300;
var upload_image;
var imageX, imageY;
var mouseX, mouseY;
var imageDrag = false;
make_base();
canvas.addEventListener("mousemove", function (evt) {
var mousePos = getMousePos(canvas, evt);
mouseX = mousePos.x;
mouseY = mousePos.y;
});
function getMousePos(canvas, event) {
var rect = canvas.getBoundingClientRect();
return {
x: event.clientX - rect.left,
y: event.clientY - rect.top
};
}
function isInsideImage(rect) {
var pos = { x: mouseX, y: mouseY };
return pos.x > imageX && pos.x < imageX + rect.width && pos.y < imageY + rect.height && pos.y > imageY;
}
function make_base()
{
upload_image = new Image();
imageX = 0;
imageY = 0;
upload_image.onload = function(){
context.drawImage(upload_image, 0, 0);
}
upload_image.src = 'https://lh3.googleusercontent.com/-6Zw-hozuEUg/VRF7LlCjcLI/AAAAAAAAAKQ/A61C3bhuGDs/w126-h126-p/eagle.jpg';
}
canvas.addEventListener("mousedown", function (evt) {
if(isInsideImage(upload_image)) {
imageDrag = true;
}
});
canvas.addEventListener("mouseup", function (evt) {
if(imageDrag)
imageDrag = false;
});
setInterval(function() {
if(imageDrag) {
context.clearRect(0, 0, canvas.width, canvas.height);
imageX = mouseX;
imageY = mouseY;
context.drawImage(upload_image, imageX, imageY);
}
}, 1000/30);
The event you're looking for would be https://developer.mozilla.org/en/docs/Web/Events/mousedown - AFAIK (correct me if I'm wrong) but the click event would only fire when a complete click event has completed (both down and up).
Here's some sample code for this;
var mouseX;
var mouseY; // Accessible outside the function. Easier access to canvas drawing.
var canvas = ''; // Complete this to get canvas element
canvas.addEventListener("mousedown", function(mouse){
// Get mouse co-ordinates
})
Inside this event listener, you can check for your current mouse position...
var canvasElement = element.getBoundingClientRect()
mouseX = mouse.pageX - canvasElement.left;
mouseY = mouse.pageY - canvasElement.top;
Use these variables when drawing your image to the canvas to determine the image's x and y position. These should change as your mouse moves around the canvas. I.e, pass them to your make_base() function;
make_base(mouseX, mouseY)
Update your drawing function to account for them;
function make_base(mouseX, mouseY)
{
upload_image = new Image();
upload_image.src = 'https://lh3.googleusercontent.com/-6Zw-hozuEUg/VRF7LlCjcLI/AAAAAAAAAKQ/A61C3bhuGDs/w126-h126-p/eagle.jpg';
upload_image.onload = function(){
context.drawImage(upload_image, 0, 0);
canvas.addEventListener('click', canvas.onmousemove = function(e) {
/// correct mouse position so its relative to canvas
var rect = canvas.getBoundingClientRect(),
constantX = 0, constantY = 0,
x = mouseX,
y = mouseY
context.clearRect(0, 0, canvas.width, canvas.height);
context.drawImage(upload_image, x, y);
});
}
}
PLEASE NOTE that the code above is not complete, for example, the X and Y will be based on where your mouse is on the PAGE, not the CANVAS. there are separate calculations needed to account for this.
Or, you can just embed an external link under the image to take you to wherever you want!
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.
I'm trying to create an interactive app to enable users to select the shape they want by clicking on the different buttons for the shapes and then enable them to draw the shape wherever they will click on the canvas.
This part is okay but when i click on a different button to draw a shape it seems that the previous shape comes along with the new shape and seems to be overlapped.
Here's the pic:
As you see, the rectangle and the round shape becomes overlapped.
I've tried to use layers of canvas to fix it but now the rectangle button is not working and the rounded shape is not appearing where the user clicks, rather like 30px away from it.
Here's the codes:
<!DOCTYPE html>
<html>
<head>
<script>
function initiateCanvasRectangle()
{
var ctx = document.getElementById('myCanvas1').getContext('2d');
ctx.canvas.addEventListener('mousemove', function(event) {
var mouseX = event.clientX - ctx.canvas.offsetLeft;
var mouseY = event.clientY - ctx.canvas.offsetTop;
});
ctx.canvas.addEventListener('click', function(event) {
var mouseX = event.clientX - ctx.canvas.offsetLeft;
var mouseY = event.clientY - ctx.canvas.offsetTop;
ctx.fillRect(mouseX,mouseY,100,50);
ctx.fillStyle = "purple";
});
}
function initiateCanvasCircle()
{
var ctx = document.getElementById('myCanvas2').getContext('2d');
ctx.canvas.addEventListener('mousemove', function(event) {
var mouseX = event.clientX - ctx.canvas.offsetLeft;
var mouseY = event.clientY - ctx.canvas.offsetTop;
});
ctx.canvas.addEventListener('click', function(event) {
var mouseX = event.clientX - ctx.canvas.offsetLeft;
var mouseY = event.clientY - ctx.canvas.offsetTop;
ctx.beginPath();
ctx.arc(mouseX, mouseY, 30, 0, 2 * Math.PI, false);
ctx.fillStyle = 'pink';
ctx.fill();
});
}
function rect(){
window.addEventListener('click', function(event) {
initiateCanvasRectangle();
});
}
function drawRect()
{
rect();
}
function circle(){
window.addEventListener('click', function(event) {
initiateCanvasCircle();
});
}
function drawCircle()
{
circle();
}
</script>
<style>
BUTTON.rect {
padding: 8px 8px 8px 32px;
font-family: Arial, Verdana;
background-color: white;
border:2px solid black;
}
#tbl {
border-collapse:collapse;
}
</style>
</head>
<body>
<table border="1" id="tbl">
<tr><td><button class="circle" onclick="drawCircle(); return true;" style="padding:20px 40px 20px 40px;">Circle</button>
</td>
<td>
<button class="rect" onclick="drawRect(); return true;" style="padding:20px 40px 20px 40px;"></button>
</td></tr>
</table>
<p>
<div style="position: relative;">
<canvas id="myCanvas1" width="1100" height="400" style="position: absolute; left: 0; top: 0; z-index: 0; border:1px solid black"></canvas>
<canvas id="myCanvas2" width="1100" height="400" style="position: absolute; left: 0; top: 0; z-index: 1;"></canvas>
</div>
</body>
</html>
Can you tell me how to fix it? Any help will be much appreciated. Thanks.
I try to draw a circle in the middle of the device browsers width and height. But the canvas element disturb. The circle become draw in the middle of the devices width and height, if I make the canvas big enough, but the canvas size should fit in the device size.
Is there any way to fit the canvas width and height the device width and height?
thats the solution:
<html>
<head>
<meta name="viewport" content="width=device-width, height=device-height, initial-scale=1, maximum-scale=1">
<style>
/* Remove padding and margin */
* {
margin:0;
padding:0;
}
html, body, .myCanvas {
width: 100%;
height: 100%;
}
</style>
</head>
<body>
<canvas id="myCanvas" class="myCanvas"/>
<script>
var canvas = document.getElementById('myCanvas');
var width = canvas.width;
var height = canvas.height;
var context = canvas.getContext('2d');
var centerX = width / 2;
var centerY = height / 2;
var radius = 70;
context.beginPath();
context.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
context.fillStyle = 'green';
context.fill();
context.lineWidth = 5;
context.strokeStyle = '#FF3300';
context.stroke();
console.log("width: " + width);
console.log("height: " + height);
</script>
</body>
</html>
Just add this to your code, right after getting the canvas:
canvas.width = width;
canvas.height = height;
You can also remove width and height attributes from the html part
Use css % size
HTML:
<canvas id="myCanvas" class="myCanvas"/>
CSS:
/* Remove padding and margin */
* {
margin:0;
padding:0;
}
html, body, .myCanvas {
width: 100%;
height: 100%;
}
Edit:
Get the width/height of your canvas instead of the window.
<html>
<head>
<meta name="viewport" content="width=device-width, height=device-height, initial-scale=1, maximum-scale=1">
<style>
/* Remove padding and margin */
* {
margin:0;
padding:0;
}
html, body, .myCanvas {
width: 100%;
height: 100%;
}
</style>
</head>
<body>
<canvas id="myCanvas" class="myCanvas"/>
<script>
var canvas = document.getElementById('myCanvas');
var width = canvas.width;
var height = canvas.height;
var context = canvas.getContext('2d');
var centerX = width / 2;
var centerY = height / 2;
var radius = 70;
context.beginPath();
context.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
context.fillStyle = 'green';
context.fill();
context.lineWidth = 5;
context.strokeStyle = '#FF3300';
context.stroke();
console.log("width: " + width);
console.log("height: " + height);
</script>
</body>
</html>
Hello I am lilbit new to Javascript and Jquery.
i want to move earth(image) around sun(image) but i dont want to use any jQuery-plugin.
I have tried few Option but it is not working.
So If there is anyway(i guess it is) then plz answer.
Thanks in Advance
<html>
<head>
<style type="text/css">
body {
background-color: ivory;
}
canvas {
position:absolute;
left:15%;
top:5%;
margin-left:center;
margin-top:center;
background-color:black;
border:1px solid red;
}
#Aditya{
position:relative;
top:25%;
left:20%;
}
</style>
<script type="text/javascript" src="js/Jquery.js"></script>
<script type="text/javascript">
$(document).ready(function(){
var canvas = document.getElementById("icanvas");
var ctx = canvas.getContext("2d");
var radianAngle = 0;
var cx = 400;
var cy = 400;
var radius = 230;
var img = document.getElementById("myearth");
img.height="5px";
img.width="5px";
img.onload = start;
function start() {
animate();
}
function animate() {
requestAnimationFrame(animate);
// Drawing code goes here
radianAngle +=Math.PI / 120;
ctx.clearRect(0, 0, canvas.width, canvas.height);
// draw the image rotated around the circumference
ctx.save();
ctx.translate(cx, cy);
ctx.rotate(radianAngle);
ctx.drawImage(img, radius - img.width / 2, -img.height/2);
ctx.restore();
}
});
</script>
</head>
<body>
<canvas id="icanvas" width="800px" height="800px">
<img src="earth.jpg" alt="earth" id="myearth" width="50%" height="50%"></img>
<img src="sun.jpg" alt="Sun" id="Aditya"></img>
</canvas>
</canvas>
</body>
sorry for delay to upload code.only earth is moving into canvas.dont know how to put sun in center.
Thank you all to showing interest.But i finally did it.perhaps you would like to see.
<html>
<head>
<style type="text/css">
body {
background-color: ivory;
}
canvas {
position:absolute;
left:15%;
top:5%;
margin-left:center;
margin-top:center;
background-color:black;
border:1px solid red;
}
.sunimg{
position:absolute;
left:40%;
top:40%;
}
</style>
<script type="text/javascript" src="js/Jquery.js"></script>
<script type="text/javascript">
$(document).ready(function(){
$("#Aditya").addClass("sunimg");
var canvas = document.getElementById("icanvas");
var ctx = canvas.getContext("2d");
var radianAngle = 0;
var cx = 400;
var cy = 400;
var radius = 230;
var img = document.getElementById("myearth");
img.height="5px";
img.width="5px";
img.onload = start;
function start() {
animate();
}
function animate() {
requestAnimationFrame(animate);
// Drawing code goes here
radianAngle +=Math.PI / 120;
ctx.clearRect(0, 0, canvas.width, canvas.height);
// draw the image rotated around the circumference
ctx.save();
ctx.translate(cx, cy);
ctx.rotate(radianAngle);
ctx.drawImage(img, radius - img.width / 2, -img.height/2);
ctx.restore();
}
});
</script>
</head>
<body>
<canvas id="icanvas" width="800px" height="800px">
<img src="earth.jpg" alt="earth" id="myearth" width="50%" height="50%"></img>
</canvas>
<img src="sun.jpg" alt="Sun" id="Aditya"></img>
</body>