Canvas HTML5 JavaScript code not working, with canvas.toDataURL() - javascript

I've failed to get this code working:
(function() {
// Creates a new canvas element and appends it as a child
// to the parent element, and returns the reference to
// the newly created canvas element
function createCanvas(parent, width, height) {
var canvas = {};
canvas.node = document.createElement('canvas');
canvas.context = canvas.node.getContext('2d');
canvas.node.width = width || 100;
canvas.node.height = height || 100;
parent.appendChild(canvas.node);
return canvas;
}
function init(container, width, height, fillColor) {
var canvas = createCanvas(container, width, height);
var ctx = canvas.context;
// define a custom fillCircle method
ctx.fillCircle = function(x, y, radius, fillColor) {
this.fillStyle = fillColor;
this.beginPath();
this.moveTo(x, y);
this.arc(x, y, radius, 0, Math.PI * 2, false);
this.fill();
};
ctx.clearTo = function(fillColor) {
ctx.fillStyle = fillColor;
ctx.fillRect(0, 0, width, height);
};
ctx.clearTo(fillColor || "#ddd");
// bind mouse events
canvas.node.onmousemove = function(e) {
if (!canvas.isDrawing) {
return;
}
var x = e.pageX - this.offsetLeft;
var y = e.pageY - this.offsetTop;
var radius = 10; // or whatever
var fillColor = '#ff0000';
ctx.fillCircle(x, y, radius, fillColor);
};
canvas.node.onmousedown = function(e) {
canvas.isDrawing = true;
};
canvas.node.onmouseup = function(e) {
canvas.isDrawing = false;
};
}
var container = document.getElementById('canvas');
init(container, 200, 200, '#ddd');
})();
function hi(){
var canvas = document.getElementsByTagName('canvas');
var imageData = canvas.toDataURL();
document.getElementById("his").innerHTML=imageData;
}
It's a little JavaScript code, which creates a little canvas in the div with the id of canvas.
And, I'm trying to make the image save, and write to a div with the id of his the saved image. NOW that's where the code stops working... I'd greatly appreciate your help, thanks! :)

document.getElementsByTagName('canvas') returns a NodeList, not a single element. So use
function hi(){
var canvas = document.getElementsByTagName('canvas')[0];
imageData = canvas ? canvas.toDataURL() : "could not find a <canvas> element";
document.getElementById("his").textContent = imageData;
}

Image data URLs belong in image src attributes. Images don't have innerHTML.

Related

Why my small app does not draw on smartphones?

I have this code, that is meant to allow drawing on android smartphones tablets. I use touch events. With desktop events, it works, on desktop browsers, it work. In the code, I commented out the code for desktop and I left only the code for android smartphones and tablets. Any ideas please?
Here is the HTML:
<div id="canvas">Click to draw<br/></div>
Here is the JavaScript:
(function() {
// Creates a new canvas element and appends it as a child
// to the parent element, and returns the reference to
// the newly created canvas element
function createCanvas(parent, width, height) {
var canvas = {};
canvas.node = document.createElement('canvas');
canvas.context = canvas.node.getContext('2d');
canvas.node.width = width || 100;
canvas.node.height = height || 100;
parent.appendChild(canvas.node);
return canvas;
}
function init(container, width, height, fillColor) {
var canvas = createCanvas(container, width, height);
var ctx = canvas.context;
// define a custom fillCircle method
ctx.fillCircle = function(x, y, radius, fillColor) {
this.fillStyle = fillColor;
this.beginPath();
this.moveTo(x, y);
this.arc(x, y, radius, 0, Math.PI * 2, false);
this.fill();
};
ctx.clearTo = function(fillColor) {
ctx.fillStyle = fillColor;
ctx.fillRect(0, 0, width, height);
};
ctx.clearTo(fillColor || "#ddd");
// bind mouse events
/*canvas.node.onmousemove = function(e) {
if (!canvas.isDrawing) {
return;
}
var x = e.pageX - this.offsetLeft;
var y = e.pageY - this.offsetTop;
var radius = 5; // or whatever
var fillColor = '#ff0000';
ctx.fillCircle(x, y, radius, fillColor);
};
canvas.node.onmousedown = function(e) {
canvas.isDrawing = true;
};
canvas.node.onmouseup = function(e) {
canvas.isDrawing = false;
};
*/
// bind touch events
canvas.node.ontouchmove = function(e) {
if (!canvas.isDrawing) {
return;
}
var x = e.pageX - this.offsetLeft;
var y = e.pageY - this.offsetTop;
var radius = 5; // or whatever
var fillColor = '#ff0000';
ctx.fillCircle(x, y, radius, fillColor);
};
canvas.node.ontouchstart = function(e) {
canvas.isDrawing = true;
};
canvas.node.ontouchend = function(e) {
canvas.isDrawing = false;
};
}
var container = document.getElementById('canvas');
init(container, 200, 200, '#ddd');
})();
Link to the code: https://codepen.io/sp2012/pen/gOmGZGV
It should be because of your x and y extraction
var x = e.pageX - this.offsetLeft;
var y = e.pageY - this.offsetTop;
Check this documentation for canvas touch events
I think you should access e.touches array to extract pageX and pageY info.
Here is a link where I made some changes to make it work for mobile. But it's just a hack :) . Also go through this link which has similar question.

How do I update a cloned HTML canvas element with the context and data of the original canvas?

I have written a script that allows users to draw simple lines on top of an html 5 canvas element. The ultimate goal is to have this drawing being tiled and repeated across the rest of the browser. I have gotten a cloned canvas onto the page but am struggling on how to draw the same lines simultaneously on top of multiple canvases.
I will paste my code below
var size = 40;
var md = false;
var canvas = document.getElementById('canvas');
canvas.addEventListener('mousedown', down);
canvas.addEventListener('mouseup', toggledraw);
canvas.width = 600;
canvas.height = 600;
canvas.addEventListener('mousemove', move);
function move(evt){
var mousePos = getMousePos(canvas, evt);
var posx = mousePos.x;
var posy = mousePos.y;
draw(canvas, posx, posy);
window.posx;
return mousePos;
};
function down(){
md = true;
}
function toggledraw(){
md = false;
}
function getMousePos(canvas, evt){
var rect = canvas.getBoundingClientRect();
return{
x:evt.clientX - rect.left,
y:evt.clientY - rect.top
};
};
function draw(canvas, posx, posy){
var context = canvas.getContext('2d');
if(md){
context.fillRect(posx, posy, size, size)
}
};
cloneCanvas(canvas, window.posx, window.posy, size);
function cloneCanvas(canvas, posx, posy, size,) {
console.log(posx);
var newCanvas = document.createElement('canvas');
var context = newCanvas.getContext('2d');
newCanvas.className = "newNew";
newCanvas.width = canvas.width;
newCanvas.height = canvas.height;
document.body.appendChild(newCanvas);
//context.fillRect(posx, posy, size, size)
context.drawImage(canvas, posx, posy);
return canvas;
}
The way I would go about it is to update the cloned canvas after drawing on the main canvas.
Based on your current code I would first want to return the cloned canvas instead of the old canvas. This way you have a reference to it.
function cloneCanvas(canvas, posx, posy, size,) {
...
// --> return canvas;
return newCanvas // Becomes this.
}
Next, looking at the line:
cloneCanvas(canvas, window.posx, window.posy, size);
I see that you're using your own "posx" and "posy" variables. I would get rid of those since you will always want to copy the whole canvas. (In this case). Change the line like this
var clone = cloneCanvas(canvas, 0, 0, size);
Next, I wrote a little helper function to link two canvases.
function drawFromSource(source, destination) {
return function() {
var context = destination.getContext('2d');
context.clearRect(0, 0, destination.width, destination.height);
context.drawImage(source, 0, 0);
}
}
This function returns a callback that when called draws the the orginal canvas onto a cloned canvas.
You initialize it like this:
var updateClone = drawFromSource(canvas, clone);
And last but not least you have to add the newly created callback into the draw function. Right after you draw onto your main canvas.
function draw(canvas, posx, posy) {
var context = canvas.getContext('2d');
if (md) {
context.fillRect(posx, posy, size, size)
updateClone();
}
};
Voila!
Here is a link to the working code, I shifted some of your code around.
https://jsfiddle.net/30efdvz3/5/
Just for fun. Tiled version just change "numberofTiles"
https://jsfiddle.net/30efdvz3/3/
Try this code
In this I have created a function for registering mouse event according to canvas. and call this function for all canvases.
var size = 40;
var md = false;
var canvas1 = document.getElementById('canvas');
registerEvents(canvas1)
function move(evt){
console.log(evt.target.id);
var canvas = document.getElementById(evt.target.id);
var mousePos = getMousePos(canvas, evt);
var posx = mousePos.x;
var posy = mousePos.y;
draw(canvas, posx, posy);
window.posx;
return mousePos;
};
function registerEvents(canvas){
canvas.addEventListener('mousedown', down);
canvas.addEventListener('mouseup', toggledraw);
canvas.width = 600;
canvas.height = 600;
canvas.addEventListener('mousemove', move);
}
function down(){
md = true;
}
function toggledraw(){
md = false;
}
function getMousePos(canvas, evt){
var rect = canvas.getBoundingClientRect();
return{
x:evt.clientX - rect.left,
y:evt.clientY - rect.top
};
};
function draw(canvas, posx, posy){
var context = canvas.getContext('2d');
if(md){
context.fillRect(posx, posy, size, size)
}
};
cloneCanvas(canvas, window.posx, window.posy, size);
function cloneCanvas(canvas, posx, posy, size,) {
console.log(posx);
var newCanvas = document.createElement('canvas');
var context = newCanvas.getContext('2d');
var id = "newCanvas";
newCanvas.className = "newNew";
newCanvas.id = id;
newCanvas.width = canvas.width;
newCanvas.height = canvas.height;
newCanvas.style.border = "1px solid black";
document.body.appendChild(newCanvas);
context.drawImage(canvas, posx, posy);
registerEvents(document.getElementById(id))
return canvas;
}
Here is working fiddle
Actually you were close, I have made just some changes and achieved what you desired, here is the result.
function cloneCanvas(canvas, posx, posy, size,) {
var newCanvas = document.createElement('canvas');
var context = newCanvas.getContext('2d');
...
return context; // this should return the context!
}
And,
var clonedCanvas = cloneCanvas(canvas, window.posx, window.posy, size);
// after you call the function get the 2d context to variable.
Last change is,
function draw(canvas, posx, posy){
var context = canvas.getContext('2d');
if(md){
clonedCanvas.fillRect(posx, posy, size, size); // fillRect to variable that you defined at above,
context.fillRect(posx, posy, size, size)
}
};
Jsfiddle output;
Hope helps,

Blur canvas that is full width of window without transparent edge?

I'm having some issues with an effect I'm trying to achieve using canvas and the CSS blur filter.
Essentially I need a canvas that is 100% of the height and width of the window, which can be erased to show elements sitting beneath. I am using the blur so the shapes/drawing looks blurred (this is needed).
My issue is that despite oversizing the canvas, there is still a transparent edge around the corners, which shows the elements beneath (i.e. the body with a blue background). I have tried multiple negative margin/overflow hacks, but can't seem to get around it?
I need this canvas to be the full width of the screen, blurred, and not crop in at all, but maybe this is just how CSS filters render, only what is visible?
(function() {
// make canvas larger than window
var largeWidth = window.innerWidth * 3;
var largeHeight = window.innerHeight * 3;
function createCanvas(parent, width, height) {
var canvas = {};
canvas.node = document.createElement('canvas');
canvas.context = canvas.node.getContext('2d');
canvas.node.width = largeWidth;
canvas.node.height = largeHeight;
parent.appendChild(canvas.node);
return canvas;
}
function init(container, width, height, fillColor) {
var canvas = createCanvas(container, 3000, 3000);
var ctx = canvas.context;
ctx.fillCircle = function(x, y, radius, fillColor) {
this.fillStyle = fillColor;
this.beginPath();
this.moveTo(x, y);
this.arc(x, y, radius, 0, Math.PI * 2, false);
this.fill();
};
ctx.clearTo = function(fillColor) {
ctx.fillStyle = fillColor;
ctx.fillRect(0, 0, width, height);
};
ctx.clearTo(fillColor || "#ddd");
canvas.node.onmousemove = function(e) {
var x = e.pageX - this.offsetLeft;
var y = e.pageY - this.offsetTop;
var radius = 100; // or whatever
var fillColor = '#ff0000';
ctx.globalCompositeOperation = 'destination-out';
ctx.fillCircle(x, y, radius, fillColor);
};
canvas.node.onmousedown = function(e) {
canvas.isDrawing = true;
};
}
var container = document.getElementById('canvas');
init(container, largeWidth, largeHeight, '#fff');
})();
/* CSS: */
body {
background: blue;
}
#canvas {
z-index: 1;
top: 0;
left: 0;
position: fixed;
filter: blur(10px);
-webkit-filter: blur(10px);
}
<div id = "canvas"></div>
Please see my fiddle
Thanks
Solution 1 - AKA "Ready Today"
Don't blur your canvas but blur what you put inside it; ex:
// After filling circle
context.shadowColor = color;
context.shadowBlur = 16;
context.stroke();
Here is a fiddle
Solution 2 - AKA "Tomorrow .. maybe"
Webkit is working on such feature. But I'm not sure it will work as you intend with canvas, maybe it will considere the whole canvas as "blur mask" so it will blur underneath event if content inside canvas is erased. Here is the feature :
backdrop-filter: blur(10px);
Here is some doc
ps :
I'm not sure it's necessary to wrap canvas as you did .. juste create one and edit its properties directly !
Ouch ! if you make element size 3 times bigger but don't set offset it will only be able overflow on right and bottom sides
You can remove the filter from the canvas and use a gradient brush to achieve the same.
(function() {
// make canvas larger than window
var largeWidth = window.innerWidth * 3;
var largeHeight = window.innerHeight * 3;
function createCanvas(parent, width, height) {
var canvas = {};
canvas.node = document.createElement('canvas');
canvas.context = canvas.node.getContext('2d');
canvas.node.width = largeWidth;
canvas.node.height = largeHeight;
parent.appendChild(canvas.node);
return canvas;
}
function init(container, width, height, fillColor) {
var canvas = createCanvas(container, 3000, 3000);
var ctx = canvas.context;
ctx.fillCircle = function(x, y, radius, fillColor) {
this.fillStyle = fillColor;
this.beginPath();
this.moveTo(x, y);
this.arc(x, y, radius, 0, Math.PI * 2, false);
this.fill();
};
ctx.clearTo = function(fillColor) {
ctx.fillStyle = fillColor;
ctx.fillRect(0, 0, width, height);
};
ctx.clearTo(fillColor || "#ddd");
canvas.node.onmousemove = function(e) {
var x = e.pageX - this.offsetLeft;
var y = e.pageY - this.offsetTop;
var radius = 100; // or whatever
var fillColor = '#ff0000';
var radgrad = ctx.createRadialGradient(x,y,0,x,y,radius);
radgrad.addColorStop(0, 'rgba(255,0,0,1)');
radgrad.addColorStop(0.6, 'rgba(228,0,0,.6)');
radgrad.addColorStop(1, 'rgba(228,0,0,0)');
ctx.globalCompositeOperation = 'destination-out';
ctx.fillCircle(x, y, radius, radgrad);
};
canvas.node.onmousedown = function(e) {
canvas.isDrawing = true;
};
}
var container = document.getElementById('canvas');
init(container, largeWidth, largeHeight, '#fff');
})();
/* CSS: */
body {
background: blue;
}
#canvas {
z-index: 1;
top: 0;
left: 0;
position: fixed;
}
<div id = "canvas"></div>
you should change your css as below
(function() {
var largeWidth = ( window.innerWidth * 3)+30;
var largeHeight = (window.innerHeight * 3)+30;
function createCanvas(parent, width, height) {
var canvas = {};
canvas.node = document.createElement('canvas');
canvas.context = canvas.node.getContext('2d');
canvas.node.width = largeWidth;
canvas.node.height = largeHeight;
parent.appendChild(canvas.node);
var overlay = document.getElementById("overlay");
overlay.style.width=(largeWidth -30) +"px";
overlay.style.height =( largeHeight-30)+"px";
return canvas;
}
function init(container, width, height, fillColor) {
var canvas = createCanvas(container, 3000, 3000);
var ctx = canvas.context;
ctx.fillCircle = function(x, y, radius, fillColor) {
this.fillStyle = fillColor;
this.beginPath();
this.moveTo(x, y);
this.arc(x, y, radius, 0, Math.PI * 2, false);
this.fill();
};
ctx.clearTo = function(fillColor) {
ctx.fillStyle = fillColor;
ctx.fillRect(0, 0, width, height);
};
ctx.clearTo(fillColor || "#ddd");
canvas.node.onmousemove = function(e) {
var x = e.pageX - this.offsetLeft;
var y = e.pageY - this.offsetTop;
var radius = 100; // or whatever
var fillColor = '#ff0000';
ctx.globalCompositeOperation = 'destination-out';
ctx.fillCircle(x, y, radius, fillColor);
};
canvas.node.onmousedown = function(e) {
canvas.isDrawing = true;
};
}
var container = document.getElementById('canvas');
init(container, largeWidth, largeHeight, '#fff');
})();
body {
background: blue;
}
#canvas {
margin: -15px;
filter: blur(10px);
-webkit-filter: blur(10px);
position: relative;
}
#overlay {
overflow:hidden;
position: fixed;
top: 0px;
left: 0px;
z-index: 1;
filter: unset;
-webkit-filter: unset;
}
<div id="overlay">
<div id="canvas">
</div>
</div>

Re-fill area of erased area for canvas

I am trying to fill color in image using below code snippet for filling color on Image of canvas . Its successfully filling color in canvas. Now I am trying to erase filled color on touch of user using this code snippet for erasing color on Image of canvas . Its erasing color & setting transparent area on that touched position. Now I want to refill that area on user touch with colors but its not allowing me to color on that because of transparent pixels. So Is there any way to refill pixels with color Or Is there any other way to erase color from image of canvas ? Any reply will be appreciated.
code snippet for filling color on Image of canvas
var ctx = canvas.getContext('2d'),
img = new Image;
img.onload = draw;
img.crossOrigin = 'anonymous';
img.src = "https://dl.dropboxusercontent.com/s/1alt1303g9zpemd/UFBxY.png";
function draw(color) {
ctx.drawImage(img, 0, 0);
}
canvas.onclick = function(e){
var rect = canvas.getBoundingClientRect();
var x = e.clientX-rect.left,
y = e.clientY-rect.top;
ctx.globalCompositeOperation = 'source-atop';
ctx.fillStyle = 'blue';
ctx.beginPath();
ctx.arc(x-5,y-5,10,0,2*Math.PI);
ctx.fill();
}
code snippet for erasing color on Image of canvas
(function() {
// Creates a new canvas element and appends it as a child
// to the parent element, and returns the reference to
// the newly created canvas element
function createCanvas(parent, width, height) {
var canvas = {};
canvas.node = document.createElement('canvas');
canvas.context = canvas.node.getContext('2d');
canvas.node.width = width || 100;
canvas.node.height = height || 100;
parent.appendChild(canvas.node);
return canvas;
}
function init(container, width, height, fillColor) {
var canvas = createCanvas(container, width, height);
var ctx = canvas.context;
// define a custom fillCircle method
ctx.fillCircle = function(x, y, radius, fillColor) {
this.fillStyle = fillColor;
this.beginPath();
this.moveTo(x, y);
this.arc(x, y, radius, 0, Math.PI * 2, false);
this.fill();
};
ctx.clearTo = function(fillColor) {
ctx.fillStyle = fillColor;
ctx.fillRect(0, 0, width, height);
};
ctx.clearTo(fillColor || "#ddd");
// bind mouse events
canvas.node.onmousemove = function(e) {
if (!canvas.isDrawing) {
return;
}
var x = e.pageX - this.offsetLeft;
var y = e.pageY - this.offsetTop;
var radius = 10; // or whatever
var fillColor = '#ff0000';
ctx.globalCompositeOperation = 'destination-out';
ctx.fillCircle(x, y, radius, fillColor);
};
canvas.node.onmousedown = function(e) {
canvas.isDrawing = true;
};
canvas.node.onmouseup = function(e) {
canvas.isDrawing = false;
};
}
var container = document.getElementById('canvas');
init(container, 531, 438, '#ddd');
})();
Warning untested code!
// create a clipping region using your erasing rect's x,y,width,height
context.save();
context.beginPath();
context.rect(erasingRectX,erasingRectY,erasingRectWidth,erasingRectHeight);
context.clip();
// redraw the original image.
// the image will be redrawn only into the erasing rects boundary
context.drawImage(yourImage,0,0);
// compositing: new pixels draw only where overlapping existing pixels
context.globalCompositeOperation='source-in';
// fill with your new color
// only the existing (clipped redrawn image) pixels will be colored
context.fillStyle='red';
context.fillRect(0,0,canvas.width,canvas.height);
// undo the clipping region
context.restore();

How can I make my mouseup and mousedown functions work with touchscreen phones?

I have a canvas square over a background image, the idea is users can use it as a lottery ticket style scratcher. Currently users can use the mouse and click over the canvas to erase the square and this works. However when I try to touch the canvas in a mobile browser, the erase tool does not work and all I do is move the browser around.
Here is the code.
(function() {
// Creates a new canvas element and appends it as a child
// to the parent element, and returns the reference to
// the newly created canvas element
function createCanvas(parent, width, height) {
var canvas = {};
canvas.node = document.createElement('canvas');
canvas.context = canvas.node.getContext('2d');
canvas.node.width = width || 100;
canvas.node.height = height || 100;
parent.appendChild(canvas.node);
return canvas;
}
function init(container, width, height, fillColor) {
var canvas = createCanvas(container, width, height);
var ctx = canvas.context;
// define a custom fillCircle method
ctx.fillCircle = function(x, y, radius, fillColor) {
this.fillStyle = fillColor;
this.beginPath();
this.moveTo(x, y);
this.arc(x, y, radius, 0, Math.PI * 3, false);
this.fill();
};
ctx.clearTo = function(fillColor) {
ctx.fillStyle = fillColor;
ctx.fillRect(0, 0, width, height);
};
ctx.clearTo(fillColor || "#ddd");
// bind mouse events
canvas.node.onmousemove = function(e) {
if (!canvas.isDrawing) {
return;
}
var x = e.pageX - this.offsetLeft;
var y = e.pageY - this.offsetTop;
var radius = 20; // or whatever
var fillColor = '#ff0000';
ctx.globalCompositeOperation = 'destination-out';
ctx.fillCircle(x, y, radius, fillColor);
};
canvas.node.onmousedown = function(e) {
canvas.isDrawing = true;
};
canvas.node.onmouseup = function(e) {
canvas.isDrawing = false;
};
}
var container = document.getElementById('canvas');
init(container, 274, 308, '#ddd');
})();
Your canvas is only listening to mouse events. You should bind the browsers touch event too. Depends on the mobile browser it the way you do that it may be a little bit different. Here are some good resources you can start with:
https://developer.mozilla.org/en-US/docs/Web/API/Touch_events
https://developer.apple.com/library/mac/documentation/AppleApplications/Reference/SafariWebContent/HandlingEvents/HandlingEvents.html
You are looking for touchstart (here) and touchend (here) events.
Be aware that the pageX and pageY of these can be a little tricky.
Here is a function I have used in the past to get these coordinates across the browsers - even mobile Safari. Just pass in the event to this to get the coordinates more reliably if you have trouble with them.
function getPageXAndY(evt) {
var pageX = evt.pageX;
if (!pageX) {
if (evt.originalEvent && evt.originalEvent.touches) {
pageX = evt.originalEvent.touches[0].pageX;
}
else if (evt.touches && evt.touches.length > 0) {
pageX = evt.touches[0].pageX;
}
}
var pageY = evt.pageY;
if (!pageY) {
if (evt.originalEvent && evt.originalEvent.touches) {
pageY = evt.originalEvent.touches[0].pageY;
}
else if (evt.touches && evt.touches.length > 0) {
pageY = evt.touches[0].pageY;
}
}
return [pageX, pageY];
};
Called like:
canvas.node.ontouchend = function(e) {
pageCoords = getPageXAndY(e); // returns [pageXVal, pageYVal]
...
}

Categories

Resources