Web 技术研究所

我一直坚信着,Web 将会成为未来应用程序的主流

简单鼠标手势处理

  貌似现在很流行使用手势吧?无论是触屏还是鼠标都可以使用手势,触屏还有直接给定的手势事件,鼠标上就需要自己实现了。实现复杂的手势一般都牵涉到图像别技术,不过我觉得复杂手势的可用性不高,用户一般记不住复杂的东西,所以咱只要实现简单手势就OK~。
  简单手势就是最基本的上下左右划动,它的处理就不需要用到麻烦的图像识别技术,只要对手势的轨迹做一些简单的计算即可。不过鼠标和触屏设备是不同的概念。鼠标的移动是很普遍的,左键拖动也经常被其它功能使用者,要做鼠标手势的话一般会用右键拖动来划出轨迹。而处理鼠标右键还要涉及到浏览器的环境菜单问题,这些问题一般都可以解决,只是在火狐上有点奇葩而已。在Chrome中有自动捕获事件的机制,在IE中可以使用setCapture来捕获。但是在火狐中,既没有自动捕获机制,也没有IE那么完善的setCapture方法,所以实现起来效果就有一些缺陷。在一些国产浏览器上甚至有对鼠标右键拖动做劫持的(360浏览器、搜狗浏览器),这种行为非常恶劣,我代表党和人民强烈谴责它们!就如同鄙视一些手机浏览器对多点触控的劫持一样!不过随着将来Web技术的发展,我觉得这些浏览器都会放弃这些恶劣的做法,至少提供API让页面程序可以阻止浏览器自带各种花样。
  下面实现简单鼠标手势的实例,这里为了方便用的jQuery,并且轨迹绘制是通过CANVAS来实现的,故没做IE8-的兼容。不过整个程序的逻辑就在这里如果非要实现兼容(甚至改成触屏方式)也是没问题的。
<!DOCTYPE html>
<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
<script>
//添加鼠标事件
$(document.documentElement).mousedown(function(e){
  //只负责鼠标右键
  if(e.button!=2)return;
  //声明变量
  var track=[],dist=0,events,canvas,g;
  //记录当前鼠标位置
  track.push([e.clientX,e.clientY]);
  //创建一个用于绘制轨迹的CANVAS
  g=(canvas=$("<canvas/>").css({
    position:"fixed",zIndex:1000,top:0,left:0
  }).appendTo(document.body).attr({
    width:this.clientWidth,height:this.clientHeight
  })).get(0).getContext("2d");
  //初始化轨迹绘制
  g.lineWidth=3,g.moveTo(track[0][0],track[0][1]);
  //设置Capture,兼容IE和FF
  if(this.setCapture)this.setCapture();
  //绑定过程事件
  $(this).on(events={
    mousemove:function(e){
      //绘制轨迹
      g.lineTo(e.clientX,e.clientY),g.stroke();
      //记录轨迹
      track.push([e.clientX,e.clientY]);
    },mouseup:function(e){
      //只负责鼠标右键
      if(e.button!=2)return;
      //释放Capture,兼容IE和FF
      if(this.releaseCapture)this.releaseCapture();
      //移除CANVAS
      canvas.remove();
      //在消息队列中添加一个动作
      setTimeout(function(){
        //注销事件
        $(this).off(events);
      }.bind(this),0);
      //如果轨迹太短则不做其它事情
      if(track.length<2)return;
      //初始化变量
      var i=0,o,a,b,c,d,k,st,ed;
      //遍历轨迹,找到轨迹所在的最小矩形区域
      while(o=track[i++])
        o[0]>=a||(a=o[0]),o[0]<=b||(b=o[0]),
        o[1]>=c||(c=o[1]),o[1]<=d||(d=o[1]);
      //计算轨迹矩形宽度和高度
      k=(d-c)/(b-a);
      //获取轨迹的开始位置和结束位置
      a=track[0],b=track[track.length-1];
      //计算鼠标开始位置到结束位置的水平和垂直距离
      c=a[0]-b[0],d=a[1]-b[1];
      //斜率大于1(垂直)
      if(k>1){
        //根据鼠标开始和结束位置判断方向
        if(d<-100)console.log("↓");
        if(d>100)console.log("↑");
      };
      //斜率小于1(水平)
      if(k<1){
        //根据鼠标开始和结束位置判断方向
        if(c<-100)console.log("→");
        if(c>100)console.log("←");
      };
      //计算鼠标从开始到结束的垂直距离
      dist=Math.sqrt(c*c+d*d);
    },contextmenu:function(){
      //如果鼠标移动的距离不小于100就阻止右键菜单
      return dist<100;
    }
  });
});
</script>

  运行这个代码,按住鼠标右键在文档上拖动就可以出现出轨迹。松开鼠标后便可以在控制台找到轨迹的手势。但是由于火狐的setCapture存在BUG,它不作用于contextmenu事件,所以当轨迹拖到文档外时将无法阻止右键菜单(虽然这个问题影响不大)。
  其实我的代码用了比较麻烦的算法,实际上只记录鼠标的开始和结束位置,中间的轨迹当做直线也可以做出简单手势(如果真的只需要这点功能的话)。我的做法是计算轨迹的,只要在最后的计算中做改动就可以实现一些稍微复杂的手势(比如V型之类的)。
网名:
3.80.32.*
电子邮箱:
仅用于接收通知
提交 悄悄的告诉你,Ctrl+Enter 可以提交哦
神奇海螺
[查看全部主题]
各类Web技术问题讨论区
发起新主题
本模块采用即时聊天邮件通知的模式
让钛合金F5成为历史吧!
次碳酸钴的技术博客,文章原创,转载请保留原文链接 ^_^