How to draw on canvas on mousedown? - html

I am looking to simply add a dot to the canvas.
I have the following code:
var canv = document.getElementById("myCanvas");
var context = canv.getContext("2d");
var radius = 5;
var putPoint = function(e){
context.beginPath();
context.arc(e.clientX, e.clientY, radius, 0, Math.PI*2);
context.fill();
}
canv.addEventListener('mousedown', putPoint);
I was learning how to do this with a video tutorial. However they were setting the canvas
as the full width/height of the browser window, whereas my canvas is on 400px * 400px and is contained within a div. I think this is the problem.
So my question is are the "e.client" parameters not working because of my canvas being only
a small part of the window?
If so, how can I track the mouse co-ordinates on my canvas?

You must adjust e.clientX/e.clientY by the offset of the canvas element.
Otherwise you're miscalculating the position of your mouse and your dot is probably being drawn outside the bounds of your canvas.
Here's your code modified to take the canvas offset into account.
var putPoint = function(e){
var BB=canvas.getBoundingClientRect();
var offsetX=BB.left;
var offsetY=BB.top;
var mouseX=e.clientX-BB.left;
var mouseY=e.clientY-BB.top;
context.beginPath();
context.arc(mouseX,mouseY,radius,0,Math.PI*2);
context.fill();
}

Related

HTML5 canvas apply color to image where shape overlays

I have this image drawn to a HTML5 canvas:
What I want to do is apply color to just a part of it.
The part where I want to apply color is defined by the following overlay image:
So, basically, I would like to guide my coloring by the overlay. So where the overlay pixels meets the main image pixels I should apply a color on the main image. At least that's how I see it working.
Notice that the overlay matches the whole image except for the lacing.
The catch is that I would like to retain the main image texture while applying the color. You can see that it has a leather texture and a "real" feel which I want to keep.
Can you please show me some methods of achieving this or share some thoughts?
Thank you!
globalCompositeOperation is your friend here.
Basically, you draw your overlay, then you set the gCO to 'source-atop' composite mode, which will make all your future drawings to only stay where there were already opaque pixels drawn, so it is important that your overlay has transparent parts.
So then you just fill a rectangle of your desired command, and finally you draw your original image, either behind, or blended to the new shape we just created.
var ctx = canvas.getContext('2d');
var loaded = 0;
function onload(){
if(++loaded === 2){
canvas.width = this.width;
canvas.height = this.height;
ctx.font = "40px sans-serif";
draw();
}
}
var original = new Image();
var overlay = new Image();
original.onload = overlay.onload = onload;
original.src = 'https://i.stack.imgur.com/vIKpI.png';
overlay.src = 'https://i.stack.imgur.com/10Tre.png';
// list of blending modes.
// Note that destination-over is a composite mode,
// which place the new drawings behind the already-there ones
var currentMode = 0;
var modes = ['destination-over', 'lighter', 'multiply', 'screen', 'overlay', 'darken',
'lighten', 'color-dodge', 'color-burn', 'hard-light', 'soft-light',
'exclusion', 'hue', 'saturation', 'color', 'luminosity' ];
function draw(){
// switch between different Blending modes
var mode = modes[currentMode];
currentMode = (currentMode+1)%(modes.length);
// clear previous
ctx.clearRect(0,0,canvas.width, canvas.height);
// draw our overlay
ctx.drawImage(overlay, 0,0);
// this will keep new drawings only where we already have existing pixels
ctx.globalCompositeOperation = 'source-atop';
ctx.fillStyle = 'red';
ctx.fillRect(0,0,canvas.width, canvas.height);
// now choose between the list of blending modes
ctx.globalCompositeOperation = mode;
// draw our original image
ctx.drawImage(original, 0,0);
// go back to default
ctx.globalCompositeOperation = 'source-over';
// just so we can know which one is shown
ctx.fillStyle = 'black';
ctx.fillText(mode, 40,40)
// do it again
setTimeout(draw, 1000)
}
canvas{
width: 100%;
}
<canvas id="canvas"></canvas>

HTML5 Canvas image resize on Chrome & easeljs

I'm struggling to make smooth image resized in canvas in Chrome. In firefox it works well, but in Chrome I'm stuck on making it smooth.
Here is the jsfiddle
http://jsfiddle.net/flashmandv/oxtrypmy/
var AVATAR_SIZE = 100;
var WHITE_BORDER_SIZE = 3;
var stage = new createjs.Stage("canvas");
var avCont = new createjs.Container();
stage.addChild(avCont);
avCont.x = avCont.y = 20;
//add white circle
var whiteBorderCircle = new createjs.Shape();
var radius = (AVATAR_SIZE+WHITE_BORDER_SIZE*2)/2;
whiteBorderCircle.graphics.beginFill("white").drawCircle(radius, radius, radius);
avCont.addChild(whiteBorderCircle);
//add avatar image mask
var avatarMask = new createjs.Shape();
avatarMask.graphics.beginFill("red").drawCircle(AVATAR_SIZE/2+WHITE_BORDER_SIZE, AVATAR_SIZE/2+WHITE_BORDER_SIZE, AVATAR_SIZE/2);
//add avatar image
var image = new Image();
image.onload = function(){
var bitmap = new createjs.Bitmap(image);
bitmap.mask = avatarMask;
var bounds = bitmap.getBounds();
bitmap.scaleX = (AVATAR_SIZE+WHITE_BORDER_SIZE*2) / bounds.width;
bitmap.scaleY = (AVATAR_SIZE+WHITE_BORDER_SIZE*2) / bounds.height;
avCont.addChild(bitmap);
stage.update();
};
image.src = 'http://files.sharenator.com/sunflowers-s800x800-423444.jpg';
Notice the jagged image
Please help
It is due to how clipping works in Chrome. Clip masks are pretty brutal in Chrome while in Firefox you get anti-aliasing along the non-straight edges.
Here is a proof-of-concept for this (run this in Chrome and in FF to see the difference):
http://jsfiddle.net/r65fcqoy/
The only way to get around this is to use composite modes instead, which basically means you need to rewrite your code unless the library you're using support this in some way.
One use of a composite mode is to use it to fill anything inside an existing drawing on the canvas.
We'll first create the filled circle we want the image to appear inside
Change comp mode to source-in and draw image
Then we go back to normal comp mode and draw the outer border
Here is an approach using vanilla JavaScript where you can control how you plug things together - this is maybe not what you're after but there is really not much option if the library as said doesn't support comp mode instead of clipping:
var canvas = document.getElementById('canvas'),
ctx = canvas.getContext('2d'),
img = new Image,
x = 70, y =70;
var AVATAR_SIZE = 100;
var WHITE_BORDER_SIZE = 3;
var radius = (AVATAR_SIZE+WHITE_BORDER_SIZE*2)/2;
img.onload = function() {
// first draw the circle for the inner image:
ctx.arc(x, y, AVATAR_SIZE*0.5, 0 , 2*Math.PI);
ctx.fill();
// now, change composite mode:
ctx.globalCompositeOperation = 'source-in';
// draw image in top
ctx.drawImage(img, x-AVATAR_SIZE*0.5, y-AVATAR_SIZE*0.5,
AVATAR_SIZE, AVATAR_SIZE);
// change back composite mode to default:
ctx.globalCompositeOperation = 'source-over';
// now draw border
ctx.beginPath();
ctx.arc(x, y, radius + 5, 0, 2*Math.PI);
ctx.closePath();
ctx.lineWidth = 10;
ctx.strokeStyle = '#ffa94e';
ctx.stroke();
};
img.src = 'http://i.stack.imgur.com/PB8lN.jpg';
<canvas id=canvas width=500 height=180></canvas>
Another solution to this would be in onload function to add another shape above the masked image to simply cover the jagged edges of the clipping mask

Different canvas sizes when using drawImage(canvas,0,0)

I have 2 canvas elements these getting its height from a parent div.
var canvas = document.getElementById("canvas");
var canvas2 = document.getElementById("canvas2");
canvas.width = canvas.width;
canvas.height = canvas.height;
canvas2.width = canvas2.width;
canvas2.height = canvas2.height;
The sizes of the canvas elements are correct in the DOM. Now i get a Problem with the drawImage() function.
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var canvas2 = document.getElementById("canvas2");
var ctx2 = canvas2.getContext("2d");
for(var i = 0;i<len;i++){
!magic drawings!
}
ctx2.drawImage(canvas, 0, 0);
The Problem is it copy the first canvas to the canvas2. When the first canvas is 150px height it only applies 150px of canvas drawing on the second canvas which is 200px height.
Any Idea or suggestion?
Edit
Ok one possible solution, but its not pretty.
ctx2.drawImage(canvas, 0, 0, canvas2.width, canvas2.height);
So the canvas gets resized. Because the width doesn't change it gets stretched regarding to the higher height. so not a perfect solution.
Use the scaling parameters of canvas context to avoid stretching
var scaleFactor=canvas2.height/canvas.height;
ctx2.drawImage(canvas,0,0,canvas.width,canvas.height,
0,0,canvas.width*scaleFactor,canvas.height*scaleFactor);

move, delete and retrieve added rectangles positions in a HTML5 canvas

I have this code below to add a rectangle to a canvas, I have some questions regarding this.
Is it possible to move the added rectangle after it has been created?
Is it possible to delete a rectangle that has been added?
Can I retrieve all added rectangles positions (x, y, width and height) after I have added a bunch of rectangles and lets say by click of a button?
<script>
function rect()
{
var canvas = document.getElementById('drawing'),
ctx = canvas.getContext('2d'),
rect = {},
drag = false;
function init() {
canvas.addEventListener('mousedown', mouseDown, false);
canvas.addEventListener('mouseup', mouseUp, false);
canvas.addEventListener('mousemove', mouseMove, false);
}
function mouseDown(e) {
rect.startX = e.pageX - this.offsetLeft;
rect.startY = e.pageY - this.offsetTop;
drag = true;
}
function mouseUp() {
drag = false;
}
function mouseMove(e) {
if (drag) {
rect.w = (e.pageX - this.offsetLeft) - rect.startX;
rect.h = (e.pageY - this.offsetTop) - rect.startY ;
//ctx.clearRect(0,0,canvas.width,canvas.height);
draw();
}
}
function draw() {
ctx.globalAlpha=0.5; // Half opacity
ctx.fillStyle= "#b0c2f7";
//ctx.fillStyle = "rgba(255, 255, 255, 0.05)";
ctx.fillRect(rect.startX, rect.startY, rect.w, rect.h);
}
init();
}
</script>
<div id="canvasDiv">
<canvas id="drawing" width="580px" height="788px" style="border:2px solid #000; background: #FFF;"></canvas>
</div>
<script>
var canvas = document.getElementById('drawing');
var context = canvas.getContext('2d');
var imageObj = new Image();
imageObj.onload = function() {
context.drawImage(imageObj, 69, 50);
};
imageObj.src = 'http://localhost/test/Images/DSC0273446.jpg';
</script>
<div id="rect">
<p><button onclick="rect();">Rectangle</button></p>
</div>
Really appreciate all help I can get in this matter, thanks!
Is it possible to move the added rectangle after it has been created?
No, once drawn it is just pixels, there is no 'rectangle object' in the canvas. The usual approach to 'moving' a shape in canvas is to clearRect() (or the whole canvas) and then fillRect() in a slightly different position in a requestAnimationFrame controlled loop.
Is it possible to delete a rectangle that has been added?
As long as you've stored the location where you drew it, you can clearRect(). Note that this clears an area of pixels, not an object - the results of previous drawing operations will not automatically reappear.
Can I retrieve all added rectangles positions (x, y, width and height) after I have added a bunch of rectangles and lets say by click of a button?
No. The canvas does not store drawn objects, only pixel image data. If you want to keep track of the objects that have been drawn then you have to do that yourself. If you want to manipulate shapes instead of pixels then there are libraries like fabric.js which add an object manipulation layer on top of canvas, or you can use an svg element instead which will let you create graphics with normal DOM methods.

How to resize the drawing of the canvas in HTML5?

I would like to resize the canvas to a smaller dimension than what it is. Here is my code:
var modelPane = document.getElementById('model_pane');
//create canvasclass="modelview"
var canvas_ = document.createElement('canvas');
canvas_.setAttribute('width', 1160);
canvas_.setAttribute('height', 500);
canvas_.setAttribute('id', 'canvas');
canvas_.setAttribute('class', 'modelview');
var ctx_ = canvas_.getContext('2d');
//draw
for (i=0;i<nodes.length;i++)
{
ctx_.strokeRect(nodes[i].x, nodes[i].y, nodes[i].width, nodes[i].height);
}
//scale
ctx_.scale(0.3,0.3);
modelPane.appendChild(canvas_);
Yet this doesn't work. Anyone know why? The canvas doesn't resize to the new dimensions.
You need to call scale first:
var ctx_ = canvas_.getContext('2d');
ctx_.scale(0.3,0.3);
//draw
for (i=0;i<nodes.length;i++)
ctx_.strokeRect(nodes[i].x, nodes[i].y, nodes[i].width, nodes[i].height);
}
Think about it, like you need to scale you canvas down. Then draw on the smaller canvas.
Example