zoukankan      html  css  js  c++  java
  • canvas-圆弧形可拖动进度条

    使用方式

    npm i drag-arc -S

    import DragArc from 'drag-arc';

    源码地址:https://github.com/pangyongsheng/canvas-arc-draw

    一、效果如下:

     

     

    链接dome

    二、

    本文是实现可拖动滑块实现的基本思路,及一个简单的dome,(https://github.com/pangyongsheng/canvas-arc-draw

    三、

    1、首先在html中创建一个canvas标签

    <canvas id="canvas"  width="400" height="400"></canvas>

    2、创建一个进度条对象,编写初始化方法,获取canvas对象及上下文环境;event方法是用来绑定事件(具体后面介绍);draw是用来绘图的方法,这里把Draw对象的全部方法赋给draw方法;创建绘图实例p,绘制初始图形;

    var Draw={
       init:function(){
        this.obj=document.getElementById("canvas");    //获取canvas对象
        this.cObj=document.getElementById("canvas").getContext("2d");//获取canvas对象上下文环境
        this.event();   //初始化事件
        this.pathr=120; //滑动路径半径
        this.draw.prototype=this; //draw继承Draw方法
        this.p=new this.draw(112,284,18);  //创建实例p
      } 
      //... 
    }

    3、在Draw中编写绘图方法draw绘制下图:

    (1)创建绘图方法,获取参数

    draw:function(x,y,r,j){  //绘图
          this.cObj.clearRect(0,0,400,400);    //清空画布
          this.x=x;   //滑块坐标x
          this.y=y;   //滑块坐标y 
          this.r=r;    //滑块移动路径半径
          this.j=j;    //橙色圆弧结束弧度值
          //...
    }

     (2)绘制内侧圆弧

    this.cObj.beginPath();
    this.cObj.lineWidth = 1;
    this.cObj.arc(200,200,100,Math.PI*0.75,Math.PI*2.25,false); // 绘制内层圆弧
    this.cObj.strokeStyle = '#0078b4';
    this.cObj.stroke();

    (3)绘制外侧圆弧

    this.cObj.beginPath();
    this.cObj.arc(200,200,120,Math.PI*0.75,Math.PI*2.25,false); // 绘制外侧圆弧
    this.cObj.strokeStyle = '#c0c0c0';
    this.cObj.lineCap = "round";
    this.cObj.lineWidth = 20;
    this.cObj.stroke();

    (4)绘制滑块

      由于滑块是可以移动的这里滑块的位置使用了坐标参数xy,及滑块半径r作为可变参数

    this.cObj.beginPath();
    this.cObj.moveTo(200,200);
    this.cObj.arc(x,y,r,0,Math.PI*2,false); // 绘制滑块
    this.cObj.fillStyle='#f15a4a';
    this.cObj.fill();
    
    this.cObj.beginPath();
    this.cObj.moveTo(200,200);
    this.cObj.arc(x,y,11,0,Math.PI*2,false); // 绘制滑块内侧白色区域
    this.cObj.fillStyle='#ffffff';
    this.cObj.fill();

     (5)绘制长度可变弧(橙色部分):

    由于长度可变,这里把闭合弧度作为可变参数

    this.cObj.beginPath();
    this.cObj.arc(200,200,120,Math.PI*0.75,this.j,false); // 可变圆弧
    this.cObj.strokeStyle = '#f15a4a';
    this.cObj.lineCap = "round";
    this.cObj.lineWidth = 20;
    this.cObj.stroke();

    至此绘图方法完成,调用drow方法并传入参数滑块坐标、半径和拖动弧度(x,y,r,j)即可完成图片的绘制。

    4、绘图方法分析

    (1)这里首先建立以canvas左上角为原点屏幕坐标系,后面的绘图都将基于该坐标系,坐标图像如下:

    编写获取当前光标位置点相对canvas坐标系(lx,ly)的方法:即当前坐标点减去canvas偏移距离

      getx:function(ev){  //获取鼠标在canvas内坐标x
        return ev.clientX-this.obj.getBoundingClientRect().left;
      },
      gety:function(ev){  //获取鼠标在canvas内坐标y
        return ev.clientY-this.obj.getBoundingClientRect().top;
      }

    (2)为方便构建圆的方程,这里建立一个以canvas中心为原点的坐标系,如下图,在实际使用draw方法绘图时使用的是黑色的坐标系,在使用圆的路径处理是我们使用红色的坐标系

    下面添加坐标转化方法,

    屏幕坐标(黑色坐标)->中心坐标(红色坐标)

    spotchange:function(a){ //屏幕坐标转化为中心坐标 
        var target={};
        if(a.x<200 && a.y<200){      //二象限
            target.x=-(200-a.x); 
            target.y=200-a.y; 
        }else if(a.x>200 && a.y<200){  //一象限  
            target.x=a.x-200; 
            target.y=200-a.y; 
        }else if(a.x>200 && a.y>200){  //四象限
            target.x=a.x-200;
            target.y=-(a.y-200) 
        }else if(a.x<200 && a.y>200){  //三象限
            target.x=-(200-a.x); 
            target.y=-(a.y-200); 
        } 
        return target; 
    },

    中心坐标(红色坐标)->屏幕坐标(黑色坐标)

    respotchange:function(a){ //中心坐标转化为屏幕坐标
        var target={};
        if(a.x>0 && a.y>0){
          target.x=200+a.x;
          target.y=(200-a.y);
        }else if(a.x<0 && a.y>0){
          target.x=200+a.x;
          target.y=200-a.y;
        }else if(a.x<0 && a.y<0){
          target.x=200+a.x;
          target.y=-(a.y-200)
        }else if(a.x>0 && a.y<0){
          target.x=200+a.x;
          target.y=-(a.y-200);
        }
        return target;
      },

    (3)滑块路径及位置计算方法

      首先不考虑xy正负,

      计算光标位置点的正切值

      tanφ = ly/lx;

      可知φ

      φ=arctan(tanφ)

      根据圆的参数方程,可获得光标点对应蓝色路径位置坐标为 

      x=rcosφ

      y=rsinφ

    (4)根据上面思路编写获取坐标位置方法,这里添加了xy和弧度值正负处理方法和可拖动弧度范围

      getmoveto:function(lx,ly){
          if(!this.p.isDown){    //是否可移动
            return false;
          }
          var tem={};    //存放目标坐标位置
          tem.o=Math.atan(ly/lx); //鼠标移动点圆形角
          tem.x=this.pathr*Math.cos(tem.o);
          tem.y=this.pathr*Math.sin(tem.o);
          if(lx<0){ //坐标点处理(正负)
            tem.x=-tem.x;
            tem.y=-tem.y;
          }
         if(lx>0){  //弧度值处理
          tem.z=-Math.atan(tem.y/tem.x)+Math.PI*2;
         }else{
          tem.z=-Math.atan(tem.y/tem.x)+Math.PI;
         }
         if(tem.z>7.06){  //最大值
          tem.z=7.06;
          tem.x=this.pathr*Math.cos(Math.PI*2.25);
          tem.y=-this.pathr*Math.sin(Math.PI*2.25);
         }
         if(tem.z<2.4){ //最小值
          tem.z=2.4;
          tem.x=this.pathr*Math.cos(Math.PI*0.75);
          tem.y=-this.pathr*Math.sin(Math.PI*0.75);
         }
        return tem;
       },

    (5)以上方法在canvas内任意点均可作为滑块拖动的目标点,这里编写cheack方法,将限制可拖动位置限制在一个大概的环形里

    check:function(x,y){  //限制可拖动范围
        var xx=x*x;
        var yy=y*y;
        var rr=114*114; //最小
        var rrr=126*126;  //最大
        if(xx+yy>rr && xx+yy<rrr){
          return true;
        }
        return false;
      },

    5、事件方法编写

    (1)鼠标按下执行方法OnMouseDown

    这里使用了getx和gety获取光标相对canvas坐标,并判断鼠标是否移动到了滑块上方位置内,(this.p是当前绘图对象,p.x即滑块横坐标,p.x即当前纵坐标,p.r即滑块最大半径),如果光标在滑块上方则设置isDown为TRUE,反正依然,后面我们会通过isDown来判断是否执行移动滑块的方法:

    OnMouseDown:function(evt){
        var X=this.getx(evt);    //获取当前鼠标位置横坐标
        var Y=this.gety(evt);     //获取当前鼠标位置纵坐标
        var minX=this.p.x-this.p.r;  
        var maxX=this.p.x+this.p.r;
        var minY=this.p.y-this.p.r;
        var maxY=this.p.y+this.p.r;
         if(minX<X && X<maxX && minY<Y && Y<maxY){   //判断鼠标是否在滑块上 
             this.p.isDown=true;      
         }else{
              this.p.isDown=false;
         }
    }

    (2)鼠标按下后移动时滑块的方法:

       OnMouseMove:function(evt){ //
           if(this.p.isDown){    //是否在滑块上按下鼠标
              var a={};         //存放当前鼠标坐标
              a.x=this.getx(evt);    //坐标转化
              a.y=this.gety(evt);
              var b=this.spotchange(a);    //坐标转化
              var co=this.getmoveto(b.x,b.y);    //获取要移动到的坐标点
              if(this.check(b.x,b.y)){    //判断移动目标点是否在可拖动范围
                var co=this.getmoveto(b.x,b.y);    //获取到移动的目标位置坐标()
                var tar=this.respotchange(co);    //坐标转化
                var o=co.z;
                this.p.draw(tar.x,tar.y,this.p.r,o);    //绘图
              }
           }
       },

     (3)鼠标释放方法

    OnMouseUp:function(){  //鼠标释放
           this.p.isDown=false
    },

    (4)最后将所有方法和事件绑定

    event:function(){  //事件绑定
           this.obj.addEventListener("mousedown",this.OnMouseDown.bind(this),false);
           this.obj.addEventListener("mousemove",this.OnMouseMove.bind(this),false);
           this.obj.addEventListener("mouseup",this.OnMouseUp.bind(this),false);
       },

    至此可拖动滑块基本方法编写完成

  • 相关阅读:
    Linked list
    mysql(1)

    mysql 1130 问题
    POST乱码
    GET乱码(2)
    GET乱码
    P65——练习题2.31
    2.1.9 C语言中的移位运算
    2.1中所想的问题:指针的类型有什么作用?
  • 原文地址:https://www.cnblogs.com/pangys/p/6837344.html
Copyright © 2011-2022 走看看