When I run it the browser loads for a while and then displays the whole canvas. How can I make it display as soon as it finishes one loop iteration?And why is this code not doing what I expect it to?
This is my code:
for(var i=0;i<50;i++){
for(var j=0;j<50;j++){
ctx.beginPath();
ctx.fillRect(10*j, 10*i, 10, 10);
ctx.fillStyle = 'rgb('+parseInt(Math.random()*255)+','+parseInt(Math.random()*255)+','+parseInt(Math.random()*255)+')';
ctx.fill();
ctx.closePath();
sleep(10);
}
}
function sleep(milliseconds) {
var start = new Date().getTime();
for (var i = 0; i < 1e7; i++) {
if ((new Date().getTime() - start) > milliseconds){
break;
}
}
}
OK... I managed to achieve the desired effect using
window.requestAnimationFrame(draw);
However can someone please explain why the code above behaves the way it does? Why does it draw all 2500 shapes before it displays the canvas?
Use requestAnimationFrame
Here's code and a Fiddle: http://jsfiddle.net/m1erickson/NRBy5/
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<style>
body{ background-color: ivory; }
canvas{border:1px solid red;}
</style>
<script>
$(function(){
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var RAF;
var i=0;
var j=0;
function animate() {
// draw stuff
ctx.beginPath();
ctx.fillRect(10*j, 10*i, 10, 10);
ctx.fillStyle = 'rgb('+parseInt(Math.random()*255)+','+parseInt(Math.random()*255)+','+parseInt(Math.random()*255)+')';
ctx.fill();
ctx.closePath();
// update
j+=1;
console.log(i+"/"+j);
if(j>=50){
i+=1;
j=0;
if(i>=50){
cancelAnimationFrame(RAF);
}
}
// request new frame
RAF=requestAnimationFrame(function() { animate(); });
}
animate();
}); // end $(function(){});
</script>
</head>
<body>
<canvas id="canvas" width=300 height=300></canvas>
</body>
</html>
Related
I am trying to cut certain pattern from file based canvas and i need multiple geometrical shapes used.
For that, i am drawing shapes on that canvas using globalCompositeOperation set to XOR.
$( document ).ready(function() {
var ctx = document.getElementById('canvas').getContext('2d');
var img = new Image();
img.src = 'http://cimsec.org/wp-content/uploads/2014/01/adriatic-sea-horizon-igor-voljc.jpg';
var width = img.naturalWidth/2; // this will be 300
var height = img.naturalHeight/2; // this will be 400
document.getElementById('canvas').width = width;
document.getElementById('canvas').height = height;
img.onload = function() {
ctx.drawImage(img, 0,0, width, height);
}
ctx.globalCompositeOperation = "xor";
function circle(x, y, radius)
{
ctx.arc(x, y, radius, 0, 2 * Math.PI, false);
ctx.fill();
}
var iks = width/2;
var sr = width/5;
var igrek = (sr);
circle(iks,igrek,sr);
var igrek2 = 3.5*sr;
circle(iks,igrek2,sr);
});
.lw { font-size: 60px; }
body {background-color:blue}
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="http://code.jquery.com/jquery-latest.min.js"></script>
<title>HTML5, CSS3 and JavaScript demo</title>
</head>
<body>
<!-- Start your code here -->
<canvas id="canvas"></canvas>
<!-- End your code here -->
</body>
</html>
Unfortunetly, it does not work correctly if i try cut more than one shape. On example on litewave only second shape is cut correctly, first one only has its perimeter cut.
Ultimately i plan to have ths shape cut from image, white area on this jpg example shoudl be transparent:
http://www.detroitbodyproducts.com/media/wysiwyg/hide.jpg
Is there any better way to do this?
You need to call ctx.beginPath(); first, or else it doesn't work:
$( document ).ready(function() {
var ctx = document.getElementById('canvas').getContext('2d');
var img = new Image();
img.src = 'http://cimsec.org/wp-content/uploads/2014/01/adriatic-sea-horizon-igor-voljc.jpg';
var width = img.naturalWidth/2; // this will be 300
var height = img.naturalHeight/2; // this will be 400
document.getElementById('canvas').width = width;
document.getElementById('canvas').height = height;
img.onload = function() {
ctx.drawImage(img, 0,0, width, height);
}
ctx.globalCompositeOperation = "xor";
function circle(x, y, radius)
{
ctx.beginPath();
ctx.arc(x, y, radius, 0, 2 * Math.PI, false);
ctx.fill();
}
var iks = width/2;
var sr = width/5;
var igrek = (sr);
circle(iks,igrek,sr);
var igrek2 = 3.5*sr;
circle(iks,igrek2,sr);
});
.lw { font-size: 60px; }
body {background-color:blue}
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="http://code.jquery.com/jquery-latest.min.js"></script>
<title>HTML5, CSS3 and JavaScript demo</title>
</head>
<body>
<!-- Start your code here -->
<canvas id="canvas"></canvas>
<!-- End your code here -->
</body>
</html>
Is it possible to wrap a text around an image inside an HTML 5 Canvas? For example using some Javascript framework? I looked into KineticJS, but couldn't find something useful.
Edit:
It seems my question is unclear. I'm looking for something lke this :
http://www.monkeydoit.com/images/panda2.gif
You can wrap text around an image (rectangle) using canvas transforms (translate+rotate)
For example, this is how you rotate the canvas and draw text down the right side of your image:
// save the untransformed state of the context
ctx.save();
// translate to the top-right corner of the image
// ( x/y properties have been added to the standard img element )
ctx.translate(image.x+image.width,image.y);
// rotate the canvas 90 degrees (PI/2 radians)
ctx.rotate(Math.PI/2);
// the canvas is now properly moved and rotated
// so we can just draw the text at [0,0]
ctx.fillText(subtext,0,0);
// restore the context to its untransformed state
ctx.restore();
This calculates how many words fit on a side using context.measureText:
var end=0;
var subtext="";
while(ctx.measureText(text.split(" ",end+1).join(" ")).width<=length)
{
subtext=text.split(" ",end+1).join(" ");
end++;
}
An interesting enhancement would be to draw text around a rectangle with rounded corners.
Here is code and a Fiddle: http://jsfiddle.net/m1erickson/U2hE3/
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<style>
body{ background-color: ivory; padding:10px; }
canvas{border:1px solid red;}
</style>
<script>
$(function(){
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var rect={x:40,y:40,width:150,height:120};
var text="This is some text that wraps on the outside of a rectangle.";
var font="14px Verdana";
drawTextAroundRect(rect,text,7,font);
function drawTextAtAngle(text,length,x,y,radians){
// if text is empty then return
if(text.length==0){return;}
var end=0;
var subtext="";
if(ctx.measureText(text).width<=length){
// all the text fits
subtext=text;
}else{
// calc how many words will fit on this length
while(ctx.measureText(text.split(" ",end+1).join(" ")).width<=length)
{
subtext=text.split(" ",end+1).join(" ");
end++;
}
}
// draw the text at the appropriate angle
ctx.save();
ctx.translate(x,y);
ctx.rotate(radians);
ctx.fillText(subtext,0,0);
ctx.restore();
// return any text that didn't fit for further processing
if(end==text.length){
return("");
}else{
return(text.substr(subtext.length));
}
}
function drawTextAroundRect(rect,text,textPadding,font){
// set the font
ctx.font=font;
// top
text=drawTextAtAngle(text,rect.width,rect.x,rect.y-textPadding,0);
// right
text=drawTextAtAngle(text,rect.height,rect.x+rect.width+textPadding,rect.y,Math.PI/2);
// bottom
text=drawTextAtAngle(text,rect.width,rect.x+rect.width,rect.y+rect.height+textPadding,Math.PI);
// left
text=drawTextAtAngle(text,rect.height,rect.x-textPadding,rect.y+rect.height,Math.PI*1.5);
// draw the rect (just for illustration)
ctx.beginPath();
ctx.rect(rect.x,rect.y,rect.width,rect.height);
ctx.stroke();
}
}); // end $(function(){});
</script>
</head>
<body>
<canvas id="canvas" width=300 height=250></canvas>
</body>
</html>
[ Add more word-wrap code given questioners clarification ]
You can use context.measureText to get the width of text and use that to wrap text around an image.
Given text width you can build a word-wrap by advancing to the next line when text exceeds your desired width.
In the case of wrapping around a picture, you will have 2 desired widths—shorter while the text might run into the image and longer after that.
Here is code and a Fiddle: http://jsfiddle.net/m1erickson/XM5Yp/
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<style>
body{ background-color: ivory; }
canvas{border:1px solid red;}
</style>
<script>
$(function(){
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var maxWidth = 350;
var lineHeight = 25;
var x = (canvas.width - maxWidth) / 2;
var y = 60;
var text = "'Twas the night before Christmas, when all through the house. Not a creature was stirring, not even a mouse. The stockings were hung by the chimney with care in hopes that St. Nicholas soon would be there.";
ctx.font = '16pt Calibri';
ctx.fillStyle = '#333';
var imgWidth;
var imgHeight;
var img=new Image();
img.onload=function(){
imgWidth=img.width;
imgHeight=img.height;
ctx.drawImage(img,canvas.width-img.width,0)
wrapText(text, x, y, maxWidth, lineHeight);
}
img.src="https://dl.dropboxusercontent.com/u/139992952/stackoverflow/house204-1.jpg";
function wrapText(text, x, y, maxWidth, lineHeight) {
var words = text.split(' ');
var line = '';
var maxLineWidth=y>imgHeight+10?maxWidth:maxWidth-imgWidth;
for(var n = 0; n < words.length; n++) {
var testLine = line + words[n] + ' ';
var metrics = ctx.measureText(testLine);
var testWidth = metrics.width;
if(testWidth > maxLineWidth) {
ctx.fillText(line, x, y);
line = words[n] + ' ';
y += lineHeight;
maxLineWidth= y>imgHeight+10?maxWidth:maxWidth-imgWidth;
}
else {
line = testLine;
}
}
ctx.fillText(line, x, y);
}
}); // end $(function(){});
</script>
</head>
<body>
<canvas id="canvas" width=400 height=325></canvas>
</body>
</html>
I am trying to mimic one of the demos on gauge.js' website without luck. I am trying to figure out how to create a gauge that is actually almost full circle. Half circle gauge won't work for what I need it for. Any ideas?
This is what I have at the moment but it renders a half gauge.
$( document ).ready(function() {
var opts = {
lines: 12, // The number of lines to draw
angle: 0, // The length of each line
lineWidth: 0.0001, // The line thickness
pointer: {
length: 0.9, // The radius of the inner circle
strokeWidth: 0.035, // The rotation offset
color: '#000' // Fill color
},
colorStart: '#FFF', // Colors
colorStop: '#FFF', // just experiment with them
strokeColor: '#E0E0E0', // to see which ones work best for you
generateGradient: true
};
var target = document.getElementById('foo'); // your canvas element
var gauge = new Gauge(target);
gauge.setOptions(opts); // create sexy gauge!
gauge.maxValue = 3000; // set max gauge value
gauge.animationSpeed = 32; // set animation speed (32 is default value)
gauge.set(1250); // set actual value
});
You can draw a 360 degree guage indicator indicator using canvas context.rotate
First declare your indicator styling:
var indicatorX=150;
var indicatorY=150;
var indicatorBaseWidth=10;
var indicatorHeight=75;
var indicatorDegrees=0;
var indicatorFill="maroon";
Then use this function to draw the indicator at any angle from 0 (vertical) to 360 (back to vertical):
Note the use of translate and rotate.
Translate moves the context [0,0] drawing coordinate to the indicatorX/Y position
Rotate will rotate the context to the currently specified degree of rotation
Also, notice context.save and context restore.
Context.save() will save the state of the unmoved and unrotated canvas context.
Context.restore() will restore the context state back to its unmoved and unrotated state.
We use save/restore so that we don’t have to remember and adjust-for the previous rotation.
function drawIndicator(){
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.save();
ctx.translate(indicatorX,indicatorY);
ctx.rotate(indicatorDegrees*Math.PI/180);
ctx.beginPath();
ctx.moveTo(-indicatorBaseWidth/2,0);
ctx.quadraticCurveTo(0,10,indicatorBaseWidth/2,0);
ctx.lineTo(0,-indicatorHeight);
ctx.closePath();
ctx.strokeStyle="gray";
ctx.lineWidth=3;
ctx.stroke();
ctx.fillStyle=indicatorFill;
ctx.fill();
ctx.beginPath();
ctx.arc(0,0,3,0,Math.PI*2,false);
ctx.closePath();
ctx.fillStyle="gold";
ctx.fill();
ctx.restore();
}
Here is code and a Fiddle: http://jsfiddle.net/m1erickson/7BKDG/
<!doctype html>
<html lang="en">
<head>
<style>
body{ background-color: ivory; }
#wrapper{ position:relative; }
canvas{ position:absolute; left:40px; top:5px; border:1px solid red;}
#amount{ position:absolute; left:1px; top:5px; margin-bottom:15px; width:23px; border:0; color:#f6931f; font-weight:bold; }
#slider-vertical{ position:absolute; left:5px; top:40px; width:15px; height:225px; border:0px; color:#f6931f; font-weight:bold; }
</style>
<link rel="stylesheet" href="http://code.jquery.com/ui/1.10.3/themes/smoothness/jquery-ui.css" />
<script src="http://code.jquery.com/jquery-1.9.1.js"></script>
<script src="http://code.jquery.com/ui/1.10.3/jquery-ui.js"></script>
<script>
$(function() {
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var indicatorX=150;
var indicatorY=150;
var indicatorBaseWidth=10;
var indicatorHeight=75;
var indicatorDegrees=0;
var indicatorFill="maroon";
$( "#slider-vertical" ).slider({
orientation: "vertical",
range: "min",
min: 0,
max: 360,
value: 0,
slide: function( event, ui ) {
$( "#amount" ).val( ui.value );
indicatorDegrees=ui.value;
drawIndicator();
}
});
$( "#amount" ).val( $( "#slider-vertical" ).slider( "value" ) );
function drawIndicator(){
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.save();
ctx.translate(indicatorX,indicatorY);
ctx.rotate(indicatorDegrees*Math.PI/180);
ctx.beginPath();
ctx.moveTo(-indicatorBaseWidth/2,0);
ctx.quadraticCurveTo(0,10,indicatorBaseWidth/2,0);
ctx.lineTo(0,-indicatorHeight);
ctx.closePath();
ctx.strokeStyle="gray";
ctx.lineWidth=3;
ctx.stroke();
ctx.fillStyle=indicatorFill;
ctx.fill();
ctx.beginPath();
ctx.arc(0,0,3,0,Math.PI*2,false);
ctx.closePath();
ctx.fillStyle="gold";
ctx.fill();
ctx.restore();
}
drawIndicator();
}); // end $(function(){});
</script>
</head>
<body>
<div id="wrapper">
<input type="text" id="amount" />
<div id="slider-vertical"></div>
<canvas id="canvas" width=300 height=300></canvas>
</div>
</body>
</html>
I am using Firefox 19.0.2 on Ubuntu Linux.
I'm learning HTML5 but find that the following code's image
flashes repeatedly. Furthermore, I would like for the image
to finish downloading before the script stars:
<!DOCTYPE html>
<html lang="en">
<head>
<meta encoding="UTF-8" />
<title>Hello Canvas</title>
<script type="text/javascript">
window.onload = drawCanvas;
function canvasSupportEnabled() {
return !!document.createElement('canvas').getContext;
}
var Debugger = function() { };
Debugger.log = function(message) {
try {
console.log(message);
} catch (exception) {
return;
}
}
var x = 0;
var y = 0;
function drawCanvas() {
if (!canvasSupportEnabled())
return;
var theCanvas = document.getElementById("myCanvas");
var context = theCanvas.getContext("2d");
context.fillStyle = "#ffffaa";
context.fillRect(0, 0, 500, 300);
context.fillStyle = "#000000";
context.font = "20px Sans-Serif";
context.textBaseLine = "top";
context.fillText("Hello World!", 195, 80);
context.strokeStyle = "#000000";
context.strokeRect(x, y, 490, 290);
var platypus = new Image();
platypus.onload = function() {
context.drawImage(platypus, x, y);
}
platypus.src = "http://www.wildwatch.com.au/uploads/Platypus/PLATYPUSweb1.jpg"
window.setTimeout(drawCanvas, 200);
x = x + 5;
y = y + 5;
}
</script>
</head>
<body>
<h1>Hello Canvas.</h1>
<canvas id="myCanvas" width="500" height="300">Your browser does not support HTML5 canvas.</c
</body>
</html>
How can I solve these two problems. Do I need to double-buffer and how can I do it?
How do I detect an onload event for the images to finish being downloaded?
Thanks.
This will load the image first then create and draw the canvas.
<!DOCTYPE html>
<html lang="en">
<head>
<meta encoding="UTF-8" />
<title>Hello Canvas</title>
<script type="text/javascript">
window.onload = drawCanvas;
function canvasSupportEnabled() {
return !!document.createElement('canvas').getContext;
}
var x = 0;
var y = 0;
function drawCanvas() {
if (!canvasSupportEnabled())
return;
var platypus = new Image();
platypus.onload = function () {
var theCanvas = document.getElementById("myCanvas");
var context = theCanvas.getContext("2d");
context.fillStyle = "#ffffaa";
context.fillRect(0, 0, 500, 300);
context.fillStyle = "#000000";
context.font = "20px Sans-Serif";
context.textBaseLine = "top";
context.fillText("Hello World!", 195, 80);
context.strokeStyle = "#000000";
context.strokeRect(x, y, 490, 290);
context.drawImage(this, x, y);
}
platypus.src = "http://www.wildwatch.com.au/uploads/Platypus/PLATYPUSweb1.jpg"
}
</script>
</head>
<body>
<h1>Hello Canvas.</h1>
<canvas id="myCanvas" width="500" height="300">Your browser does not support HTML5 canvas.</canvas>
</body>
</html>
I suspect the issue is the setTimeout call. The first run of the drawCanvas function causes the image to start loading. Once the image is loaded, it'll draw on the canvas, but the subsequent drawCanvas calls caused by the timeout will cause the whole canvas to get filled with the rect you're drawing and thus making the image disappear.
The onload callback will not fire again due to the image already having been loaded.
The simplest way to fix it would be to use a preloader for the images. Basically instead of using your current window.onload handler, use another function which loads your images and stores them in some variables. Once it has finished loading the images, have it call drawCanvas which you would modify to use one of the stored images instead.
The following did it for me.
<!DOCTYPE html>
<html lang="en">
<head>
<meta encoding="UTF-8" />
<title>Hello Canvas</title>
<script type="text/javascript">
window.onload = drawCanvas;
function canvasSupportEnabled() {
return !!document.createElement('canvas').getContext;
}
var x = 0;
var y = 0;
function drawCanvas() {
if (!canvasSupportEnabled())
return;
var platypus = new Image();
platypus.onload = function () {
var theCanvas = document.getElementById("myCanvas");
var context = theCanvas.getContext("2d");
context.fillStyle = "#ffffaa";
context.fillRect(0, 0, 500, 300);
context.fillStyle = "#000000";
context.font = "20px Sans-Serif";
context.textBaseLine = "top";
context.fillText("Hello World!", 195, 80);
context.strokeStyle = "#000000";
context.strokeRect(x, y, 490, 290);
context.drawImage(this, x, y);
}
x = x + 5;
y = y + 5;
setTimeout(drawCanvas, 200);
platypus.src = "http://www.wildwatch.com.au/uploads/Platypus/PLATYPUSweb1.jpg"
}
</script>
</head>
<body>
<h1>Hello Canvas.</h1>
<canvas id="myCanvas" width="500" height="300">Your browser does not support HTML5 canvas.</
</body>
</html>
I've been following various guides and have the base code up for a simple animation but for the life of me I cannot get the canvas to reset correctly. The clearRect() function is working perfectly but when I try to draw an arc again immediatly afterwards it draws the sum of all the paths again rather than just drawing the single segment of the circle.
Can someone tell me what I'm doing wrong here, I know it's a simple solution! In short I would like the test page below to produce a kind of spinning segment instead of just drawing a circle:
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
</head>
<body>
<span id="degrees_output" style="display:block;width:60px"></span>
<button onclick="continue_animation=false;">Stop</button>
<canvas id="myCanvas" width="578" height="200"></canvas>
<script>
var degrees = 0;
var continue_animation = true;
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var output = document.getElementById('degrees_output');
window.requestAnimFrame = (function(callback) {
return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame ||
function(callback) {
window.setTimeout(callback, 1000 / 60);
};
})();
function animate() {
// update
output.innerHTML = degrees;
var radians = (degrees / 180) * Math.PI;
if (degrees >= 360)
degrees = 0;
else
degrees += 1;
// clear
if (degrees % 20 == 0)
{
context.clearRect(0, 0, 578, 200);
}
context.beginPath();
// setup the line style
context.strokeStyle = '#fa00ff';
context.lineWidth = 5;
context.lineCap = 'round';
context.arc(50, 50, 20, 0, radians, false);
// colour the path
context.stroke();
context.closePath();
// request new frame
requestAnimFrame(function() {
if (continue_animation)
animate();
});
}
animate();
</script>
If you want a fixed length arc to sweep around your circle, you'll want to specify both the starting and ending angles in your context.arc like this:
context.arc(50, 50, 20, startRadians, radians, false);
and startRadians can just be any angle behind your "radians" value:
var startRadians= (degrees-45) * Math.PI/180;
and, Yes, you will need to clear the canvas (at least the previous arc) before drawing the arc in a new position:
context.clearRect(0,0,canvas.width,canvas.height);
Here is code and a Fiddle: http://jsfiddle.net/m1erickson/VFhzX/
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<style>
body{ background-color: ivory; }
canvas{border:1px solid red;}
</style>
<script>
$(function(){
var degrees = 0;
var continue_animation = true;
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var output = document.getElementById('degrees_output');
window.requestAnimFrame = (function(callback) {
return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame ||
function(callback) {
window.setTimeout(callback, 1000 / 60);
};
})();
function animate() {
// update
output.innerHTML = degrees;
var radians = (degrees / 180) * Math.PI;
var startRadians= (degrees-45) * Math.PI/180;
if (degrees >= 360)
degrees = 0;
else
degrees += 1;
// clear
if (degrees % 20 == 0)
{
context.clearRect(0, 0, 578, 200);
}
context.clearRect(0,0,canvas.width,canvas.height);
context.beginPath();
// setup the line style
context.strokeStyle = '#fa00ff';
context.lineWidth = 5;
context.lineCap = 'round';
context.arc(50, 50, 20, startRadians, radians, false);
// colour the path
context.stroke();
context.closePath();
// request new frame
requestAnimFrame(function() {
if (continue_animation)
animate();
});
}
animate();
}); // end $(function(){});
</script>
</head>
<body>
<span id="degrees_output" style="display:block;width:60px"></span>
<button onclick="continue_animation=false;">Stop</button>
<canvas id="myCanvas" width="578" height="200"></canvas>
</body>
</html>