HTML Canvas& Javascript - 悬停和点击事件

时间:2017-04-27 16:28:11

标签: javascript html canvas hover click

下面是一个脚本,它定义了两个分别绘制4个矩形按钮和1个圆形按钮的功能。我正在尝试在按钮中实现特定的Hover和Click功能(如脚本警报中所述),但我对如何执行此操作感到有些不知所措。我尝试在每次单击时调用makeInteractiveButton()函数,但这会导致很多奇数重叠和延迟。我希望脚本执行以下操作:

如果圆形按钮悬停,我希望它的fillColour可以更改,如果单击它,我希望它再次更改为代码中描述的颜色(#FFC77E用于悬停,#FFDDB0用于单击)。这应该在悬停或点击期间发生。

HTML:

<html lang="en">
<body>
    <canvas id="game" width = "750" height = "500"></canvas>
    <script type='text/javascript' src='stack.js'></script>
</body>
</html>

JavaScript的:

var c=document.getElementById('game'),
    canvasX=c.offsetLeft,
    canvasY=c.offsetTop,
    ctx=c.getContext('2d')
    elements = [];

c.style.background = 'grey';

function makeInteractiveButton(x, strokeColor, fillColor) {
    ctx.strokeStyle=strokeColor;
    ctx.fillStyle=fillColor;
    ctx.beginPath();
    ctx.lineWidth=6;
    ctx.arc(x, 475, 20, 0, 2*Math.PI);
    ctx.closePath();
    ctx.stroke();
    ctx.fill();
    elements.push({
        arcX: x,
        arcY: 475,
        arcRadius: 20
    });
}

b1 = makeInteractiveButton(235, '#FFFCF8', '#FFB85D');

c.addEventListener('mousemove', function(event) {
    x=event.pageX-canvasX; // cursor location
    y=event.pageY-canvasY;

    elements.forEach(function(element) {
        if (x > element.left && x < element.left + element.width && 
            y > element.top && y < element.top + element.height) { // if cursor in rect
          alert('Rectangle should undergo 5 degree rotation and 105% scale');
        }
        else if (Math.pow(x-element.arcX, 2) + Math.pow(y-element.arcY, 2) < 
                 Math.pow(element.arcRadius, 2)) { // if cursor in circle
            alert('Set b1 fillColour to #FFC77E.');
        }
    });
}, false);

c.addEventListener('click', function(event) {
    x=event.pageX-canvasX; // cursor location
    y=event.pageY-canvasY;

    elements.forEach(function(element) {
        if (x > element.left && x < element.left + element.width && 
            y > element.top && y < element.top + element.height) { // if rect clicked
            alert('Move all cards to centre simultaneously.');
        }
        else if (Math.pow(x-element.arcX, 2) + Math.pow(y-element.arcY, 2) < 
                 Math.pow(element.arcRadius, 2)) { // if circle clicked
            alert('Set b1 fillColour to #FFDDB0.');
        }
    });
}, false);

1 个答案:

答案 0 :(得分:1)

example canvas hitting test

一种方法是保留所有元素数据并编写一个hitTest(x,y)函数,但是当你有很多复杂的形状时,最好使用辅助画布来渲染元素的ID而不是它们的颜色和第二个画布中的x,y的颜色是hitted元素的ID,我应该提到第二个画布是可见的,它只是一个用于获取hitted元素的gelper。

Github示例:

https://siamandmaroufi.github.io/CanvasElement/

对矩形的hitTest的简单实现:

&#13;
&#13;
    var Rectangle = function(id,x,y,width,height,color){
      this.id = id;
      this.x=x;
      this.y=y;
      this.width = width;
      this.height = height;
      this.color = color  || '#7cf';
      this.selected = false;
    }

    Rectangle.prototype.draw = function(ctx){
     ctx.fillStyle = this.color;
     ctx.fillRect(this.x,this.y,this.width,this.height);
     if(this.selected){
       ctx.strokeStyle='red';
       ctx.setLineDash([5,5]);
       ctx.lineWidth = 5;
       ctx.strokeRect(this.x,this.y,this.width,this.height);
     }
    }

    Rectangle.prototype.hitTest=function(x,y){
     return (x >= this.x) && (x <= (this.width+this.x)) &&
            (y >= this.y) && (y <= (this.height+this.y));
    }

    var Paint  = function(el) {
     this.element = el;
     this.shapes = [];
    }

    Paint.prototype.addShape = function(shape){
     this.shapes.push(shape);
    }

    Paint.prototype.render = function(){
     //clear the canvas
     this.element.width = this.element.width;
     var ctx = this.element.getContext('2d');
     for(var i=0;i<this.shapes.length;i++){
      this.shapes[i].draw(ctx);
     }
    }

    Paint.prototype.setSelected = function(shape){
      for(var i=0;i<this.shapes.length;i++){
        this.shapes[i].selected = this.shapes[i]==shape;
      }
      this.render();
    }

    Paint.prototype.select = function(x,y){
     for(var i=this.shapes.length-1;i>=0;i--){
      if(this.shapes[i].hitTest(x,y)){
       return this.shapes[i];
      }
     }
     return null;
    }

    var el = document.getElementById('panel');
    var paint = new Paint(el);
    var rectA = new Rectangle('A',10,10,150,90,'yellow');
    var rectB = new Rectangle('B',150,90,140,100,'green');
    var rectC = new Rectangle('C',70,85,200,70,'rgba(0,0,0,.5)');

    paint.addShape(rectA);
    paint.addShape(rectB);
    paint.addShape(rectC);

    paint.render();


    function panel_mouseUp(evt){
     var p = document.getElementById('panel'); 
     var x = evt.x - p.offsetLeft;
     var y = evt.y - p.offsetTop;
     var shape = paint.select(x,y);
     if(shape){ 
      alert(shape.id);
     }
     //console.log('selected shape :',shape);
    }

    function panel_mouseMove(evt){
      var p = document.getElementById('panel'); 
      var x = evt.x - p.offsetLeft;
      var y = evt.y - p.offsetTop;
      var shape = paint.select(x,y);

      paint.setSelected(shape);
    }


    el.addEventListener('mouseup',panel_mouseUp);
    el.addEventListener('mousemove',panel_mouseMove);
&#13;
    body {background:#e6e6e6;}
    #panel {
     border:solid thin #ccc;
     background:#fff;
     margin:0 auto;
     display:block;
    }
&#13;
    <canvas id="panel" width="400px" height="200px"  >
    </canvas>   
&#13;
&#13;
&#13;

只需点击或移动形状

即可