-1

I made this with DOM events and CSS transitions and I'm really struggling to figure out how to make something like this with canvas. I want to be able to have touch events and eventually play sounds.

I was looking at phaser.js and it seems promising, but creating event handlers on shapes isn't built in.

It seems like the idea is to draw a bunch of rectangles, listen to touch and click events on the entire canvas, then figure out which corresponding rectangle to animate... but I'm lost just thinking about it.

So easy with DOM, so difficult with canvas? All help greatly appreciated.

azium
  • 20,056
  • 7
  • 57
  • 79

1 Answers1

2

It's not so difficult when you know that the canvas is a single element containing multiple drawings. Only the canvas element itself triggers events. Each of the multiple drawings on the canvas do not trigger individual events.

So to do your effect on canvas you must manually handle these tasks:

  • save definition of each sound-bar: it's x,y position along with it's width & height

  • listen for mouse events

  • manually test if the mouse event occurred inside one of the sound-bars by hit-testing the mouse against each saved sound-bar

  • if the mouse is inside a particular sound-bar, play that bar's sound and highlight that bar with color.

Here's example annotated code and a Demo:

// canvas related variables
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
var $canvas=$("#canvas");
var canvasOffset=$canvas.offset();
var offsetX=canvasOffset.left;
var offsetY=canvasOffset.top;

// create an array of objects representing each sound to be played
var sounds=[];
for(var i=0;i<15;i++){
  sounds.push({
    element:document.createElement('audio'),
    src:'https://dl.dropboxusercontent.com/u/139992952/multple/Ticking_Clock-KevanGC-1934595011.mp3',
    isPlaying:false
  });
  document.body.appendChild(sounds[i].element);
  sounds[i].element.src=sounds[i].src;
}

// create an array of objects representing the hit area of each "sound-bar"
var hits=[];
for(var i=0;i<15;i++){
  hits.push({x:213,y:i*43+88,w:750,h:40,fill:randomColor()});
}

// load the sound board
var img=new Image();img.onload=start;img.src="https://dl.dropboxusercontent.com/u/139992952/multple/soundboard.png";
function start(){
  // resize the canvas to image size
  canvas.width=img.width;
  canvas.height=img.height;
  // draw the sound board image
  ctx.drawImage(img,0,0);
  // listen for mousedown events
  $("#canvas").mousedown(function(e){handleMouseDown(e);});
}

// handle mousedown events
function handleMouseDown(e){
  // tell the browser we're handling this event
  e.preventDefault();
  e.stopPropagation();

  // get mouse X&Y
  mx=parseInt(e.clientX-offsetX);
  my=parseInt(e.clientY-offsetY);

  // hit test each sound-bar
  for(var i=0;i<hits.length;i++){
    var h=hits[i];
    // define this sound-bar by drawing it (no stroke/fill)
    ctx.beginPath();
    ctx.rect(h.x,h.y,h.w,h.h);
    // is the mouse in this particular sound-bar
    if(ctx.isPointInPath(mx,my)){
      var s=sounds[i];
      // if this bar is playing sound, pause
      // and redraw the un-highlighted sound board
      if(s.isPlaying){
        s.element.pause();
        ctx.clearRect(0,0,cw,ch);
        ctx.drawImage(img,0,0);
        // if this bar is silent, start playing
        // and fill this bar with a highlight color
      }else{
        s.element.play();
        ctx.fillStyle=hits[i].fill;
        ctx.fill();
      }
      s.isPlaying=!s.isPlaying;
    }
  }
}

// adjust for window scrolling
window.onscroll=function(e){
  var BB=canvas.getBoundingClientRect();
  offsetX=BB.left;
  offsetY=BB.top;
}

// utility: get a random color
function randomColor(){ 
  return('#'+Math.floor(Math.random()*16777215).toString(16));
}
body{ background-color: ivory; }
#canvas{border:1px solid red;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<h4>Click on a sound-bar to play it's sound<br>Click again to pause its sound</h4>
<canvas id="canvas" width=300 height=300></canvas>
markE
  • 102,905
  • 11
  • 164
  • 176
  • Wow thanks that was very thorough! I did manage to create a canvas version in the meantime but it's great to see this approach. [Here's my latest version](http://note-pad.meteor.com/) – azium Mar 08 '15 at 06:16