Zoom the canvas with respect to mouse cordinates - javascript

I have a very simple application, on which I draw the image on canvas perfectly. I am translating the context by image.width/2, image.height/2 and set the destination point as -image.width/2, -image.height/2.
function draw() {
window.canvas = document.getElementById('canvas');
window.ctx = canvas.getContext('2d');
window.image = document.createElement("img");
image.onload = function() {
canvas.width = image.width;
canvas.height = image.height;
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.translate(image.width/2,image.height/2);
ctx.drawImage(image,-image.width/2,-image.height/2);
};
image.src = 'rec.JPG';
}
This is displaying the image as it supposed to be. So considering this conept that if I want to make the center point of image in center of canvas I should do this as I did above. Now, I want user to click on canvas, I am getting mouse coordinates. Then I want to scale this image and redraw the canvas such that user will see that part of the image in center (zoomed version). The code is as follow:
function zoom(evt) {
var x = getMousePos(canvas, evt).x;
var y = getMousePos(canvas, evt).y;
canvas.width = image.width;
canvas.height = image.height;
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.translate(x,y);
ctx.scale(1.5, 1.5);
ctx.drawImage(image,-x,-y);
}
function getMousePos(canvas, evt) {
var rect = canvas.getBoundingClientRect();
return {
x: evt.clientX - rect.left,
y: evt.clientY - rect.top
};
}
But I am not getting the right results somehow. I want to see the region where user clicked and then I again want to click to zoom out and thats it. I can do a later part easily but having problem with zooming the perfect region. I saw similiar questions on stackoverflow, but they aren't meeting my requirement. This is my html and css:
<style>
.container {
height: 500px;
}
.container .image-container {
height: 500px;
width: 50%;
overflow: auto;
position: absolute;
border: 1px solid;
}
img {
display: none;
}
canvas {
width: 100%;
}
</style>
<body onload="draw()">
<div class="container">
<div class="image-container">
<canvas
id="canvas"
onclick="zoom(event)"
>
</canvas>
</div>
</div>
</body>
P.S: I don't want panning. Just zoom-in and out on clicks. You can play with the snippet.
function draw() {
window.canvas = document.getElementById('canvas');
window.ctx = canvas.getContext('2d');
window.image = document.createElement("img");
window.isZoom = false;
image.onload = function() {
canvas.width = image.width;
canvas.height = image.height;
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.translate(image.width/2,image.height/2);
ctx.drawImage(image,-image.width/2,-image.height/2);
};
image.src = 'https://d85ecz8votkqa.cloudfront.net/support/help_center/Print_Payment_Receipt.JPG';
}
function zoom(evt) {
if(!isZoom) {
var x = getMousePos(canvas, evt).x;
var y = getMousePos(canvas, evt).y;
canvas.width = image.width;
canvas.height = image.height;
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.translate(x,y);
ctx.scale(2, 2);
ctx.drawImage(image,-x,-y);
canvas.style.cursor = 'zoom-out';
isZoom = true;
} else {
canvas.width = image.width;
canvas.height = image.height;
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.translate(image.width/2,image.height/2);
ctx.drawImage(image,-image.width/2,-image.height/2);
isZoom=false;
canvas.style.cursor = 'zoom-in';
}
}
function getMousePos(canvas, evt) {
var rect = canvas.getBoundingClientRect();
return {
x: evt.clientX - rect.left,
y: evt.clientY - rect.top
};
}
<style>
.container {
height: 500px;
}
.container .image-container {
height: 500px;
width: 50%;
overflow: auto;
position: absolute;
border: 1px solid;
}
img {
display: none;
}
canvas {
width: 100%;
cursor: zoom-in;
}
</style>
<body onload="draw()">
<div class="container">
<div class="image-container">
<canvas
id="canvas"
onclick="zoom(event)"
>
</canvas>
</div>
</div>
</body>

You where really close, just have to mix the scale into your drawing of the image
function draw() {
window.canvas = document.getElementById('canvas');
window.ctx = canvas.getContext('2d');
window.image = document.createElement("img");
window.isZoom = false;
image.onload = function() {
canvas.width = image.width;
canvas.height = image.height;
ctx.drawImage(image, 0,0);
};
image.src = 'https://d85ecz8votkqa.cloudfront.net/support/help_center/Print_Payment_Receipt.JPG';
}
function zoom(evt) {
canvas.width = image.width;
canvas.height = image.height;
ctx.clearRect(0, 0, canvas.width, canvas.height);
var scale = 2
if (!isZoom) {
var pos = getMousePos(canvas, evt);
ctx.scale(scale, scale);
ctx.drawImage(image, -pos.x*scale*scale, -pos.y*scale*scale);
canvas.style.cursor = 'zoom-out';
} else {
ctx.drawImage(image, 0, 0);
canvas.style.cursor = 'zoom-in';
}
isZoom = !isZoom
}
function getMousePos(canvas, evt) {
var rect = canvas.getBoundingClientRect();
return {
x: evt.clientX - rect.left,
y: evt.clientY - rect.top
};
}
.container {
height: 500px;
}
.container .image-container {
height: 500px;
width: 50%;
overflow: auto;
position: absolute;
border: 1px solid;
}
img {
display: none;
}
canvas {
width: 100%;
cursor: zoom-in;
}
<body onload="draw()">
<div class="container">
<div class="image-container">
<canvas id="canvas" onclick="zoom(event)">
</canvas>
</div>
</div>
</body>
Besides the addition of var scale I did some cleanup to your code:
var x = getMousePos(canvas, evt).x;
var y = getMousePos(canvas, evt).y;
That was kind of a wasteful double call to getMousePos

Related

can't enable scroll bar on css style overflow: scroll on <canva>s or container div

I am trying to make a long drawing canvas, but users can exit drawing mode and go to Hand scroll mode just like you normally scroll website on your phone.
I was thinking to add a scrollbar on the side of the canvas. But it would be better if we can scroll the canvas normally like we reading a website on phone.
html,css code:
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="user-scalable=no,initial-scale=1.0,maximum-scale=1.0" />
<style>
.container {
margin: 10px;
overflow: scroll;
}
#main {border: 1px solid #0000ff; overflow: scroll;}
</style>
<script src="draw.js"></script>
</head>
<body>
<div class="container">
<button id="clear">clear button that will clear teh canvas</button><br>
<canvas id="main" width="250" height="1000"></canvas>
</div>
</body>
</html>
javascript code for touch drawing:
window.onload = function() {
document.ontouchmove = function(e){ e.preventDefault(); }
var canvas = document.querySelector('#main');
// const width = canvas.width = window.innerWidth;
// const height = canvas.height = window.innerHeight;
var canvastop = canvas.offsetTop;
var context = canvas.getContext("2d");
var lastx;
var lasty;
context.strokeStyle = "#000000";
context.lineCap = 'round';
context.lineJoin = 'round';
context.lineWidth = 5;
function clear() {
context.fillStyle = "#ffffff";
context.rect(0, 0, 300, 300);
context.fill();
}
function dot(x,y) {
context.beginPath();
context.fillStyle = "#000000";
context.arc(x,y,1,0,Math.PI*2,true);
context.fill();
context.stroke();
context.closePath();
}
function line(fromx,fromy, tox,toy) {
context.beginPath();
context.moveTo(fromx, fromy);
context.lineTo(tox, toy);
context.stroke();
context.closePath();
}
canvas.ontouchstart = function(event){
event.preventDefault();
lastx = event.touches[0].clientX;
lasty = event.touches[0].clientY - canvastop;
dot(lastx,lasty);
}
canvas.ontouchmove = function(event){
event.preventDefault();
var newx = event.touches[0].clientX;
var newy = event.touches[0].clientY - canvastop;
line(lastx,lasty, newx,newy);
lastx = newx;
lasty = newy;
}
var clearButton = document.getElementById('clear')
clearButton.onclick = clear
clear()
}
I don't really understand what you'd like to do. However no need to add 'scroll' to everything.
Try this:
.container {
margin: 10px;
}
#main {
border: 1px solid #0000ff;
width: 250px;
height:600px;
overflow-y: auto
}
And then:
<canvas id="main"></canvas>
In this way your canvas will get a vertical scroll only if its contents is more than 600px, and at the same time you'll be able to scroll the page in a normal way.

HTML5 Canvas stroke not following mouse Y point

I'm writing a drawing app in HTML5 Canvas, which includes a freehand draw with the mouse.
I have a problem whereby the mouse move to draw the stroke is not under the crosshair cursor. The X co-ordinate is fine, but the Y coordinate is offset by a varying amount as the mouse pointer is moved (closer at the top of the page, drifts further away as we closer to the bottom).
It has something to do with the 'header bar' div at the top.
Here is the code.
<style>
#divContainer {
width: 100%;
height: 100%;
}
#divHeader {
position: absolute;
left: 0px;
top: 0px;
right: 0px;
height: 28px;
background-color: #333;
}
#divContentArea {
position: absolute;
left: 0px;
top: 29px;
right: 0px;
bottom: 5px;
}
#divContentCenter {
position: absolute;
top: 0px;
left: 0px;
bottom: 0px;
right:0px;
}
.canvascontainer {
position: relative;
overflow: auto;
width:100%;
height:100%;
}
.canvas {
cursor: crosshair;
width: 100%;
height: 100%;
position:absolute;
left:0px;
top:0px;
z-index: 2;
}
.maincanvas {
cursor: crosshair;
width: 100%;
height: 100%;
position:absolute;
left:0px;
top:0px;
z-index: 1;
}
</style>
<div id="divContainer">
<div id="divHeader">
The Header
</div>
<div id="divContentArea">
<div id="divContentCenter">
<div id='canvascontainer' class='canvascontainer' >
<canvas id="canvas" class='canvas'>
Sorry, your browser does not support a canvas object.
</canvas>
<canvas id="maincanvas" class='maincanvas'>
Sorry, your browser does not support a canvas object.
</canvas>
</div>
</div>
</div>
</div>
<script>
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
const canrect = canvas.getBoundingClientRect();
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
var maincanvas = document.getElementById('maincanvas');
var maincontext = maincanvas.getContext('2d');
maincanvas.width = window.innerWidth;
maincanvas.height = window.innerHeight;
var lastPoint;
var startPoint;
var isDrawing = false;
context.lineWidth = 3;
context.lineJoin = context.lineCap = 'round';
context.setLineDash([0, 0]);
context.globalAlpha = 1.0;
function drawGuideLines() {
for ( i = 0; i < canvas.height; i += 20 ) {
context.beginPath();
context.setLineDash([2, 2]);
context.lineWidth = 1;
if ( i % 60 == 0 ) {
context.lineWidth = 2;
}
context.strokeStyle = '#ccc';
context.moveTo(0,i);
context.lineTo(canvas.width,i);
context.stroke();
}
for ( i = 0; i < canvas.width; i += 20 ) {
context.beginPath();
context.setLineDash([2, 2]);
context.lineWidth = 1;
if ( i % 60 == 0 ) {
context.lineWidth = 2;
}
context.strokeStyle = '#ccc';
context.moveTo(i,0);
context.lineTo(i, canvas.height);
context.stroke();
}
}
function getMousePos(e) {
return {
x: e.offsetX - canrect.left,
y: e.offsetY + canrect.top
};
}
function clearPage() {
context.clearRect(0, 0, canvas.width, canvas.height);
}
function copyToMain () {
maincontext.drawImage(canvas, 0, 0);
clearPage();
}
canvas.onmousedown = function(e) {
isDrawing = true;
canvas.addEventListener("mousemove", drawDirectPath, false);
lastPoint = { x: e.clientX, y: e.clientY };
lastPoint = { x: e.offsetX, y: e.offsetY };
// lastPoint = { x: e.offsetX, y: e.PageY };
lastPoint = getMousePos(e);
};
function drawDirectPath(e) {
if (!isDrawing) return;
context.beginPath();
context.setLineDash([0, 0]);
context.lineWidth = 3;
context.strokeStyle = 'red';
context.fillStyle = 'red';
//show_mouse_info(e, 'GetMousePos:' + getMousePos(e).x + ', ' + getMousePos(e).y);
//show_mouse_info(e, 'boundrect:' + canrect.x + ', ' + canrect.y);
//mx = e.clientX;
//my = e.clientY;
mx = e.offsetX;
my = e.offsetY;
context.moveTo(lastPoint.x, lastPoint.y);
context.lineTo(mx, my);
context.stroke();
lastPoint = { x: mx, y: my };
}
canvas.onmouseup = function() {
isDrawing = false;
copyToMain ();
};
canvas.onmouseleave = function() {
isDrawing = false;
copyToMain ();
};
drawGuideLines();
</script>
I have tried using OffsetX/Y, PageX/Y, clinetX/Y to see if these make a difference but I cannot solve the problem.
The test, click the mouse in the top right or top left and drag/draw down diagonally to the opposite bottom corner to see the effect.
Don't give the canvas a width and height of 100% using CSS.
.canvas {
cursor: crosshair;
position:absolute;
left:0px;
top:0px;
z-index: 2;
}
Couple other things you may want to consider
Always declare variables for (let i =...
Don't make getBoundingClientRect() a const. The reason for this is if you needed to add a resize function you wouldn't be able to change the bounds because the variable holds the original bounds.
You are assigning lastPoint over and over. Not really sure what this is about.
lastPoint = { x: e.clientX, y: e.clientY };
lastPoint = { x: e.offsetX, y: e.offsetY };
// lastPoint = { x: e.offsetX, y: e.PageY };
lastPoint = getMousePos(e);

Line not drawn in the right position on the canvas

I've set up a canvas where I am drawing a line on top of an image (second canvas underneath it). The canvas is fitted into a container. My problem is that when I draw a line (two clicks needed), it is not drawn in the right place.
The goal is to be able that the line will be drawn exactly where I click, even after the canvas is resized to fit the container's size.
My code:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
<script src="/Scripts/jquery-1.10.2.min.js"></script>
</head>
<body>
<style>
.container {
position: relative;
width: 50%;
}
canvas {
max-width: 100%;
height: auto;
}
.container > canvas {
position: absolute;
top: 100px;
left: 100px;
}
.container .buttons {
position: absolute;
top: 0;
left: 0;
}
#canvas-bg {
z-index: 0;
}
#canvas-draw {
z-index: 1;
}
</style>
<div class="container">
<canvas id="canvas-draw" width="300" height="150" style="border: 1px solid #d3d3d3;">Your browser does not support the HTML5 canvas tag.</canvas>
<canvas id="canvas-bg" width="300" height="150" style="border: 1px solid #d3d3d3;">Your browser does not support the HTML5 canvas tag.</canvas>
</div>
<script>
var needFirstPoint = true;
function drawNextLine(ctx, x, y) {
if (needFirstPoint) {
ctx.lineWidth = 5;
ctx.beginPath();
ctx.moveTo(x, y);
needFirstPoint = false;
}
else {
ctx.lineTo(x, y);
ctx.stroke();
}
}
var canvasDrawing = null;
var canvasImage = null;
var ctxDrawing = null;
var ctxImage = null;
$(document).ready(function () {
canvasDrawing = $('#canvas-draw').get(0);
canvasImage = $("#canvas-bg").get(0);
if (!canvasDrawing.getContext) { return; }
ctxDrawing = canvasDrawing.getContext('2d');
ctxImage = canvasImage.getContext('2d');
function isCanvasBlank(canvas) {
var blank = document.createElement('canvas');
blank.width = canvas.width;
blank.height = canvas.height;
return canvas.toDataURL() == blank.toDataURL();
}
$('#canvas-draw').on('click', function (e) {
if (needFirstPoint == false && isCanvasBlank(canvasDrawing) == false) {
ctxDrawing.clearRect(0, 0, canvasDrawing.width, canvasDrawing.height);
needFirstPoint = true;
return false;
}
var offset = $(this).offset();
var x = e.pageX - offset.left;
var y = e.pageY - offset.top;
drawNextLine(ctxDrawing, x, y);
});
////////////
var imageLoader = document.getElementById('imageLoader');
imageLoader.addEventListener('change', handleImage, false);
function handleImage(e) {
var reader = new FileReader();
reader.onload = function (event) {
var img = new Image();
img.onload = function () {
canvasImage.width = img.width;
canvasImage.height = img.height;
ctxImage.drawImage(img, 0, 0);
// refresh drawing canvas
$('#canvas-draw').width(img.width);
$("#canvas-draw").height(img.height);
canvasDrawing = $('#canvas-draw').get(0);
ctxDrawing = canvasDrawing.getContext('2d');
canvasDrawing.width = img.width;
canvasDrawing.height = img.height;
ctxDrawing.clearRect(0, 0, canvasDrawing.width, canvasDrawing.height);
}
img.src = event.target.result;
}
reader.readAsDataURL(e.target.files[0]);
}
});
</script>
<div class="buttons">
Clear canvas
<input type="file" id="imageLoader" name="imageLoader" />
</div>
To accurately poll the pointer position on the Canvas you have to account for it's offset relative to the top-left corner of the screen - as .clientX (.pageX) and .clientY (.pageY) events return the pointer position relative to the browser window not the Canvas itself.
In plain JavaScript something like the following is often used...
/* click event handler */
function canvasClicked(e) {
var cnvBox = document.getElementById('canvas').getBoundingClientRect();
/* canvas-relative values */
var X = e.clientX - cnvBox.left,
Y = e.clientY - cnvBox.top;
}
... and the JQuery way goes something like this...
$("#canvas").click(function(e){
var cnvOffset = $(this).offset();
/* canvas-relative values */
var X = e.pageX - cnvOffset.left,
Y = e.pageY - cnvOffset.top;
});
Hoped that helped :)

Image not showing in javascript

When running my program I have an image I want to draw on the mouse's x position(clientX) and y position(clientY).
When running the program regularly by not using client x and y in the position for being drawn, it works just fine.
This is the image
//variables
var c = document.getElementById("canvas");
var ctx = c.getContext("2d");
var player = new Image();
player.src = "http://i.stack.imgur.com/P9vJm.png";
//functions
function start() {
setInterval(update, 10);
}
function update() {
clearRender();
render();
}
function clearRender() {
ctx.clearRect(0,0,1300,500);
}
function render() {
var mx = document.clientX;
var my = document.clientY;
ctx.drawImage(player, mx, my);
}
#canvas {
height: 500px;
width: 1300px;
background-color: black;
position: absolute;
left: 25px;
top: 50px;
}
body {
background-color: white;
}
<!DOCTYPE html>
<html>
<head>
<title> Space Invaders </title>
<link rel="stylesheet" type="text/css" href="invader.css">
</head>
<body>
<canvas id="canvas"> </canvas>
<script type="text/javascript" src="invader.js"></script>
</body>
</html>
To get you started, you would need an event handler to get your mouse position
c.addEventListener('mousemove', update, false);
JS:
//variables
var c = document.getElementById("canvas");
var ctx = c.getContext("2d");
var player = new Image();
player.src = "http://i.stack.imgur.com/P9vJm.png";
c.addEventListener('mousemove', update, false);
//functions
function start() {
setInterval(update, 10);
}
function update(e) {
//clearRender();
render(e);
}
function clearRender() {
ctx.clearRect(0, 0, 1300, 500);
}
function render(e) {
var pos = getMousePos(c, e);
posx = pos.x;
posy = pos.y;
ctx.drawImage(player, posx, posy);
}
function getMousePos(canvas, evt) {
var rect = canvas.getBoundingClientRect();
return {
x: evt.clientX - rect.left,
y: evt.clientY - rect.top
};
}
Here's a fiddle: https://jsfiddle.net/vwbo8k6k/
This might help you understand more about mouse positions, but I hope the image shows this time.
http://stackoverflow.com/a/17130415/2036808

Canvas Fill Page Width and Height

http://jsbin.com/oMUtePo/1/edit
I've been having a pain trying to get canvas to fill the whole page.
I tried using...
canvas.width = document.body.clientWidth;
canvas.height = document.body.clientHeight;
It filled the width, but not the height, and the drawing board was drawing 1px lines, which is not what I want.
When using 100% for width and height in CSS the width is scaled, and the height is cut, when drawing it looks as if a raster image was scaled significantly larger in ms paint and there's a large offset on onmousedown drawing which is obviously not what I want.
Any help would be greatly appreciated.
Full Code:
<!DOCTYPE html>
<head>
<meta charset="utf-8" />
<title>HTML5 Canvas Drawing Board</title>
<style>
* {
margin: 0;
padding: 0;
}
body, html {
height: 100%;
}
#myCanvas {
cursor: crosshair;
position: absolute;
width: 100%;
height: 100%;
}
</style>
<script type="text/JavaScript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js?ver=1.4.2"></script>
<script type="text/javascript">
window.onload = function() {
var myCanvas = document.getElementById("myCanvas");
var curColor = $('#selectColor option:selected').val();
var ctx = myCanvas.getContext("2d");
ctx.fillStyle="#000";
ctx.fillRect(0,0,500,500);
if(myCanvas){
var isDown = false;
var canvasX, canvasY;
ctx.lineWidth = 5;
$(myCanvas)
.mousedown(function(e){
isDown = true;
ctx.beginPath();
canvasX = e.pageX - myCanvas.offsetLeft;
canvasY = e.pageY - myCanvas.offsetTop;
ctx.moveTo(canvasX, canvasY);
})
.mousemove(function(e){
if(isDown !== false) {
canvasX = e.pageX - myCanvas.offsetLeft;
canvasY = e.pageY - myCanvas.offsetTop;
ctx.lineTo(canvasX, canvasY);
ctx.strokeStyle = "white";
ctx.stroke();
}
})
.mouseup(function(e){
isDown = false;
ctx.closePath();
});
}
};
</script>
</head>
<body>
<canvas id="myCanvas">
Sorry, your browser does not support HTML5 canvas technology.
</canvas>
</body>
</html>
You have to set the absolute size in pixels on the canvas element and not with CSS as you do in the demo, so first remove the following lines from the CSS rule:
#myCanvas {
cursor: crosshair;
position: absolute;
/*width: 100%; Remove these */
/*height: 100%;*/
}
Then add this to your code - you need to use clientWidth/Height of the window object.
myCanvas.width = window.innerWidth;
myCanvas.height = window.innerHeight;
var ctx = myCanvas.getContext("2d");
ctx.fillStyle="#000";
ctx.fillRect(0,0, myCanvas.width, myCanvas.height);
Your modified JSBIN.

Categories

Resources