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 相关文章推荐
向当前style sheet中插入一个新的style实现方法
Apr 01 Javascript
JQuery对表单元素的基本操作使用总结
Jul 18 Javascript
JQuery表格拖动调整列宽效果(自己动手写的)
Sep 01 Javascript
jqueryMobile使用示例分享
Jan 12 Javascript
Bootstrap 组件之按钮(二)
May 11 Javascript
深入浅析jQuery对象$.html
Aug 22 Javascript
JS变量中有var定义和无var定义的区别以及es6中let命令和const命令
Feb 19 Javascript
微信小程序 ES6Promise.all批量上传文件实现代码
Apr 14 Javascript
vue技术分享之你可能不知道的7个秘密
Apr 09 Javascript
vue实现word,pdf文件的导出功能
Jul 31 Javascript
Node4-5静态资源服务器实战以及优化压缩文件实例内容
Aug 29 Javascript
解决layui弹出层layer的area过大被遮挡的问题
Sep 21 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 采集书并合成txt格式的实现代码
2009/03/01 PHP
PHP header()函数使用详细(301、404等错误设置)
2013/04/17 PHP
使用PHP下载CSS文件中的图片的代码
2013/09/24 PHP
PHP JSON格式的中文显示问题解决方法
2015/04/09 PHP
php集成套件服务器xampp安装使用教程(适合第一次玩PHP的新手)
2015/06/03 PHP
laravel 数据迁移与 Eloquent ORM的实现方法
2019/04/12 PHP
PHP写API输出的时用echo的原因详解
2019/04/28 PHP
使用JQuery和s3captche实现一个水果名字的验证
2009/08/14 Javascript
AngularJS内置指令
2015/02/04 Javascript
JavaScript实现俄罗斯方块游戏过程分析及源码分享
2015/03/23 Javascript
JS实现控制表格行内容垂直对齐的方法
2015/03/30 Javascript
基于JavaScript代码实现随机漂浮图片广告
2016/01/05 Javascript
json实现添加、遍历与删除属性的方法
2016/06/17 Javascript
基于vue2的table分页组件实现方法
2017/03/20 Javascript
vue组件 $children,$refs,$parent的使用详解
2017/07/31 Javascript
新手vue构建单页面应用实例代码
2017/09/18 Javascript
jQuery实现form表单序列化转换为json对象功能示例
2018/05/23 jQuery
vue实现带过渡效果的下拉菜单功能
2020/02/19 Javascript
js删除指定位置超链接中含有百度与360的标题
2021/01/06 Javascript
python中的yield使用方法
2014/02/11 Python
Python入门篇之函数
2014/10/20 Python
python判断字符串是否包含子字符串的方法
2015/03/24 Python
Python中的高级函数map/reduce使用实例
2015/04/13 Python
Python实现把数字转换成中文
2015/06/29 Python
详解Python中的Cookie模块使用
2015/07/06 Python
python+adb命令实现自动刷视频脚本案例
2020/04/23 Python
Python基于execjs运行js过程解析
2020/11/27 Python
匡威德国官网:Converse德国
2019/01/26 全球购物
阿巴庭院:Abba Patio
2019/06/18 全球购物
医学求职自荐信
2014/06/21 职场文书
迎新生标语大全
2014/10/06 职场文书
检讨书范文1000字
2015/01/28 职场文书
拖欠货款起诉状
2015/05/20 职场文书
2021-4-3课程——SQL Server查询【2】
2021/04/05 SQL Server
《仙剑客栈2》第一弹正式宣传片公开 年内发售
2022/04/07 其他游戏
MySQL 条件查询的常用操作
2022/04/28 MySQL