does not support HTML5 Canvas element? - html

The following code creates a Canvas element in an HTML page,
I Have Use this code but Error is shown bellow
<canvas id="exmpl" width="300" height="300">
This is Canvas Element..
</canvas>
Using JavaScript, I have draw on the canvas:
var exmpl= document.getElementById('exmpl');
var context = example.getContext('2d');
context.fillStyle = 'red';
context.fillRect(30, 30, 50, 50);
This code draws a red rectangle on the screen.

This code is perfect always use higher level version if you use canvas tag.
var exmpl= document.getElementById('exmpl');
var context = example.getContext('2d');
context.fillStyle = 'red';
context.fillRect(30, 30, 50, 50);

Related

How can I change the prefilled data-color attribute based on a classname?

I have this code:
<canvas data-color="40,97,245">
The problem? The color is already filled in and I want to make sure the data-color changes when there is a certain classname on canvas.
The problem is that I can't change the color of it. Background-color works, but text and line colors do not change. Is there a way to do this?
So, e.g.
<canvas class="changeToBlue" data-color="#BLUE COLOR HEX">
How could I do this?
Couple things:
Setting attributes, data or otherwise, is not the right way to set colors when drawing.
The reason the CSS background-color property "works" is because the canvas element is transparent to start. Drawing color, whether for lines, texts, or shapes, is not styleable through CSS. The color property only affects DOM text, which canvas-drawn text is not.
Instead, you want to work with the 2d drawing context. To set the colors, get the drawing context then set the fillStyle or strokeStyle properties. See the MDN help page for more info on strokes and colors.
Example of setting the style:
let ctx = canvas.getContext('2d');
ctx.fillStyle = 'blue';
ctx.strokeStyle = 'blue';
Full Snippet:
function setBlues() {
let canvases = document.querySelectorAll('canvas.changeToBlue');
for (let canvas of canvases) {
let ctx = canvas.getContext('2d');
ctx.fillStyle = 'blue';
ctx.strokeStyle = 'blue';
}
}
function draw() {
let canvases = document.querySelectorAll('canvas');
for (let canvas of canvases) {
let ctx = canvas.getContext('2d');
ctx.fillText('Filled', 10, 50);
ctx.strokeText('Stroked', 10, 30);
ctx.beginPath();
ctx.moveTo(75, 50);
ctx.lineTo(100, 75);
ctx.lineTo(100, 25);
ctx.fill();
}
}
setBlues();
draw();
<canvas id="canvas" class="changeToBlue" width="150" height="150"></canvas>
<canvas id="canvas2" width="150" height="150"></canvas>
<canvas id="canvas3" class="changeToBlue" width="150" height="150" style="background-color:gold"></canvas>
You can try using jquery.
$(".changeToBlue").attr("data-color","#000000");

html5 canvas text slide in behind nothing

I want to have html5 canvas text slide in behind nothing, its an effect where text appears like coming out behind some obstacle, but the obstacle is invisible.
Here is some youtube video showing how to do it in after effect:
https://www.youtube.com/watch?v=KIYMy7vLLRo
I know how to slide a text along canvas, and one idea I got is having two canvases on top of each other, and top canvas is smaller and contains the text that is initially out of canvas and slides in. But if there is a way to do it with just one canvas that would be great.
You can using a clipping path to mask out part of the text.
Save the existing clipping path using the save() method. Create a shape/path and make it the new clipping path using the clip() method. Draw your text. Store the previous clipping path using the restore() method.
For example, suppose your canvas is 100 pixels by 100 pixels. The following will draw text on only the left side of the canvas.
context.save();
context.rect(0, 0, 50, 100);
context.clip();
context.fillText("Draw some text.", 30, 50);
context.restore();
jsFiddle : https://jsfiddle.net/CanvasCode/vgpov2yk/3
var c = document.getElementById('myCanvas');
var ctx = c.getContext("2d");
// Positions for the text startint off
var xText = -100;
var yText = 150;
// This will update the canvas as fast as possible (not good)
setInterval(function () {
// Clear the canvas
ctx.fillStyle = "#F0F";
ctx.fillRect(0, 0, c.width, c.height);
ctx.save()
// We create a clip rect
ctx.rect(200,0,400,400);
ctx.clip();
// Draw text
ctx.fillStyle = "#FFF";
ctx.font = "30px Arial";
ctx.fillText("Hello World", xText, yText);
ctx.restore();
// Increase the text x position
if (xText < 200) {
xText += 0.5;
}
}, 15);
All you have to do is use a clip rect which is like a mask in image editing.

Why toDataURL() not working when I draw image on canvas?

I have canvas and an <img> element in my page and I am simply trying to clone/copy what ever is drawn on the canvas to the img element. I don't have problem as long as I use drawing commands alone and clone the image but when I draw an image then it won't clone anything.
html:
<canvas id="canvas" width="600" height="400">Default Text (No JS)</canvas>
<img id="img" alt="This is dynamic image" src="https://www.gravatar.com/avatar/c585e7964ff782b11a41d19679e43e9d?s=48&d=identicon&r=PG&f=1" style="position:fixed;top:0;right:400px">
A simple HTML page with a canvas in the left and image element in the right side.
js:
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
var todo = 0;
drawImage(); //commenting this would clone the canvas
drawCloud();
checkAllDone();
function checkAllDone(){
if (this.todo ==0) copyCanvas();
}
function drawImage(){
this.todo++;
var img = new Image();
img.onload = function(){
context.drawImage(img,0,0,200,200);
this.todo--;
checkAllDone();
};
img.src = 'http://i.stack.imgur.com/RxFwQ.png?s=64&g=1';
}
function drawCloud(){
context.beginPath();
context.moveTo(170, 80);
context.bezierCurveTo(130, 100, 130, 150, 230, 150);
context.bezierCurveTo(250, 180, 320, 180, 340, 150);
context.bezierCurveTo(420, 150, 420, 120, 390, 100);
context.bezierCurveTo(430, 40, 370, 30, 340, 50);
context.bezierCurveTo(320, 5, 250, 20, 250, 50);
context.bezierCurveTo(200, 5, 150, 20, 170, 80);
context.closePath();
context.lineWidth = 5;
context.fillStyle = '#8ED6FF';
context.fill();
context.strokeStyle = '#0000ff';
context.stroke();
checkAllDone();
}
function copyCanvas(){
var img = document.getElementById('img');
img.src = canvas.toDataURL();
//img.src = context.getImageData();
}
Now this is very simple script where there are mainly three functions
drawImage(): This will draw an image into the context
drawCloud(): This draws a shape using drawing commands which looks like cloud
copyCanvas(): This one liner is expected to clone the image and what ever raster drawings drawon on the canvas is put as an image and works as source to the <img> element.
Twist is that when I draw both Image and Cloud, copyCanvas won't work as expected. The image element doesn't copy canvas content. Where as if I comment out drawImage then it properly copies canvas contents. Why is that?
Regarding your code, these two this are actually window:
function checkAllDone(){
if (this.todo ==0) copyCanvas();
}
function drawImage(){
this.todo++;
// ......
While the one inside img.onload is indeed img:
img.onload = function(){
context.drawImage(img,0,0,200,200);
this.todo--;
checkAllDone();
};
So window.todo (todo you declared in line 3) is always 1 when checkAllDone runs, and it obviously fails.
Read more about this, notice the difference between function context variations.
Since you have declared a global todo indicator, the simplest fix is to use todo instead of this.todo.
However, after fix you will encounter another problem:
Uncaught SecurityError: Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported.
which you could find an answer here.

Using globalCompositeOperation in few phases

I'm drawing many things on my context. Shapes, texts, images..
I want to use achieve the same effect i'm getting using the clip method on the context with globalCompositeOperation (Using the clip is harder for me to perform and i don't know if possible for texts)
The user can draw few shapes. and then start a mask phase. to draw some more shapes, texts.. which would draw into the mask and then the next draw will be clipped in the masked phase. and then continue to regular drawing...
For ex.
The user draw this drawing
Then started masked mode and drew this 2 red lines
Then he stopped drawing into the mask, and start drawing rectangle to consider the mask
And finally applied the mask clipping and the result should look like this
I've managed to clip the rectangle with the lines if there were no earlier drawings.
// Starting the mask phase
ctx.strokeStyle = 'red';
ctx.lineWidth = 5;
ctx.beginPath();
ctx.moveTo(20, 20);
ctx.lineTo(240, 140);
ctx.moveTo(80, 20);
ctx.lineTo(300, 140);
ctx.stroke();
ctx.globalCompositeOperation = 'source-out';
ctx.fillStyle = 'cyan';
ctx.fillRect(50, 70, 250, 20);
// Setting the composition back
ctx.globalCompositeOperation = 'source-over';
but when i'm adding my drawings in the beginning of the code, the composition considering it as well.
ctx.fillStyle = 'brown';
ctx.beginPath();
ctx.arc(80, 80, 50, 50, 0, Math.PI * 2);
ctx.fill();
ctx.fillStyle = 'yellow';
ctx.fillRect(80, 60, 150, 40);
ctx.fillStyle = 'black';
ctx.font = '40pt arial';
ctx.fillText('Hello', 130, 110);
// How to tell the context to start from here the compisition ???
How to tell the context to start composition from a certain point, if possible ?
I could create another canvas and draw the mask there.. and then draw the new canvas on the main canvas. But there is better solution ?
You can change the compositing mode at any point in the drawing flow by changing .globalCompositeOperation. But, as you've discovered, any new compositing mode will also affect existing canvas content.
Your intuition is correct about using a second "staging canvas" to do compositing that won't destroy your existing content.
You can use an in-memory canvas to do compositing and create your rect-with-erased-lines. Then you can drawImage this in-memory canvas to your main canvas. Since the compositing was done on your in-memory canvas, your existing circle-hello content is not undesirably affected by compositing.
Here's example code and a Demo:
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
// create an in-memory canvas to do compositing
var c=document.createElement('canvas');
var cctx=c.getContext('2d');
var img=new Image();
img.onload=start;
img.src="https://dl.dropboxusercontent.com/u/139992952/multple/temp6a.png";
function start(){
ctx.drawImage(img,0,0);
addCompositedRectangle();
ctx.drawImage(c,0,0);
}
function addCompositedRectangle(){
// resize the in-memory canvas
// Note: this automatically clears any previous content
// and also resets any previous compositing modes
c.width=300; // largest width;
c.height=140; // largest height;
// Starting the mask phase
cctx.strokeStyle = 'red';
cctx.lineWidth = 5;
cctx.beginPath();
cctx.moveTo(20, 20);
cctx.lineTo(240, 140);
cctx.moveTo(80, 20);
cctx.lineTo(300, 140);
cctx.stroke();
cctx.globalCompositeOperation = 'source-out';
cctx.fillStyle = 'cyan';
cctx.fillRect(50, 70, 250, 20);
// Setting the composition back
cctx.globalCompositeOperation = 'source-over';
}
body{ background-color: ivory; padding:10px; }
#canvas{border:1px solid red;}
<canvas id="canvas" width=300 height=300></canvas>

HTML5 Canvas, shadowColor & shadowBlur

My question is regarding this shadowBlur feature used on the 2nd (outer) rectangle below. The shadowBlur feature is applied to every shape after this rectangle. (If you comment out the shadowColor and shadowBlur lines 21 & 22, and then uncomment the shadowColor and shadowBlur lines on lines 14 & 15, you should see what I mean.) My question is, how do I apply shadowBlur to one specific portion of the Canvas drawing without applying the feature to every succeeding portion of the Canvas. In this example I have tried creating separate variable for each canvas and context, but the problem still persists.
Attribution: These examples are based on examples from html5canvastutorials.com
<!DOCTYPE html>
<html lang="en"
<head>
<script type="text/javascript">
function addRect(){
var canvas1=document.getElementById("myCanvas");
var ctx=canvas1.getContext("2d");
var canvas3=document.getElementById("myCanvas");
var ctx3=canvas3.getContext("2d");
ctx.rect(60,60,180,80);
ctx.fillStyle="green";
//ctx.shadowColor="black";
//ctx.shadowBlur = 10;
ctx.fill();
ctx3.lineWidth = 3;
ctx3.strokeStyle='red';
ctx3.shadowColor="black";
ctx3.shadowBlur = 10;
ctx3.strokeRect(45,45,210,110);
}
function addOval(){
var canvas2=document.getElementById("myCanvas");
var context=canvas2.getContext("2d");
// define center of oval
var centerX = 288;
var centerY = 250;
// define size of oval
var height = 100;
var width = 250;
var controlRectWidth = width * 1.33;
context.beginPath();
context.moveTo(centerX,centerY - height/2);
// draw left side of oval
context.bezierCurveTo(centerX-controlRectWidth/2,centerY-height/2,
centerX-controlRectWidth/2,centerY+height/2,
centerX,centerY+height/2);
// draw right side of oval
context.bezierCurveTo(centerX+controlRectWidth/2,centerY+height/2,
centerX+controlRectWidth/2,centerY-height/2,
centerX,centerY-height/2);
context.fillStyle="red";
context.fill();
context.lineWidth=5;
context.strokeStyle="blue";
context.stroke();
context.closePath();
}
</script>
</head>
<body onload="addRect(); addOval();">
<canvas id="myCanvas" width="700" height="400">
Your browser does not support the canvas element.
</canvas>
</body>
</html>
Use either this:
ctx.save();
ctx.shadowColor="black";
ctx.shadowBlur = 10;
ctx.strokeRect(45,45,210,110);
ctx.restore();
Or this:
ctx.shadowColor="black";
ctx.shadowBlur = 10;
ctx.strokeRect(45,45,210,110);
ctx.shadowColor= undefined;
ctx.shadowBlur = undefined;
I am not sure about 'undefined' in second case - something to nullify/reset the value.
var canvas3=document.getElementById("myCanvas");
var ctx3=canvas1.getContext("2d");
change canvas1 to canvas3 in the second line. Your ctx3 is actually pointing to canvas1 which i think is wrong.
You can also consider setting the shadow color to "transparent" instead of undefined or null. This also seems to do the trick.