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 相关文章推荐
使用jQuery.Validate进行客户端验证(初级篇) 不使用微软验证控件的理由
Jun 28 Javascript
js split 的用法和定义 js split分割字符串成数组的实例代码
May 13 Javascript
THREE.JS入门教程(2)着色器-上
Jan 24 Javascript
js触发select onchange事件的小技巧
Aug 05 Javascript
Angularjs编写KindEditor,UEidtor,jQuery指令
Jan 28 Javascript
js H5 canvas投篮小游戏
Aug 18 Javascript
javascript this详细介绍
Sep 19 Javascript
JS实现拖动滚动条评分的效果代码分享
Sep 29 Javascript
浅谈Fetch 数据交互方式
Dec 20 Javascript
浅谈Layui的eleTree树式选择器使用方法
Sep 25 Javascript
antd多选下拉框一行展示的实现方式
Oct 31 Javascript
html中两种获取标签内的值的方法
Jun 16 jQuery
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
海贼王动画变成“真人”后,凯多神还原,雷利太帅了!
2020/04/09 日漫
收集的php编写大型网站问题集
2007/03/06 PHP
PHP垃圾回收机制引用计数器概念分析
2013/06/24 PHP
PHP CodeIgniter分页实例及多条件查询解决方案(推荐)
2017/05/20 PHP
thinkPHP实现基于ajax的评论回复功能
2018/06/22 PHP
php 使用expat方式解析xml文件操作示例
2019/11/26 PHP
BOOM vs RR BO3 第二场2.13
2021/03/10 DOTA
javascript form 验证函数 弹出对话框形式
2009/06/23 Javascript
Javascript attachEvent传递参数的办法
2009/12/14 Javascript
JavaScript 用cloneNode方法克隆节点的代码
2012/10/15 Javascript
自写的jQuery异步加载数据添加事件
2014/05/15 Javascript
浅析JavaScript中的事件机制
2015/06/04 Javascript
微信小程序开发之录音机 音频播放 动画实例 (真机可用)
2016/12/08 Javascript
图解Javascript——作用域、作用域链、闭包
2017/03/21 Javascript
jquery submit()不能提交表单的解决方法
2017/04/24 jQuery
node文字生成图片的示例代码
2017/10/26 Javascript
angular2系列之路由转场动画的示例代码
2017/11/09 Javascript
vue2中,根据list的id进入对应的详情页并修改title方法
2018/08/24 Javascript
layui table动态表头 改变表格头部 重新加载表格的方法
2019/09/21 Javascript
Python 可爱的大小写
2008/09/06 Python
利用aardio给python编写图形界面
2017/08/21 Python
Python中pygal绘制雷达图代码分享
2017/12/07 Python
Python文件打开方式实例详解【a、a+、r+、w+区别】
2019/03/30 Python
python如何使用socketserver模块实现并发聊天
2019/12/14 Python
Python3 字典dictionary入门基础附实例
2020/02/10 Python
Python装饰器实现方法及应用场景详解
2020/03/26 Python
读群众路线心得体会
2014/03/07 职场文书
销售团队激励口号
2014/06/06 职场文书
我为党旗添光彩演讲稿
2014/09/10 职场文书
2014年惩防体系建设工作总结
2014/12/01 职场文书
离婚撤诉申请书范本
2015/05/18 职场文书
高中数学教学反思范文
2016/02/18 职场文书
九年级化学教学反思
2016/02/22 职场文书
详解Html5项目适配系统深色模式方案总结
2021/04/14 HTML / CSS
如何用JS实现简单的数据监听
2021/05/06 Javascript
Vue3.0写自定义指令的简单步骤记录
2021/06/27 Vue.js