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触发器详解
Mar 10 Javascript
Colortip基于jquery的信息提示框插件在IE6下面的显示问题修正方法
Dec 06 Javascript
TextArea不支持maxlength的解决办法(jquery)
Sep 13 Javascript
常见效果实现之返回顶部(结合淡入、淡出、减速滚动)
Jan 04 Javascript
js中settimeout方法加参数的使用实例
Feb 27 Javascript
使用GruntJS构建Web程序之合并压缩篇
Jun 06 Javascript
微信公众号开发 自定义菜单跳转页面并获取用户信息实例详解
Dec 08 Javascript
jQuery插件FusionCharts实现的2D面积图效果示例【附demo源码下载】
Mar 06 Javascript
AngularJS service之select下拉菜单效果
Jul 28 Javascript
基于webpack-hot-middleware热加载相关错误的解决方法
Feb 22 Javascript
Node.js 的 GC 机制详解
Jun 03 Javascript
JavaScript前端页面搜索功能案例【基于jQuery】
Jul 10 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
日本收入最高的漫画家:海贼王作者版税年收入高达8.45亿元
2020/03/04 日漫
克隆一个新项目的快捷方式
2013/04/10 PHP
浅析Dos下运行php.exe,出现没有找到php_mbstring.dll 错误的解决方法
2013/06/29 PHP
ecshop实现smtp发送邮件
2015/02/03 PHP
Javascript之文件操作
2007/03/07 Javascript
从零开始学习jQuery (四) jQuery中操作元素的属性与样式
2011/02/23 Javascript
30个让人兴奋的视差滚动(Parallax Scrolling)效果网站
2012/03/04 Javascript
事件冒泡是什么如何用jquery阻止事件冒泡
2013/03/20 Javascript
js对象内部访问this修饰的成员函数示例
2014/04/27 Javascript
nodeJS代码实现计算交社保是否合适
2015/03/09 NodeJs
JS中script标签defer和async属性的区别详解
2016/08/12 Javascript
微信小程序商城项目之商品属性分类(4)
2017/04/17 Javascript
微信小程序页面开发注意事项整理
2017/05/18 Javascript
浅谈node中的exports与module.exports的关系
2017/08/01 Javascript
JavaScript动态绑定详解
2017/09/14 Javascript
vue路由中前进后退的一些事儿
2019/05/18 Javascript
JavaScript的Proxy可以做哪些有意思的事儿
2019/06/15 Javascript
vue项目中使用particles实现粒子背景效果及遇到的坑(按钮没有点击响应)
2020/02/11 Javascript
linux环境下安装pyramid和新建项目的步骤
2013/11/27 Python
仅利用30行Python代码来展示X算法
2015/04/01 Python
在Python的Flask中使用WTForms表单框架的基础教程
2016/06/07 Python
python之文件的读写和文件目录以及文件夹的操作实现代码
2016/08/28 Python
解决Alexnet训练模型在每个epoch中准确率和loss都会一升一降问题
2020/06/17 Python
高考考python编程是真的吗
2020/07/20 Python
详解CSS 3 中的 calc() 方法
2018/01/12 HTML / CSS
详解前端HTML5几种存储方式的总结
2016/12/27 HTML / CSS
canvas 橡皮筋式线条绘图应用方法
2019/02/13 HTML / CSS
全球摩托车装备领导者:RevZilla
2017/09/04 全球购物
一位农村小子的自荐信
2014/04/07 职场文书
品牌服务方案
2014/06/03 职场文书
顶岗实习计划书
2015/01/16 职场文书
开平碉楼导游词
2015/02/06 职场文书
严以用权专题学习研讨会发言材料
2015/11/09 职场文书
Ajax请求超时与网络异常处理图文详解
2021/05/23 Javascript
用Python爬取某乎手机APP数据
2021/06/15 Python
pycharm部署django项目到云服务器的详细流程
2021/06/29 Python