一、效果如下:

See the Pen XRmNRK by pangyongsheng (@pangyongsheng) on CodePen.

链接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);
},

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

canvas-圆弧形可拖动进度条的更多相关文章

  1. canvas-弧形可拖动进度条

    一.效果如下: See the Pen XRmNRK by pangyongsheng (@pangyongsheng) on CodePen. 链接dome 二. 本文是实现可拖动滑块实现的基本,及 ...

  2. [Android] SeekBar---可拖动进度条

    SeekBar---可拖动进度条 ()setMax //设置SeekBar最大数值 ()setProgress //设置SeekBar当前数值 ()setSecondaryProgress//设置Se ...

  3. Android——音乐播放器完善——进度条显示当前播放进度,加可拖动进度条(未待解决完问题)

    效果: 问题:可拖动进度条随进度条移动时,会致使音乐卡顿(待解决) xml <?xml version="1.0" encoding="utf-8"?&g ...

  4. UISlider无法拖动进度条的问题解决

    UISlider无法拖动进度条的问题解决 最近业务中的视频播放使用到了UISlider,但是有一个奇怪的问题,就是在Modar出来的控制器中UISlider是可以正常使用的,但是在Push出来的控制器 ...

  5. android中SeekBar拖动进度条的使用及事件监听

    下面和大家分享一下android中SeekBar拖动进度条的使用,以及事件监听.拖动进度条的事件监听需要实现SeekBar.OnSeekBarChangeListener接口,调用SeekBar的se ...

  6. canvas 简易的加载进度条

    做一个web app,想在第一次或者更新的时候,有一个更新进度条,我个人比较喜欢圆的那种. canvas + svg高低配,应该还不错的.顺便一提,canvas用来压缩图片也是么么哒的. 先看下效果图 ...

  7. Jquery实现可拖动进度条demo

    html <div class="progress"> <div class="progress_bg"> <div class= ...

  8. 视频支持拖动进度条播放的实现(基于nginx)

    http协议下的flv/mp4流式播放支持的三个要点: 1 服务器端要支持flv/mp4流式播放,现在nginx或者lighttpd都是支持这样的应用的,还支持mp4的流式播放(默认编译版本一般都是打 ...

  9. canvas 水滴图、液体进度条、仿加速球、圆球水波图

    传送门:https://github.com/guoyoujin/WaterMoire <!DOCTYPE html> <html lang="en"> & ...

随机推荐

  1. DataTables合并单元格(rowspan)的实现思路(多分组分类的情况)

    直接上代码,原理之前的随笔已经讲过了.http://www.cnblogs.com/hdwang/p/7115835.html 1.先看看效果 2.html代码,含js代码 2.1 common.js ...

  2. spring.net框架配置和使用

    spring.net框架学习笔记 spring.net框架是用于解决企业应用开发的复杂性的一种容器框架,它的一大功能IOC(控制反转),通俗解释就是通过spring.net框架的容器创建对象实体,而不 ...

  3. LOJ#2983. 「WC2019」数树

    传送门 抄题解 \(Task0\),随便做一下,设 \(cnt\) 为相同的边的个数,输出 \(y^{n-cnt}\) \(Task1\),给定其中一棵树 设初始答案为 \(y^n\),首先可以发现, ...

  4. CSS框架960Grid从入门到精通一步登天

    http://blog.chinaunix.net/uid-22414998-id-2878529.html 1.什么是CSS框架?     CSS框架是一种你能够使用在你的web项目中概念上的结构, ...

  5. 「Django」contenttypes基本用法

    当一张表和多个表ForeignKey关联,并且多个FK中只能选择其中一个或其中n个时,可以利用contenttypes,只需定义三个字段就搞定! contenttypes 是Django内置的一个应用 ...

  6. 关闭ubuntu dash 方法

    因为ubuntu默认的sh是连接到dash的,又因为dash跟bash的不兼容所以出错了.执行时可以把sh换成bash 文件名.sh来执行.成功.dash是什么东西,查了一下,应该也是一种shell, ...

  7. 在同一个表中将varchar2类型的数据转存到blob类型的字段中

    用一条修改语句即可:update t_content set f_body=rawtohex(f_check) where f_type in (0,4)此处须用rawtohex()函数将f_chec ...

  8. Spark记录-Scala模式匹配

    Scala模式匹配 模式匹配是Scala函数值和闭包后第二大应用功能.Scala为模式匹配提供了极大的支持,处理消息. 模式匹配包括一系列备选项,每个替代项以关键字大小写为单位.每个替代方案包括一个模 ...

  9. HDU 3094 树上删边 NIM变形

    基本的树上删边游戏 写过很多遍了 /** @Date : 2017-10-13 18:19:37 * @FileName: HDU 3094 树上删边 NIM变形.cpp * @Platform: W ...

  10. day63_SpringMVC学习笔记_01

    1.JAVAEE体系结构 JAVAEE体系结构图如下所示: 2.什么是springmvc? 什么是mvc? Model1 Model2 SpringMVC是什么? SpringMVC是一个web层mv ...