canvas实现弧形可拖动进度条效果


Posted in Javascript onMay 11, 2017

一、效果如下:

canvas实现弧形可拖动进度条效果

二、

本文是实现可拖动滑块实现的基本思路,及一个简单的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绘制下图:

canvas实现弧形可拖动进度条效果

(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实现弧形可拖动进度条效果

编写获取当前光标位置点相对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方法绘图时使用的是黑色的坐标系,在使用圆的路径处理是我们使用红色的坐标系

canvas实现弧形可拖动进度条效果

下面添加坐标转化方法,

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

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)滑块路径及位置计算方法

canvas实现弧形可拖动进度条效果

 首先不考虑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);
 },

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

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持三水点靠木!

Javascript 相关文章推荐
javascript实现上传图片前的预览(TX的面试题)
Aug 20 Javascript
ext for eclipse插件安装方法
Apr 27 Javascript
悬浮数字的实现案例
Feb 19 Javascript
jquery对table中各数据的增加、保存、删除操作示例
May 14 Javascript
ECMAScript5(ES5)中bind方法使用小结
May 07 Javascript
深入理解javascript中concat方法
Dec 12 Javascript
javascript中this关键字详解
Dec 12 Javascript
webpack教程之webpack.config.js配置文件
Jul 05 Javascript
Element Input组件分析小结
Oct 11 Javascript
Jquery实现无缝向上循环滚动列表的特效
Feb 13 jQuery
vue中input的v-model清空操作
Sep 06 Javascript
在antd Table中插入可编辑的单元格实例
Oct 28 Javascript
es6学习笔记之Async函数的使用示例
May 11 #Javascript
Node.js安装配置图文教程
May 10 #Javascript
使用bootstrap插件实现模态框效果
May 10 #Javascript
详解Vue用axios发送post请求自动set cookie
May 10 #Javascript
Node.js 异步异常的处理与domain模块解析
May 10 #Javascript
基于Node的React图片上传组件实现实例代码
May 10 #Javascript
JavaScript使用ZeroClipboard操作剪切板
May 10 #Javascript
You might like
php中instanceof 与 is_a()区别分析
2015/03/03 PHP
php修改上传图片尺寸的方法
2015/04/14 PHP
超详细的php用户注册页面填写信息完整实例(附源码)
2015/11/17 PHP
Laravel5.7 Eloquent ORM快速入门详解
2019/04/12 PHP
JavaScript入门教程(10) 认识其他对象
2009/01/31 Javascript
jQuery实现随意改变div任意属性的名称和值(部分原生js实现)
2013/05/28 Javascript
用Js实现的动态增加表格示例自己写的
2013/10/21 Javascript
阻止事件(取消浏览器对事件的默认行为并阻止其传播)
2013/11/03 Javascript
js随机生成网页背景颜色的方法
2015/02/26 Javascript
JQuery中节点遍历方法实例
2015/05/18 Javascript
深入浅析JS是按值传递还是按引用传递(推荐)
2016/09/18 Javascript
js实现悬浮窗效果(支持拖动)
2017/03/09 Javascript
AngularJs定时器$interval 和 $timeout详解
2017/05/25 Javascript
基于Jquery Ajax type的4种类型(详解)
2017/08/02 jQuery
vue异步加载高德地图的实现
2018/06/19 Javascript
webpack+vue-cil中proxyTable处理跨域的方法
2018/07/20 Javascript
前端路由&amp;webpack基础配置详解
2019/06/10 Javascript
vue实现多级菜单效果
2019/10/19 Javascript
vue使用一些外部插件及样式的配置代码
2019/11/18 Javascript
详解vue组件之间的通信
2020/08/30 Javascript
Node快速切换版本、版本回退(降级)、版本更新(升级)
2021/01/07 Javascript
浅谈pyqt5中信号与槽的认识
2019/02/17 Python
解决python明明pip安装成功却找不到包的问题
2019/08/28 Python
Python调用Windows命令打印文件
2020/02/07 Python
Python爬取数据并实现可视化代码解析
2020/08/12 Python
Python数据分析库pandas高级接口dt的使用详解
2020/12/11 Python
高级销售员求职信
2013/10/25 职场文书
老师给学生的表扬信
2014/01/17 职场文书
党建示范点实施方案
2014/03/12 职场文书
校园联欢晚会主持词
2014/03/17 职场文书
秋季校运会广播稿100字
2014/09/18 职场文书
2014年化妆品销售工作总结
2014/12/01 职场文书
长城导游词400字
2015/01/30 职场文书
网站文案策划岗位职责
2015/04/14 职场文书
用python批量解压带密码的压缩包
2021/05/31 Python
死磕 java同步系列之synchronized解析
2021/06/28 Java/Android