<!doctype html>
<html ng-app="app">

<head>
  <script data-require="angular.js@1.5.6" data-semver="1.5.6" src="https://code.angularjs.org/1.5.6/angular.min.js"></script>
  <link rel="stylesheet" href="style.css" />
  <script src="script.js"></script>
</head>

<body ng-controller="main">
  <div class="outer">
    <div class="panel" my-canvas-wrapper>
      <canvas width="200" height="200" my-canvas-directive tracking="tracking"></canvas>
      <button class="btn1" ng-click="click('btn1')">btn1</button>
      <p ng-mouseover="hover(true)" ng-mouseout="hover(false)">Вот канвас, поверх которого кнопочка и текст. Канвасу нужно отслеживать движения мыши над ним.</p>
    </div>
    </div>
  <pre>tracking: {{tracking|json}}</pre>


</body>

</html>
/* Styles go here */
.outer {
  margin: 30px;
}

.outer {
  user-select: none;
  -moz-user-select: none;
  -webkit-user-select: none;
  -ms-user-select: none;
}

.panel {
  position: relative;
  width: 200px;
  height: 200px;
  border: 1px solid black;
}

.btn1 {
  position: absolute;
  top: 0;
  right: 0;
  height: 20px;
}

.btn2 {
  position: absolute;
  bottom: 0;
  right: 0;
}

.panel p {
  position: absolute;
  bottom: 5px; height: auto;
  left: 5px; right:5px;
  padding: 10px;
  border: 1px solid transparent;
}

.panel p:hover {
  border: 1px solid black;
}

.panel canvas {
  position: absolute;
  z-index: 0;
  background-color: #cff;
}
// Code goes here

angular.module('app', [])
  .controller('main', function($scope) {
     $scope.tracking = {clicks:{ btn1:0, btn2: 0}, hover: false };
     $scope.click = function(b) { $scope.tracking.clicks[b]++; }
     $scope.hover = function(v) { $scope.tracking.hover = v; }
  })

.directive("myCanvasWrapper", function() {
  return {
    controller: function($element) {
      this.$elem = $element;
    }
  };
})

.directive("myCanvasDirective", function() {
  return {
    scope: {
      tracking: '='
    },
    require: ['myCanvasDirective', '^?myCanvasWrapper'],
    link: function(scope, $elem, attrs, ctrls) {
      var ctrl = ctrls[0],
        wrap = ctrls[1],
        elem = $elem[0];
      
      ctrl.ctx = elem.getContext('2d');
      
      var area = wrap ? wrap.$elem : $elem;
      console.debug(area);
      var drawing = false;
      
      scope.tracking.bound = {elem: area[0].nodeName + "." + area.attr('class')};
      
      function getcoords(ev) {
        return {x:ev.offsetX, y:ev.offsetY}
      }
      
      
      area.bind('mousedown', function(e) {
        drawing = true;
        ctrl.drawStart(getcoords(e));
      });

      area.bind('mousemove', function(e) {
        scope.tracking.offset = {x:e.offsetX, y:e.offsetY};
        scope.tracking.client = {x:e.clientX, y:e.clientY};
        scope.tracking.target = e.target.nodeName;
        scope.$root.$digest();
        if(!drawing) return;
        ctrl.drawMove(getcoords(e));
      });
      
      area.bind('mouseup', function(e) {
        
        drawing = false;
        ctrl.drawStop(getcoords(e));
      });

    },
    controller: function() {
      var last;
      this.init = function(ctx) {
        this.ctx = ctx;
      }
      this.drawStart = function(p) {
        last = p;
        this.ctx.beginPath();
      };
      this.drawMove = function(p) {
        this.ctx.moveTo(last.x, last.y);
        this.ctx.lineTo(p.x, p.y);
        this.ctx.stroke();
        last= p;
      }
      this.drawStop = function(p) {
        this.ctx.clearRect(0, 0, 200, 200);
      }
    }
  };
});