allocen
allocen

Reputation: 79

Javascript Canvas complexity

I'm trying to replicate a GPS map system from a game into the web. Basically there are 12 maps in the game each having a different safearea where you can warp your character or go, but i'm having some issues along the way.

Check it here

function ntGps($timeout) {
return {
    restrict: 'E',
    replace: true,
    scope: {
        ntMap: '@',
        ntX: '@',
        ntY: '@'
    },
    template: '<div class="nt-gps"><div class="nt-content"></div></div>',
    link: link
};

function link(scope, el) {
    var q = el[0].querySelector("div.nt-content"),
        m = new Image(),
        a = new Image(),
        c = document.createElement("canvas");

    m.src = "http://i.imgur.com/vD9jua7.png";
    a.src = "http://i.imgur.com/AU2peAy.png";

    scope.$watch(e, l);

    function e() {
        return el[0].clientWidth;
    }

    function l(s) {
        var x, y;

        scope.style = {
            'width': s + "px",
            'height': s + "px"
        };


        c.width = s;
        c.height = s;

        m.onload = _d;

        if (m.complete) {
            _d();
        }

        function _d() {
        var _c = c.getContext("2d"),
                        _x = Math.floor((s * scope.ntX) / 256, 10) + 4,
                        _y = Math.floor((s * scope.ntY) / 256, 10) + 4;

                    _c.drawImage(a, 0, 0, 512, 512, 50, 50, s - 100, s - 100);



                    _c.globalCompositeOperation = "lighten";

                    _c.drawImage(m, 0, 0, 512, 512, 0, 0, s, s);


                    c.addEventListener("click", function(e) {
                        // console.log(_c.getImageData(0, 0, 1, 1));
                        var clickedX = e.pageX - this.offsetLeft;
                        var clickedY = e.pageY - this.offsetTop;

                        console.log(e);
                    });
        }
    }

    q.appendChild(c);

}

}

This is part of the code above.

The link above is taken as example for the first map. So as you can see, there are 2 images, first is the map itself and 2nd one over the first is where the player should be able to click to warp its character from the web, clicking outside the white area is restricted, but here is a problem too, that image with white colors should be transparent though, so the player can only see the map itself without the safearea map image, so if he tries to click elsewhere outside where the safezone allows nothing happen otherwise print for now a console.log with the specific event so i that can take the x,y coords for further use.

So again, there are 12 totals maps each unique, with a unique safezone.

Can anyone help me sort this out? Much thanks.

Upvotes: 0

Views: 88

Answers (1)

Kaiido
Kaiido

Reputation: 136627

I'm not sure I got exatly what you're asking for, but from my understanding, you want to know if user clicked in a white pixel from your "safe-area" image.

To do this, you just have to save the imageData of your safe-area at launch, and then check in this imageData's data, if the pixel at coordinate x y is white (255, 255, 255, 255).

Note: I wasn't able to make your angular code to work, so I rewrite it.

var ctx = canvas.getContext('2d');
var s = canvas.width = canvas.height = 457;

var data; // here we will store our safe area's imageData

function isSafeArea(x, y) {
  // flatten our coordinates (y * w + x) & multiply by 4 (4 slots per pixels)
  // (canvas.width * y + x) * 4
  // or bitwise shift
  var flattened = (canvas.width * y + x) << 2;
  // here we can just check for alpha value since it's either transparent or white, 
  // I set the threshold a bit low in case of antialiasing, but you can be more strict
  return data[flattened + 3] > 125;
}

var safeArea = new Image();
// when it has loaded, save its image data
safeArea.onload = initSafeArea;
// we need it to not taint our canvas, so we'll use a proxy here
safeArea.crossOrigin = 'anonymous';
safeArea.src = "https://crossorigin.me/http://i.imgur.com/AU2peAy.png";

var shownMap = new Image();
shownMap.onload = function() {
  if (data) // if we already initialised the safeArea
    draw()
};
shownMap.src = "http://i.imgur.com/vD9jua7.png";

function initSafeArea() {
  ctx.drawImage(this, 0, 0, 512, 512, 50, 50, s - 100, s - 100);
  data = new Uint32Array(ctx.getImageData(0, 0, canvas.width, canvas.height).data);
  if (shownMap.naturalWidth) {
    draw();
  }
  canvas.addEventListener("mousemove", onmousemove);
}

function draw() {
  ctx.drawImage(shownMap, 0, 0, 512, 512, 0, 0, s, s);
  if (toggle.checked) {
    ctx.drawImage(safeArea, 0, 0, 512, 512, 50, 50, s - 100, s - 100);
  }
}
var peg = new Image();
peg.src = "https://maps.gstatic.com/tactile/pegman_v3/default/runway-1x.png";

var clickedX, clickedY,
    moving = false;
function handleMoveMove(){
  moving = false;
  draw();
  if(isSafeArea(clickedX, clickedY)){
    canvas.style.cursor = 'none';
    ctx.drawImage(peg, 0,0, 28, 28, clickedX-14, clickedY-14, 28, 28)
    }
  else{
    canvas.style.cursor = 'default';
    }
  }
// I changed the event so I debounce it
function onmousemove(e) {
  clickedX = e.pageX - this.offsetLeft;
  clickedY = e.pageY - this.offsetTop;
  if(!moving){
    requestAnimationFrame(handleMoveMove);
    }
  moving = true;
}
toggle.onchange = draw;
<label>show the safe area :
  <input type="checkbox" id="toggle">
</label>
<br>
<canvas id="canvas"></canvas>

Upvotes: 1

Related Questions