2009-04-15

JavaScriptでcanvas要素内にマウスでお絵かき

マウスの要素内座標が取れるようになったので、簡単な例を一つ。

function getElementAbsPos(elem)
{
  var x = 0;
  var y = 0;
  while(elem){
    x += elem.offsetLeft;
    y += elem.offsetTop;
    elem = elem.offsetParent;
  }
  return {x:x, y:y};
}

function getMousePosOnElement(elem, ev)
{
  if(!ev){ ev = event;}//for IE
  if(elem.getBoundingClientRect){
    var bcr = elem.getBoundingClientRect();
    var x = ev.clientX - bcr.left;
    var y = ev.clientY - bcr.top;
    return {x:x, y:y};
  }
  else if(typeof(ev.pageX) == "number" && typeof(ev.pageY) == "number"){
    var pos = getElementAbsPos(elem);
    return {x:ev.pageX-pos.x, y:ev.pageY-pos.y};
  }
  else{
    return {x:0, y:0};
  }
}


var BORDER_WIDTH = 10;
var cv = document.createElement("canvas");
cv.setAttribute("width", "320");
cv.setAttribute("height", "240");
cv.style.cssText = "border: "+BORDER_WIDTH+"px solid;";
document.body.appendChild(cv);
var lastPoint = null;

cv.onmousedown = function(ev) {
  lastPoint = getMousePosOnElement(cv, ev);
  lastPoint.x -= BORDER_WIDTH;
  lastPoint.y -= BORDER_WIDTH;
}
cv.onmousemove = function(ev) {
  if(lastPoint){
    var currPoint = getMousePosOnElement(cv, ev);
    currPoint.x -= BORDER_WIDTH;
    currPoint.y -= BORDER_WIDTH;
    var ctx = cv.getContext("2d");
    ctx.beginPath();
    ctx.moveTo(lastPoint.x, lastPoint.y);
    ctx.lineTo(currPoint.x, currPoint.y);
    ctx.stroke();
    lastPoint = currPoint;
  }
}
cv.onmouseup = function(ev) {
  lastPoint = null;
}
cv.onmouseout = function(ev) {
  lastPoint = null;
}

例によってインタラクティブコンソールへ貼り付けて実行可能。

getMousePosOnElementより上は昨日書いたとおり。

borderを太くするとその分座標がずれてしまうので、そのあたりは適切に補正してやる必要がありました。