views:

95

answers:

2

Hello all,

I'm trying to accomplish what's being demonstrated at this site for an experiment I'm working on. The blocks are to be selected via mouseclick I suppose. As a Javascript newbie, I don't know where to begin something like this myself. Adding the HTML canvas element into the mix (since it's gaining in popularity and pretty good at manipulating pixel) would be a pretty nice addition. Also, I'd like it if certain blocks couldn't be selected (perhaps have then grayed out) if they've been selected already given their coordinates.

I hope I've made myself clear. Can anyone out there help me? Could somebody point me in the right direction?

Thanks-a-million! Dude-Dastic

A: 

Here's an interesting article with lots of examples that can get you started on Per-pixel manipulation. You'll basically need to make an array and modify it at the level that you want.

http://beej.us/blog/2010/02/html5s-canvas-part-ii-pixel-manipulation/

agscala
Thanks for the link, agscala. That is some very intimidating stuff.
Dude-Dastic
+1  A: 

You use

id=context.getImageData(x, y, w, h);
//id.data is an array of the format [r, g, b, a, r, g, b, a]

You then use context.putImageData(id, x, y);
I have applied this in places such as particle effects using canvas [where particles are 1x1 pixel large], my simple 3d render, color selector, etc.

Its helpful.

--- Update: Didn't realize you were asking about traversing DOM tree... --- ------ The below code will find the DOM element that has been clicked. Note that for textnodes that are direct children of document.body, you must wrap a or some sort of container around them. This is because they don't have the exact same properties as element_nodes ... For your grid-like effect, it would be very easy to extend this. Once you get the hit object's x/y, you could do the drawing. By the way, for your situation, setting pixels one at a time probably isn't the best thing you can do. I suggest you look into context.fillStyle="#RRGGBB"; context.fillRect(x, y, w, h); which in your example, would be context.fillStyle="#0000FF"; context.fillRect(x, y, 100, 100); ...

<html>
<head>
<script>
function Rect(x, y, w, h)
{
    this.x = x;
    this.y = y;
    this.w = w;
    this.h = h;

    this.hitTest = function(x, y)
    {
        if(this.x > x) return false; //If LEFT BORDER is right of x, fail
        if(this.x + this.w < x) return false; //IF RIGHT BORDER is LEFT of x, fail
        if(this.y > y) return false; //IF MY TOP IS BELOW y, fail
        if(this.y + this.h < y) return false;//if my BOTTOM is above y, fail
        return true;
    }
};
//original: http://www.quirksmode.org/js/findpos.html 
//Func was changed a little
function findPos(obj) {
    var curleft = curtop = 0;
    try
    {
        if (obj.offsetParent) {
            do {
                curleft += obj.offsetLeft;
                curtop += obj.offsetTop;
            } while (obj = obj.offsetParent);
        }
    }catch(e){}; //Sometimes offset parent isn't Assumedined... so we just stop and return
    return [curleft,curtop];
}

function findScreenPos(obj) {
    var curleft = curtop = 0;
    try
    {
        if (obj.offsetParent) {
            do {
                curleft += obj.offsetLeft;
                curtop += obj.offsetTop - obj.scrollTop;
            } while (obj = obj.offsetParent);
        }
    }catch(e){}; //Sometimes offset parent isn't Assumedined... so we just stop and return
    return [curleft,curtop];
}
findElementUnderMouseInNode      = function(node)
{
   //Note that this function excludes our canvas.
   var cnl = node.childNodes.length;
   for(var i = 0; i < cnl; i++)
   {
      var childNode = node.childNodes[i];
      if((childNode.toString() != "[object Comment]") && (childNode != "[object Text]"))
      {
         {
            var childNodePos = findScreenPos(childNode);
            var pos = new Rect(childNodePos[0], childNodePos[1], childNode.offsetWidth, childNode.offsetHeight);
            if(pos.hitTest(_xmouse, _ymouse))
            {
               var deeperNode = findElementUnderMouseInNode(childNode);
               if(deeperNode == null)
                  return childNode;
               else
                  return deeperNode;

            }
         }
      }
   }
   return null;
};
window.onmousedown = function(e){
  if(e.pageX)
  {
    _xmouse = e.pageX;
    _ymouse = e.pageY;
  }
  else
  {
    if(typeof(event) == "undefined") return;
    _xmouse = event.clientX + document.body.scrollLeft;
    _ymouse = event.clientY + document.body.scrollTop;
  }
  var n = findElementUnderMouseInNode(document.body);
  var mydiv = document.createElement("div");
  mydiv.style.position = "absolute";
  mydiv.style.left = findPos(n)[0] + "px";
  mydiv.style.top  = findPos(n)[1] + "px";
  mydiv.style.width= n.offsetWidth + "px";
  mydiv.style.height= n.offsetHeight + "px";
  mydiv.style.border = "1px #FFFF00 solid";
  mydiv.style.backgroundColor = "#FFFF00";
  mydiv.style.opacity = 0.5;
  document.body.appendChild(mydiv);
}
</script>
</head>
<body>
<span>asdf</span><br>
<img src="" width="100" height="100" />
<div>LOL</div>
asdf
</body>
</html>

Logic of the function:
The function gets the childnodes of an element.
If (the node is not a comment node or a text node) AND the child isn't your canvas
Search the node's childnodes [be more precise, select the element that is at the edge of the DOM tree, otherwise you might as well be saying "the user clicked the document.body"]

If the childNode has a childnode that was hit, return that, otherwise return yourself.

ItzWarty
Maybe I should think of accomplishing this some other way. Javascript and the canvas element both has steep learning curves. Anyway, thanks for your help, ItzWarty.
Dude-Dastic
I actually didn´t realize you were trying to find out what node was being selected. I know how to do that. I´ll update my answer, i´m getting the code out right now. What you´re looking for is a way to ¨traverse dom¨ which i used in my first CMS...
ItzWarty
I've learned how to actually draw the grid on the canvas by going to http://diveintohtml5.org/canvas.html. I can also use a background image via css display the grid. Now I'm trying to select a 10 x 10 block by mouse click and have it be highlighted. I also need to gather mouse coordinates somehow.
Dude-Dastic
WOW! Thanks for the code, ItzWarty! I'll give it a try and see what happens!
Dude-Dastic
Look at the code I provided. the mouse's x/y position is stored in _xmouse and _ymouse...
ItzWarty
By the way, on the example, what you have to do is click on one of the nodes in the document [the image node, the text node, the div] and it'll be hi-lited...
ItzWarty
The code works like a charm, ItzWarty! Awesome stuff. I've since eliminated the canvas element in favor of a single div element that houses other div elements with numeric IDs for selection. What I need now is a way to unselect an element (you know, I might not like my selection and want to change it before doing other things) and retrieve the coordinates of the selected elements for database storage. Thanks a bunch!
Dude-Dastic