Jump to content

Updating canvas


fiveworlds

Recommended Posts

Trying to update text in canvas saving the background. So far I haven't been able to not use clear rect. I can do it using a framework but I would rather be able to do it without one.

 


<canvas id="myCanvas" width="578" height="200"></canvas>
<script>
var message, canvas = document.getElementById('myCanvas'), context = canvas.getContext('2d'), boundingrect = canvas.getBoundingClientRect();
function getMousePos(e) {
return {
x: e.clientX - boundingrect.left,
y: e.clientY - boundingrect.top
};
}

canvas.addEventListener('mousemove', function(e) {
mousePos = getMousePos(e);
message = 'Mouse position: ' + mousePos.x + ',' + mousePos.y;
context.clearRect(0, 0, canvas.width, canvas.height);
context.font = '18pt Calibri';
context.fillStyle = 'black';
context.fillText(message, 10, 25);
}, false);
</script>

 


Here I can save the background data and then redraw it but that isn't a good solution.

<canvas id="myCanvas" width="578" height="200"></canvas>
<script>
var message, canvas = document.getElementById('myCanvas'), context = canvas.getContext('2d'), boundingrect = canvas.getBoundingClientRect();
function getMousePos(e) {
return {
x: e.clientX - boundingrect.left,
y: e.clientY - boundingrect.top
};
}
context.rect(10,10,150,100);
context.stroke();
canvasdata = context.getImageData(0, 0, canvas.width, canvas.height);
canvas.addEventListener('mousemove', function(e) {
mousePos = getMousePos(e);
message = 'Mouse position: ' + mousePos.x + ',' + mousePos.y;
context.clearRect(0, 0, canvas.width, canvas.height);
context.font = '18pt Calibri';
context.fillStyle = 'black';
context.putImageData(canvasdata, 0, 0);
context.fillText(message, 10, 25);
}, false);
</script>

 




Is there a way to update already filled text??

Link to comment
Share on other sites

Okay well that was actually very helpful. Still haven't got it perfect though. I can create an offscreen canvas layer and then merge the layers. However at the moment it isn't detecting transparency around the text perfectly it has a white border.

 

 

<canvas id="myCanvas" width="578" height="200"></canvas>
<script>
var message, canvas = document.getElementById('myCanvas'), context = canvas.getContext('2d'), boundingrect = canvas.getBoundingClientRect();
function getMousePos(e) {
return {
x: e.clientX - boundingrect.left,
y: e.clientY - boundingrect.top
};
}

canvas.offscreenCanvas = document.createElement("canvas");
canvas.offscreenCanvas.width = canvas.width;
canvas.offscreenCanvas.height = canvas.height;
canvas.offscreenContext = canvas.offscreenCanvas.getContext("2d");

canvas.offscreenCanva = document.createElement("canvas");
canvas.offscreenCanva.width = canvas.width;
canvas.offscreenCanva.height = canvas.height;
canvas.offscreenContex = canvas.offscreenCanva.getContext("2d");


canvas.offscreenContex.fillStyle = 'blue';
canvas.offscreenContex.fillRect(0,0,canvas.width,canvas.height);

canvas.offscreenContex.stroke();
canvas.offscreenContex.canvasdata = canvas.offscreenContex.getImageData(0, 0, canvas.width, canvas.height);
canvas.addEventListener('mousemove', function(e) {
mousePos = getMousePos(e);
message = 'Mouse position: ' + mousePos.x + ',' + mousePos.y;

canvas.offscreenContex.fillStyle = 'blue';
canvas.offscreenContex.fillRect(0,0,canvas.width,canvas.height);
canvas.offscreenContex.stroke();
canvas.offscreenContex.canvasdata = canvas.offscreenContex.getImageData(0, 0, canvas.width, canvas.height);
context.clearRect(0, 0, canvas.width, canvas.height);
canvas.offscreenContext.globalAlpha = 0;
canvas.offscreenContext.clearRect(0, 0, canvas.width, canvas.height);
canvas.offscreenContext.font = '18pt Calibri';context.fillStyle = 'black';
canvas.offscreenContext.globalAlpha = 1;
canvas.offscreenContext.fillText(message, 0, 18);
canvas.offscreenContext.canvasdata = canvas.offscreenContext.getImageData(0, 0, canvas.width, canvas.height);
imageDataArray = [canvas.offscreenContex.canvasdata,canvas.offscreenContext.canvasdata];
mergeLayerData (imageDataArray);





}, false);

function mergeLayerData( imageDataArray ) {

var newImageData = imageDataArray[ 0 ];


for ( var j = 1, len = imageDataArray.length; j < len; j++ ) {

for ( var i = 0, bytes = imageDataArray[ j ].data.length; i < bytes; i += 4 ) {
var index = ( imageDataArray[ j ].data[ i + 3 ] === 0 ? 0 : j );

newImageData.data[ i ] = imageDataArray[ index ].data[ i ];
newImageData.data[ i + 1 ] = imageDataArray[ index ].data[ i + 1 ];
newImageData.data[ i + 2 ] = imageDataArray[ index ].data[ i + 2 ];
newImageData.data[ i + 3 ] = imageDataArray[ index ].data[ i + 3 ];
}

}
context.putImageData( newImageData, 0, 0 );

};
</script>

 

Link to comment
Share on other sites

I am still not sure what for all this you need. Your examples from 1st post didn't blink at all here.

Double buffering is useful to remove such blinking, while drawing, for a too long time, on on-screen bitmap.

See answers here:

http://stackoverflow.com/questions/2795269/does-html5-canvas-support-double-buffering

Answer with 69 votes has code which is switching back and forth overlayed element. And draw to the one currently invisible.

 

I realized that you could place one element over another element, same position, CSS or dynamically created.

Then set background on deeper one, and draw text on "top" one, but in such way that text is on "top", the rest pass through whatever is below.

Like while programming sprites with transparent regions.

Edited by Sensei
Link to comment
Share on other sites

Okay so I eventually figured out how to do it using offscreen canvas. The idea being that prior to drawing my text on the canvas I save the portion of the background that it covers to the offscreen canvas and so only redraw that section when the text is updated.

<canvas id="myCanvas" width="578" height="200"></canvas>
    <script>
     var message, canvas = document.getElementById('myCanvas'), context = canvas.getContext('2d'), boundingrect = canvas.getBoundingClientRect();
      function getMousePos(e) {
        return {
          x: e.clientX - boundingrect.left,
          y: e.clientY - boundingrect.top
        };
      }
    
    context.fillStyle = 'green';
    context.fillRect(0,0,200,100);
    offscreenCanvas = document.createElement("canvas");
    offscreenCanvas.width = canvas.width;
    offscreenCanvas.height = 26;
    offscreenContext = offscreenCanvas.getContext("2d");
    offscreenContext.canvasdata = context.getImageData(0, 0, canvas.width, canvas.height);        
    offscreenContext.putImageData(offscreenContext.canvasdata,0,0);
    
      canvas.addEventListener('mousemove', function(e) {
        mousePos = getMousePos(e);
        message = 'Mouse position: ' + mousePos.x + ',' + mousePos.y;            
        context.clearRect(0, 0, canvas.width, 26);        
        context.fillStyle = 'black';        

        context.putImageData (offscreenContext.getImageData(0, 0, canvas.width, canvas.height),0,0);        
        context.font = '18pt Times New Roman';
        context.fillStyle = 'black';
        context.globalAlpha = 1;  
        context.fillText(message, 0, 18);
        
      }, false);     

    </script>
Edited by fiveworlds
Link to comment
Share on other sites

If it works I wouldn't worry about it, but meant something along these lines. Similar to what Sensei mentioned using CSS for absolute positioning.

<!doctype html>

<html lang="en">
<head>
    <style>
body {
    background-color: blue;
}

canvas {
    position: absolute;
    left: 100px;
    top: 50px;
}
</style>
</head>
<body>
    <canvas id="gameCanvas" width="578" height="200"></canvas>  
    <canvas id="textCanvas" width="578" height="200"></canvas>
   <script>
var gameCanvas=document.getElementById("gameCanvas");
var ctx=gameCanvas.getContext("2d");
ctx.fillStyle="red";
ctx.fillRect(0,0, gameCanvas.width, gameCanvas.height);


     var message, canvas = document.getElementById('textCanvas'), context = canvas.getContext('2d'), boundingrect = canvas.getBoundingClientRect();
      function getMousePos(e) {
        return {
          x: e.clientX - boundingrect.left,
          y: e.clientY - boundingrect.top
        };
      }

      canvas.addEventListener('mousemove', function(e) {
        mousePos = getMousePos(e);
        message = 'Mouse position: ' + mousePos.x + ',' + mousePos.y;
        context.clearRect(0, 0, canvas.width, canvas.height);
        context.font = '18pt Calibri';
        context.fillStyle = 'black';
        context.fillText(message, 10, 25);
      }, false);
    </script>
</body>
</html>

Granted can see some limitations with this too, so depends on what you are looking for.

Edited by Endy0816
Link to comment
Share on other sites

CSS for absolute positioning.

 

 

Why would you do that?? A game should be made with.

body{margin:0px;}
canvas{width:100%;height:100%;}

This allows the game to run full-screen on all platforms. Then if you are including a game in a container it should be in an iframe.

 

 

Granted can see some limitations with this too

 

I did look at doing things that way too. However if you have multiple canvases all the event listeners have to be on the topmost canvas.

Link to comment
Share on other sites

Why would you do that?? A game should be made with.

body{margin:0px;}
canvas{width:100%;height:100%;}
This allows the game to run full-screen on all platforms. Then if you are including a game in a container it should be in an iframe.

 

He used left,top,

so these two elements overlap each other.. Without them elements would be one below another, not overlapping.

Could be mixed with width,height.

Or use JavaScript to set position and size at start up. Or even generate these elements dynamically.

Edited by Sensei
Link to comment
Share on other sites

I'd use canvas{position:fixed;top:0px;left:0px;width:100%;height:100%} to make them overlap. It is good practice to make all games suited to being put in an iframe because most sites with games force you to use iframes facebook etc.

Link to comment
Share on other sites

While writing a click event listener with transparency I noticed the code was throwing a weird error in chrome.

Uncaught SecurityError: Failed to execute 'getImageData' on 'CanvasRenderingContext2D': The canvas has been tainted by cross-origin data.

If I run the code on my server as localhost or my domain it isn't throwing an error.

<!DOCTYPE HTML>
<html>
  <head>
    <style>
      body {
        margin: 0px;
        padding: 0px;
      }
    </style>
  </head>
  <body>
    <canvas id="myCanvas" width="800" height="400"></canvas>
    <script>
      var canvas = document.getElementById('myCanvas');
      var context = canvas.getContext('2d');
      var boundingrect = canvas.getBoundingClientRect();
      
      function getMousePos(e) {
        return {
          x: e.clientX - boundingrect.left,
          y: e.clientY - boundingrect.top
        };
      }
      
      var imageObj = new Image();
      
      imageObj.onload = function() {
        canvas_img = [];
        t=canvas_img.length;
        
        offscreenCanvas = document.createElement("canvas");
        offscreenCanvas.width = imageObj.naturalWidth;
        offscreenCanvas.height = imageObj.naturalHeight;  
        offscreenContext  = offscreenCanvas.getContext("2d");  
        
        offscreenContext.drawImage(imageObj, 0, 0);
        canvasdata=offscreenContext.getImageData(0,0, offscreenCanvas.width, offscreenCanvas.height);
        
        for (j=10; j<(canvas.height-imageObj.naturalHeight); j=j+10+imageObj.naturalHeight){            
             for (i=10; i<(canvas.width-imageObj.naturalWidth); i=i+10+imageObj.naturalWidth){    
                
                canvas_img[t]={
                    x         : i,
                    y         : j,
                    data      : imageObj,
                    imagedata : canvasdata,
                    src          : imageObj.src,
                    width     : imageObj.naturalWidth,
                    height    : imageObj.naturalHeight                
                };
                context.drawImage(imageObj, i, j);                
                t=t+1;
             }
         }
      };
      imageObj.src = 'king_of_hearts.png';  
            
      canvas.addEventListener('click', function(e) {
         mousePos = getMousePos(e);        
        
         for(i=0; i<canvas_img.length; i++){
             if(mousePos.x > canvas_img[i].x && mousePos.y > canvas_img[i].y)
             {
            
                if(mousePos.x < (canvas_img[i].x+canvas_img[i].width) && mousePos.y < (canvas_img[i].y+canvas_img[i].height))
                {
                    if(canvas_img[i].imagedata.data[((mousePos.y-canvas_img[i].y)*canvas_img[i].width+(mousePos.x-canvas_img[i].x))*4+3]===0){
                        
                    }
                    else
                    {
                        alert(canvas_img[i].src);
                    }
                    
                    
                }        
             }
         }
      });
    </script>
  </body>
</html>  
Link to comment
Share on other sites

Yeah only Kirby's method didn't refer to things I could do on my server (or settings on a server that was hosting me) and it didn't work the error was still thrown.

 

I tried the mozilla method https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_enabled_image

var img = new Image,
canvas = document.createElement("canvas"),
ctx = canvas.getContext("2d"),
src = "http://example.com/image"; // insert image url here

img.crossOrigin = "Anonymous";

img.onload = function() {
canvas.width = img.width;
canvas.height = img.height;
ctx.drawImage( img, 0, 0 );
localStorage.setItem( "savedImageData", canvas.toDataURL("image/png") );
}
img.src = src;
// make sure the load event fires for cached images too
if ( img.complete || img.complete === undefined ) {
img.src = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==";
img.src = src;
}

but got the error

Image from origin 'file://' has been blocked from loading by Cross-Origin Resource Sharing policy: Invalid response. Origin 'null' is therefore not allowed access.

It would probably work on localhost but I am trying to make it work just running the file from my desktop.

Edited by fiveworlds
Link to comment
Share on other sites

Tried?

img.crossOrigin = "Anonymous"; Together with Access-Control-Allow-Origin "*"

Like they said in threads.. ?

 

The whole thing is about origin of image. If it's dynamic/loaded from server outside of our control, it can change content to something else, so it could be used to in inject something to our server.

Edited by Sensei
Link to comment
Share on other sites

Tried?

img.crossOrigin = "Anonymous"; Together with Access-Control-Allow-Origin "*"

Like they said in threads.. ?

 

 

That's Apache webserver as I was saying there seems to be no way of just running the file from my desktop without using a webserver.

 

 

<IfModule mod_setenvif.c>

<IfModule mod_headers.c>

<FilesMatch "\.(cur|gif|ico|jpe?g|png|svgz?|webp)$">

SetEnvIf Origin ":" IS_CORS

Header set Access-Control-Allow-Origin "*" env=IS_CORS

</FilesMatch>

</IfModule>

</IfModule>

 

You can't set the header using xmlhttprequests

    previous = undefined;
    function pagereloader() {        
      var xhttp = new XMLHttpRequest();
      
      xhttp.onreadystatechange = function() {
        if (xhttp.readyState == 4 && xhttp.status == 200) {
            current = escape(xhttp.responseText.toString());
            if(previous){
                if(previous!==current){location.reload();}
            }
            previous=current;
        }
      };
      xhttp.open("GET", window.location.href, true);
      xhttp.setRequestHeader("Access-Control-Allow-Origin","*");
      xhttp.send();

    }
    setTimeout(pagereloader, 1000);

returned...

XMLHttpRequest cannot load file:///C:/Users/David/Desktop/New%20folder%20(5)/test.html. Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-extension, https, chrome-extension-resource.
Edited by fiveworlds
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.