I have been having some trouble with displaying a sprite sheet on a simple canvas. For debugging purposes I have taken the code out from my main code so that I can work on just one small file. The sprite sheet loads up next to the canvas but the canvas does not display the sprite itself.
Any help is much appreciated. Thanks
<canvas id="canvas" width="800" height="36" style="border:1px solid" onload="draw_hello()" ></canvas>
<img id="helloSprites" src="Tux-Hello.png">
<script>
//hello sprite
var x=0;
var y=0;
var f=0;
var w=32;
var h=32;
var mycanv=document.getElementById("canvas");
var ctx=mycanv.getContext("2d");
//helloImage.src = "images/Tux-Hello.png";
//var helloImage = new Image();
var hello=document.getElementById("helloSprites");
function draw_hello() {
setInterval(drawHello,200);
}
function drawHello() {
ctx.fillStyle="#292";
ctx.fillRect(0,0,mycanv.width, mycanv.height);
ctx.fillStyle="#aaa";
ctx.fillRect(0,25,mycanv.width, mycanv.height);
if (x>=(mycanv.width)) {
x=0;
}
x+=2;
f++;
// draw the car
if (f==2) {
f=4;
}
if (f==6) {
f=0;
}
ctx.drawImage(hello, w, f*h, w, h, x, y, w, h);
}
</script>
Attach your onload to the body element and not the canvas element.
You're probably calling onload--and therefore calling draw_hello() before the img element is fully loaded.
Related
Is there possibility to convert the image present in a canvas element into an image representing by img src?
I need that to crop an image after some transformation and save it. There are a view functions that I found on the internet like: FileReader() or ToBlop(), toDataURL(), getImageData(), but I have no idea how to implement and use them properly in JavaScript.
This is my html:
<img src="http://picture.jpg" id="picture" style="display:none"/>
<tr>
<td>
<canvas id="transform_image"></canvas>
</td>
</tr>
<tr>
<td>
<div id="image_for_crop">image from canvas</div>
</td>
</tr>
In JavaScript it should look something like this:
$(document).ready(function() {
img = document.getElementById('picture');
canvas = document.getElementById('transform_image');
if(!canvas || !canvas.getContext){
canvas.parentNode.removeChild(canvas);
} else {
img.style.position = 'absolute';
}
transformImg(90);
ShowImg(imgFile);
}
function transformImg(degree) {
if (document.getElementById('transform_image')) {
var Context = canvas.getContext('2d');
var cx = 0, cy = 0;
var picture = $('#picture');
var displayedImg = {
width: picture.width(),
height: picture.height()
};
var cw = displayedImg.width, ch = displayedImg.height
Context.rotate(degree * Math.PI / 180);
Context.drawImage(img, cx, cy, cw, ch);
}
}
function showImg(imgFile) {
if (!imgFile.type.match(/image.*/))
return;
var img = document.createElement("img"); // creat img object
img.id = "pic"; //I need set some id
img.src = imgFile; // my picture representing by src
document.getElementById('image_for_crop').appendChild(img); //my image for crop
}
How can I change the canvas element into an img src image in this script? (There may be some bugs in this script.)
canvas.toDataURL() will provide you a data url which can be used as source:
var image = new Image();
image.id = "pic";
image.src = canvas.toDataURL();
document.getElementById('image_for_crop').appendChild(image);
Complete example
Here's a complete example with some random lines. The black-bordered image is generated on a <canvas>, whereas the blue-bordered image is a copy in a <img>, filled with the <canvas>'s data url.
// This is just image generation, skip to DATAURL: below
var canvas = document.getElementById("canvas")
var ctx = canvas.getContext("2d");
// Just some example drawings
var gradient = ctx.createLinearGradient(0, 0, 200, 100);
gradient.addColorStop("0", "#ff0000");
gradient.addColorStop("0.5" ,"#00a0ff");
gradient.addColorStop("1.0", "#f0bf00");
ctx.beginPath();
ctx.moveTo(0, 0);
for (let i = 0; i < 30; ++i) {
ctx.lineTo(Math.random() * 200, Math.random() * 100);
}
ctx.strokeStyle = gradient;
ctx.stroke();
// DATAURL: Actual image generation via data url
var target = new Image();
target.src = canvas.toDataURL();
document.getElementById('result').appendChild(target);
canvas { border: 1px solid black; }
img { border: 1px solid blue; }
body { display: flex; }
div + div {margin-left: 1ex; }
<div>
<p>Original:</p>
<canvas id="canvas" width=200 height=100></canvas>
</div>
<div id="result">
<p>Result via <img>:</p>
</div>
See also:
MDN: canvas.toDataURL() documentation
Do this. Add this to the bottom of your doc just before you close the body tag.
<script>
function canvasToImg() {
var canvas = document.getElementById("yourCanvasID");
var ctx=canvas.getContext("2d");
//draw a red box
ctx.fillStyle="#FF0000";
ctx.fillRect(10,10,30,30);
var url = canvas.toDataURL();
var newImg = document.createElement("img"); // create img tag
newImg.src = url;
document.body.appendChild(newImg); // add to end of your document
}
canvasToImg(); //execute the function
</script>
Of course somewhere in your doc you need the canvas tag that it will grab.
<canvas id="yourCanvasID" />
I´ve found two problems with your Fiddle, one of the problems is first in Zeta´s answer.
the method is not toDataUrl(); is toDataURL(); and you forgot to store the canvas in your variable.
So the Fiddle now works fine http://jsfiddle.net/gfyWK/12/
I hope this helps!
canvas.toDataURL is not working if the original image URL (either relative or absolute) does not belong to the same domain as the web page. Tested from a bookmarklet and a simple javascript in the web page containing the images.
Have a look to David Walsh working example. Put the html and images on your own web server, switch original image to relative or absolute URL, change to an external image URL. Only the first two cases are working.
Corrected the Fiddle - updated shows the Image duplicated into the Canvas...
And right click can be saved as a .PNG
http://jsfiddle.net/gfyWK/67/
<div style="text-align:center">
<img src="http://imgon.net/di-M7Z9.jpg" id="picture" style="display:none;" />
<br />
<div id="for_jcrop">here the image should apear</div>
<canvas id="rotate" style="border:5px double black; margin-top:5px; "></canvas>
</div>
Plus the JS on the fiddle page...
Cheers
Si
Currently looking at saving this to File on the server --- ASP.net C# (.aspx web form page) Any advice would be cool....
The code runs with no bugs, but a problem I am having is because the ".onLoad" function makes it display after the text has already been displayed on the screen. The problem I am facing is that I would like if the text (Loading graphics and loading variables) displayed over the image.
The code is here:
<! DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml1-transitional.dtd">
<html>
<body>
<canvas id="ctx" width="800" height="500" style="border:1px solid #d3d3d3;"></canvas>
<script>
var ctx = document.getElementById("ctx").getContext("2d");
var canvas = document.getElementById('ctx');
var context = canvas.getContext('2d');
var imageObj = new Image();
imageObj.onload = function(){
context.drawImage(imageObj,0,0);
};
imageObj.src = 'img/startscreen.jpg';
ctx.fillText('Loading variables.',50,50);
character=new Object();
character.hp=1;
character.name=null;
ctx.fillText('Loading graphics..',50,100);
</script>
</body>
</html>
I would layer the background image on its own canvas positioned behind the text layer. Then you can clear and update the text layer without having to re-draw the background image.
#background,#overlay {
position: absolute;
}
<canvas id="background"></canvas>
<canvas id="overlay"></canvas>
var can = document.getElementById('overlay'),
bg_can = document.getElementById('background'),
height = can.height = bg_can.height = 500,
width = can.width = bg_can.width = 500,
ctx = can.getContext('2d'),
bctx = bg_can.getContext('2d');
var img = new Image();
img.src = ' ... ';
img.onload = init;
function init() {
// draw the background
bctx.drawImage(this, 0, 0);
// draw your initial text
updateText('hello world');
// other stuff that is going to take time
updateText('done');
}
function updateText(msg) {
ctx.clearRect(0, 0, width, height);
ctx.fillText(msg, 50, 100);
}
This isn't very well thought out (my code example) for re-use purposes.. but I don't know much about your other needs :) hope this helps.
If you want to overlay String on image, why don you use image as backGround imange and place text over it??
Css
try in css
#ctx{
background-image:url('img/startscreen.jpg');}
remove image source in script or insert css in script itself
Css in scripts
ctx.style.backgroundImage=url('img/startscreen.jpg');
I called the function for the text to be displayed after the background has:
imageObj.src = 'img/startscreen.jpg';
imageObj.onload = function(){
context.drawImage(imageObj,0,0);
init()
};
function init(){
ctx.fillText('Loading variables.',50,50);
character=new Object();
character.hp=1;
character.name=null;
ctx.fillText('Loading graphics..',50,100);
}
I have a html page in which i need to add more than 1 canvas element and load it on the page load.
function draw()
{
var c=document.getElementById("myCanvas");
var padding = 20;
var ctx=c.getContext("2d");
var grd=ctx.createLinearGradient(0,0,175,50);
grd.addColorStop(0,"#E05D1B");
grd.addColorStop(1,"#00FF00");
ctx.fillStyle=grd;
ctx.fillRect(0,0,275,50);
}
<canvas id="myCanvas" width="250" height="8" style="margin-bottom:10px;margin-left:10px;">
<img src="images\gradient1.png" style="margin-bottom:10px;margin-left:10px;"/>
</canvas>
I am adding like this code with different id but i need to recode the javascript; how can i reduce it??
<canvas id="myCanvas1" width="250" height="8" style="margin-bottom:10px;margin-left:10px;"> <img src="images\gradient1.png" style="margin-bottom:10px;margin-left:10px;"/> </canvas>
You could pass the contexts of your separate canvas elements as a parameter to your draw function (fiddle):
function draw(ctx)
{
var grd=ctx.createLinearGradient(0,0,175,50);
grd.addColorStop(0,"#E05D1B");
grd.addColorStop(1,"#00FF00");
ctx.fillStyle=grd;
ctx.fillRect(0,0,275,50);
}
draw(document.getElementById("canvas_1").getContext("2d"));
draw(document.getElementById("canvas_2").getContext("2d"));
Or, depending on how many canvas elements you have, it may be more efficient to call your draw function on a loop (fiddle):
function draw(ctx)
{
var grd=ctx.createLinearGradient(0,0,175,50);
grd.addColorStop(0,"#E05D1B");
grd.addColorStop(1,"#00FF00");
ctx.fillStyle=grd;
ctx.fillRect(0,0,275,50);
}
var i = 1;
while (document.getElementById("canvas_" + i)) {
draw(document.getElementById("canvas_" + i).getContext("2d"));
i ++;
}
Is there possibility to convert the image present in a canvas element into an image representing by img src?
I need that to crop an image after some transformation and save it. There are a view functions that I found on the internet like: FileReader() or ToBlop(), toDataURL(), getImageData(), but I have no idea how to implement and use them properly in JavaScript.
This is my html:
<img src="http://picture.jpg" id="picture" style="display:none"/>
<tr>
<td>
<canvas id="transform_image"></canvas>
</td>
</tr>
<tr>
<td>
<div id="image_for_crop">image from canvas</div>
</td>
</tr>
In JavaScript it should look something like this:
$(document).ready(function() {
img = document.getElementById('picture');
canvas = document.getElementById('transform_image');
if(!canvas || !canvas.getContext){
canvas.parentNode.removeChild(canvas);
} else {
img.style.position = 'absolute';
}
transformImg(90);
ShowImg(imgFile);
}
function transformImg(degree) {
if (document.getElementById('transform_image')) {
var Context = canvas.getContext('2d');
var cx = 0, cy = 0;
var picture = $('#picture');
var displayedImg = {
width: picture.width(),
height: picture.height()
};
var cw = displayedImg.width, ch = displayedImg.height
Context.rotate(degree * Math.PI / 180);
Context.drawImage(img, cx, cy, cw, ch);
}
}
function showImg(imgFile) {
if (!imgFile.type.match(/image.*/))
return;
var img = document.createElement("img"); // creat img object
img.id = "pic"; //I need set some id
img.src = imgFile; // my picture representing by src
document.getElementById('image_for_crop').appendChild(img); //my image for crop
}
How can I change the canvas element into an img src image in this script? (There may be some bugs in this script.)
canvas.toDataURL() will provide you a data url which can be used as source:
var image = new Image();
image.id = "pic";
image.src = canvas.toDataURL();
document.getElementById('image_for_crop').appendChild(image);
Complete example
Here's a complete example with some random lines. The black-bordered image is generated on a <canvas>, whereas the blue-bordered image is a copy in a <img>, filled with the <canvas>'s data url.
// This is just image generation, skip to DATAURL: below
var canvas = document.getElementById("canvas")
var ctx = canvas.getContext("2d");
// Just some example drawings
var gradient = ctx.createLinearGradient(0, 0, 200, 100);
gradient.addColorStop("0", "#ff0000");
gradient.addColorStop("0.5" ,"#00a0ff");
gradient.addColorStop("1.0", "#f0bf00");
ctx.beginPath();
ctx.moveTo(0, 0);
for (let i = 0; i < 30; ++i) {
ctx.lineTo(Math.random() * 200, Math.random() * 100);
}
ctx.strokeStyle = gradient;
ctx.stroke();
// DATAURL: Actual image generation via data url
var target = new Image();
target.src = canvas.toDataURL();
document.getElementById('result').appendChild(target);
canvas { border: 1px solid black; }
img { border: 1px solid blue; }
body { display: flex; }
div + div {margin-left: 1ex; }
<div>
<p>Original:</p>
<canvas id="canvas" width=200 height=100></canvas>
</div>
<div id="result">
<p>Result via <img>:</p>
</div>
See also:
MDN: canvas.toDataURL() documentation
Do this. Add this to the bottom of your doc just before you close the body tag.
<script>
function canvasToImg() {
var canvas = document.getElementById("yourCanvasID");
var ctx=canvas.getContext("2d");
//draw a red box
ctx.fillStyle="#FF0000";
ctx.fillRect(10,10,30,30);
var url = canvas.toDataURL();
var newImg = document.createElement("img"); // create img tag
newImg.src = url;
document.body.appendChild(newImg); // add to end of your document
}
canvasToImg(); //execute the function
</script>
Of course somewhere in your doc you need the canvas tag that it will grab.
<canvas id="yourCanvasID" />
I´ve found two problems with your Fiddle, one of the problems is first in Zeta´s answer.
the method is not toDataUrl(); is toDataURL(); and you forgot to store the canvas in your variable.
So the Fiddle now works fine http://jsfiddle.net/gfyWK/12/
I hope this helps!
canvas.toDataURL is not working if the original image URL (either relative or absolute) does not belong to the same domain as the web page. Tested from a bookmarklet and a simple javascript in the web page containing the images.
Have a look to David Walsh working example. Put the html and images on your own web server, switch original image to relative or absolute URL, change to an external image URL. Only the first two cases are working.
Corrected the Fiddle - updated shows the Image duplicated into the Canvas...
And right click can be saved as a .PNG
http://jsfiddle.net/gfyWK/67/
<div style="text-align:center">
<img src="http://imgon.net/di-M7Z9.jpg" id="picture" style="display:none;" />
<br />
<div id="for_jcrop">here the image should apear</div>
<canvas id="rotate" style="border:5px double black; margin-top:5px; "></canvas>
</div>
Plus the JS on the fiddle page...
Cheers
Si
Currently looking at saving this to File on the server --- ASP.net C# (.aspx web form page) Any advice would be cool....
I have a canvas element defined statically in the html with a width and height. If I attempt to use JavaScript to resize it dynamically (setting a new width and height - either on the attributes of the canvas or via the style properties) I get the following error in Firefox:
uncaught exception: [Exception... "Illegal operation on WrappedNative prototype object" nsresult: "0x8057000c (NS_ERROR_XPC_BAD_OP_ON_WN_PROTO)" location: "JS frame :: file:///home/russh/Desktop/test.html :: onclick :: line 1" data: no]
Is it possible to resize this element or do I have to destroy it and create a new element on the fly?
You didn't publish your code, and I suspect you do something wrong. it is possible to change the size by assigning width and height attributes using numbers:
canvasNode.width = 200; // in pixels
canvasNode.height = 100; // in pixels
At least it works for me. Make sure you don't assign strings (e.g., "2cm", "3in", or "2.5px"), and don't mess with styles.
Actually this is a publicly available knowledge — you can read all about it in the HTML canvas spec — it is very small and unusually informative. This is the whole DOM interface:
interface HTMLCanvasElement : HTMLElement {
attribute unsigned long width;
attribute unsigned long height;
DOMString toDataURL();
DOMString toDataURL(in DOMString type, [Variadic] in any args);
DOMObject getContext(in DOMString contextId);
};
As you can see it defines 2 attributes width and height, and both of them are unsigned long.
Note that if your canvas is statically declared you should use the width and height attributes, not the style, eg. this will work:
<canvas id="c" height="100" width="100" style="border:1px"></canvas>
<script>
document.getElementById('c').width = 200;
</script>
But this will not work:
<canvas id="c" style="width: 100px; height: 100px; border:1px"></canvas>
<script>
document.getElementById('c').width = 200;
</script>
I just had the same problem as you, but found out about the toDataURL method, which proved useful.
The gist of it is to turn your current canvas into a dataURL, change your canvas size, and then draw what you had back into your canvas from the dataURL you saved.
So here's my code:
var oldCanvas = canvas.toDataURL("image/png");
var img = new Image();
img.src = oldCanvas;
img.onload = function (){
canvas.height += 100;
ctx.drawImage(img, 0, 0);
}
<div id="canvasdiv" style="margin: 5px; height: 100%; width: 100%;">
<canvas id="mycanvas" style="border: 1px solid red;"></canvas>
</div>
<script>
$(function(){
InitContext();
});
function InitContext()
{
var $canvasDiv = $('#canvasdiv');
var canvas = document.getElementById("mycanvas");
canvas.height = $canvasDiv.innerHeight();
canvas.width = $canvasDiv.innerWidth();
}
</script>
This worked for me just now:
<canvas id="c" height="100" width="100" style="border:1px solid red"></canvas>
<script>
var c = document.getElementById('c');
alert(c.height + ' ' + c.width);
c.height = 200;
c.width = 200;
alert(c.height + ' ' + c.width);
</script>
Here's my effort to give a more complete answer (building on #john's answer).
The initial issue I encountered was changing the width and height of a canvas node (using styles), resulted in the contents just being "zoomed" or "shrunk." This was not the desired effect.
So, say you want to draw two rectangles of arbitrary size in a canvas that is 100px by 100px.
<canvas width="100" height="100"></canvas>
To ensure that the rectangles will not exceed the size of the canvas and therefore not be visible, you need to ensure that the canvas is big enough.
var $canvas = $('canvas'),
oldCanvas,
context = $canvas[0].getContext('2d');
function drawRects(x, y, width, height)
{
if (($canvas.width() < x+width) || $canvas.height() < y+height)
{
oldCanvas = $canvas[0].toDataURL("image/png")
$canvas[0].width = x+width;
$canvas[0].height = y+height;
var img = new Image();
img.src = oldCanvas;
img.onload = function (){
context.drawImage(img, 0, 0);
};
}
context.strokeRect(x, y, width, height);
}
drawRects(5,5, 10, 10);
drawRects(15,15, 20, 20);
drawRects(35,35, 40, 40);
drawRects(75, 75, 80, 80);
Finally, here's the jsfiddle for this: http://jsfiddle.net/Rka6D/4/ .
Prototypes can be a hassle to work with, and from the _PROTO part of the error it appears your error is caused by, say, HTMLCanvasElement.prototype.width, possibly as an attempt to resize all the canvases at once.
As a suggestion, if you are trying to resize a number of canvases at once, you could try:
<canvas></canvas>
<canvas></canvas>
<canvas></canvas>
<script type="text/javascript">
...
</script>
In the JavaScript, instead of invoking a prototype, try this:
$$ = function(){
return document.querySelectorAll.apply(document,arguments);
}
for(var i in $$('canvas')){
canvas = $$('canvas')[i];
canvas.width = canvas.width+100;
canvas.height = canvas.height+100;
}
This would resize all the canvases by adding 100 px to their size, as is demonstrated in this example
Hope this helped.