We help IT Professionals succeed at work.

Complex canvas clip shape

I would like to clip everything that is grey in the image below.  That is I would like only the two images of the person to show through the clipping. How can I do that?
Pain diagram
Comment
Watch Question

CERTIFIED EXPERT
Top Expert 2015
Commented:
This idea may not be the exact user experience you are looking for, but the end result is the same; only the bodies get drawn upon. On mouseup, the gray background is restored to original leaving the red lines on the bodies where you drew them.
<script type="text/javascript">
// Keep everything in anonymous function, called on window load.

if(window.addEventListener) {
window.addEventListener('load', function () {
  var canvas, context, tool, pixels;

  function init () {
    // Find the canvas element.
    canvas = document.getElementById('imageView');
    if (!canvas) {
      alert('Error: I cannot find the canvas element!');
      return;
    }

    if (!canvas.getContext) {
      alert('Error: no canvas.getContext!');
      return;
    }

    // Get the 2D canvas context.
    context = canvas.getContext('2d');
    if (!context) {
      alert('Error: failed to getContext!');
      return;
    }
	
	var img=new Image();
	img.onload = function(){
	
	context.drawImage(img,0,0);
	var imageData = context.getImageData(0, 0, 525, 482);
    pixels = imageData.data;
    
    
	};
	
	img.src="PainDiagram.png";
    // Pencil tool instance.
    tool = new tool_pencil();
    
    // Attach the mousedown, mousemove and mouseup event listeners.
    canvas.addEventListener('mousedown', ev_canvas, false);
    canvas.addEventListener('mousemove', ev_canvas, false);
    canvas.addEventListener('mouseup',   ev_canvas, false);
  }
   

  // This painting tool works like a drawing pencil which tracks the mouse 
  // movements.
  function tool_pencil () {
    var tool = this;
    this.started = false;

    // This is called when you start holding down the mouse button.
    // This starts the pencil drawing.
    this.mousedown = function (ev) {
		context.beginPath();
		context.lineWidth = 10;
		context.lineCap = "round";
		context.strokeStyle = "red"; // line color
		context.globalAlpha=0.005;
        //context.arc(ev._x, ev._y,5,0,Math.PI*2,false);
        context.moveTo(ev._x, ev._y);
        tool.started = true;
    };

    // This function is called every time you move the mouse. Obviously, it only 
    // draws if the tool.started state is set to true (when you are holding down 
    // the mouse button).
    this.mousemove = function (ev) {
      if (tool.started) {
        //context.arc(ev._x, ev._y,5,0,Math.PI*2,false);
        context.lineTo(ev._x, ev._y);
        context.stroke();
      }
    };

    // This is called when you release the mouse button.
    this.mouseup = function (ev) {
      if (tool.started) {
        tool.mousemove(ev);
        tool.started = false;
	    var imageData2 = context.getImageData(0, 0, 525, 482);
        var newPixels = imageData2.data;
        for (var i = 0, il = pixels.length; i < il; i += 4) {
            if(pixels[i] > 204 && pixels[i] < 209){
                newPixels[i] = pixels[i];
            }
            if(pixels[i+1] > 204 && pixels[i+1] < 209){
                newPixels[i+1] = pixels[i+1];
            }
            if(pixels[i+2] > 204 && pixels[i+2] < 209){
                newPixels[i+2] = pixels[i+2];
            }
        }
        context.putImageData(imageData2, 0, 0);
      }
    };
  }

  // The general-purpose event handler. This function just determines the mouse 
  // position relative to the canvas element.
  function ev_canvas (ev) {
    if (ev.layerX || ev.layerX == 0) { // Firefox
      ev._x = ev.layerX;
      ev._y = ev.layerY;
    } else if (ev.offsetX || ev.offsetX == 0) { // Opera
      ev._x = ev.offsetX;
      ev._y = ev.offsetY;
    }

    // Call the event handler of the tool.
    var func = tool[ev.type];
    if (func) {
      func(ev);
    }
  }

  init();

}, false); }

</script>

Open in new window

CERTIFIED EXPERT

Author

Commented:
I don't believe the for loop is working. I changed the code to what's below to test it but did not see a change. An alert placed just before the for loop showed that the mouseup function is being called.
      this.mouseup = function (ev) 
	  {
	      if (tool.started) 
		  {
	        tool.mousemove(ev);
	        tool.started = false;
		var imageData2 = context.getImageData(0, 0, 700, 643);
	        var newPixels = imageData2.data;
	        for (var i = 0, il = pixels.length; i < il; i += 1) 
			{
	                pixels[i] = 0 ;
	        }
		  }	  
       };	

Open in new window

CERTIFIED EXPERT
Top Expert 2015

Commented:
pixels[i] = 0 ;

Open in new window

would not change the display because you are affecting only the original array of pixels. Plus you are not writing back to the canvas when the loop is done. To affect the new array (after drawing on it), use
newPixels[i] = 0;

Open in new window

. I tried it, and as expected, it set the red channel to zero making the image a turquoise color (mix of green and blue).

I have noticed that this whole script seems to only work in Firefox. Results from my test of the loop as written in the script I posted are attached. I'm using version 9.0.1.
canvas.jpg
CERTIFIED EXPERT
Top Expert 2015

Commented:
It works in Safari 5.1.4.

In IE7 and IE8, the image never displays.

Drawing on the canvas does not work in Chrome and Opera.

The issues may be the method used for finding the mouse position relative to the canvas. offsetX and layerX may not be recognized in the non-working browsers. Sounds like material for a new question.
CERTIFIED EXPERT
Top Expert 2015

Commented:
You can simplify the loop to this if you first bring the PainDiagram.png into photoshop or similar program and "purify" the gray background by making all pixels in the gray areas rgb(206,206,206).
var imageData2 = context.getImageData(0, 0, 525, 482);
        var newPixels = imageData2.data;
        for (var i = 0, il = pixels.length; i < il; i += 4) {          
            if(pixels[i] == 206 && pixels[i+1] == 206 && pixels[i+2] == 206){
                newPixels[i] = 206;
                newPixels[i+1] = 206;
                newPixels[i+2] = 206;
            }
        }
        context.putImageData(imageData2, 0, 0);

Open in new window

CERTIFIED EXPERT

Author

Commented:
The reason it wasn't working for me is I missed your changes (and didn't copy them) in the onload routine:
        var imageData = context.getImageData(0, 0, 525, 482);
        pixels = imageData.data;

I changed the mouseup code to below. This has the advantage of not writing over the black as well.

The image does show in IE 9 but will not draw after adding your changes. It did work before adding the changes.

Another problem is the mouseup event does not fire if the mouse is moved off the image before being released.

 Here is the URL of the project while I'm working on it:  www.barnwellmd.com/paint.html

Here's a link to another pain diagram that they have solved some of the problems. They have some other problems however: http://www.hommenorthopedics.com/questionnaire.php
          if(pixels[i] != 255 || pixels[i+1] != 204 || pixels[i+2] != 153){
                newPixels[i] = pixels[i];
                newPixels[i+1] = pixels[i+1];
                newPixels[i+2] = pixels[i+2];
          }

Open in new window

CERTIFIED EXPERT

Author

Commented:
With a couple of tweaks, this is the method I used.   Thanks for your help!
CERTIFIED EXPERT

Author

Commented:
tommyBoy,

You have been so helpful with my past questions, I wanted to point out this one: http:Q_27637145.html

Explore More ContentExplore courses, solutions, and other research materials related to this topic.