1

I am having an issue with context.getImageData() after I scaled down the canvas. I have canvas added to the HTML page:

<canvas id="canvas" width="960" height="620"></canvas>

I have image drawn on that canvas acting like button. I am testing the alpha channel to know if mouse is over the button or not:

var mx = (e) ? (e.offsetX || e.layerX) : 0;
var my = (e) ? (e.offsetY || e.layerY) : 0;
var cx = mx - (btn.x * this.ratio - 2;
var cy = my - btn.y * this.ratio - 2;
var pixels = btn.getContext().getImageData(cx, cy, 1, 1);
for (var j : number = 3; j < pixels.data.length; j += 4)
{
  if((pixels.data[j])!=0 && e)
  {
   console.log('mouse over');
 }
}

The button is sliced from the big image and pre-rendered:

var btn = createCanvas("img.png", 0, 0, 100, 100);
function createCanvas(img, sx , sy , w , h )
    {
        var canvas  = document.createElement("canvas");
        canvas.width = w;
        canvas.height = h;
        var ctx  = canvas.getContext("2d");
        ctx.drawImage(img, sx, sy, w, h, 0, 0, w, h);

        return canvas;
    }

After that sliced button/image is added to the main canvas.

this.context.drawImage(btn, 0,0, btn.width, btn.height, 100, 100, btn.width, btn.height);

It works fine until I start to scale the whole canvas.

function scale() {
   var scale = {};
   scale.x = window.innerWidth  / this.canvas.width;
   scale.y = window.innerHeight / this.canvas.height;
   var ratio = scale.x <= scale.y ? scale.x : scale.y;
}

After when I scale down the canvas the button hit/over area is bigger than the button/image itself. It looks it hasn't been scaled and it takes the original width and height. The graphic however is scaled accordingly to the canvas scale. I tried to multiply width and height by the ratio but it scale the image of a button but area where mouse reacts is still bigger than the button. What I should change in the code to have that issue gone?

p.s. I apologize for my English. :)

EDIT

The function I use to scale the canvas

 window.addEventListener('resize', resize, false);
 window.addEventListener('orientationchange', resize, false); 
 var canvas = $('#canvas');
 var ratio = 1;
 var originalCanvasW = 800;
 var originalCanvasH = 600
 function resize(e)
    {
        var scale = {x: 1, y: 1};
        var s : string = '';
        scale.x = window.innerWidth  /  canvas.width;
        scale.y = window.innerHeight /  canvas.height;

        ratio =  scale.x <= scale.y ? scale.x : scale.y;
        ratio = (ratio > 1) ? 1 : ratio;

        canvas.css('width',originalCanvasW*ratio);
        canvas.css('height',originalCanvasH*ratio);
    }
proti
  • 213
  • 3
  • 11
  • Not exactly sure what you're trying to accomplish through the scaling, but have you considered using ctx.scale(x,y) to scale the entire canvas coordinate system, instead of manually scaling? – Lucas Penney Jan 25 '14 at 00:06
  • I am trying to have a button on canvas with appropriate hitArea. So if I scale down the canvas the button scale down as well however the area of the button where mouse catches events stays unscaled. It looks like that the source canvas hasn't been scaled which is right because I scale the main one. Yes, I tried to ctx.scale(ratio, ratio); on source and/or main canvas but it doesn't solve the problem. – proti Jan 25 '14 at 10:10
  • I am attaching the image to visualise the problem http://i.stack.imgur.com/nFpqB.gif – proti Jan 25 '14 at 10:50
  • @Philipp I edited the main post. – proti Jan 25 '14 at 12:46

2 Answers2

0

You are scaling the canvas with CSS. When you do that, you aren't actually affecting the canvas itself, you are just affecting its representation in the DOM of the website. Using CSS to scale a canvas is not recommended in most cases, because it doesn't change the internal drawing resolution which means the canvas will be displayed blurred. But it also results in one canvas-pixel no longer being equivalent to one screen-pixel.

context.getImageData does still use the internal resolution (width="960" height="620)for its coordinates, while the mouse coordinates you use are measured in the coordinate system of the webpage the canvas is embedded in.

To solve this problem, there are two possibilities:

  • Factor in the current scaling-factor when you transform screen-pixel coordinates (from mouse-events) to canvas-pixel coordinates (for calls to context-functions).
  • Don't scale the canvas through CSS. Directly change the canvas.width and canvas.height and adjust the context.scale accordingly so that 960px is still the full width of the canvas.

I would recommend the second solution, because it will likely also look much better.

Philipp
  • 67,764
  • 9
  • 118
  • 153
  • I changed the resizing of the main canvas as you suggested. When I scale the main canvas context the issue stills exists. I think I should scale the source canvas because I want to have a smaller button area but when I am doing this the image is not visible. Just to let you know the x, y coords of placing the button are fine from the very beginning only that size is the problem. – proti Jan 25 '14 at 18:42
0

I think I finally managed. @Philipp thank you for the direction and stack overflow for the Related column on the right. I have found that post, stackoverflow.com/questions/14544260/ and I rewrite a bit of the resize function pasted and it worked! I am happy, I have been fighting with that from yesterday.

Community
  • 1
  • 1
proti
  • 213
  • 3
  • 11