先看一下最终效果
正弦曲线
正弦曲线公式 y = A sin(Bx + C) + D
振幅是 A,A 值越大,曲线更陡峭
B值越大 周期越短
C水平位移
垂直位移是 D,控制曲线上下移动
实现思路
首先来绘制曲线
1.定义构造函数和初始化方法
//sin曲线构造函数
function drawSin(option){
this.init(option);
}
//初始化
drawSin.prototype.init=function(o){
this.A=6;//振幅
this.B=0.02;//周期
this.C=0;//水平位移
this.D=H/2;//垂直位移
this.color='orange';//填充颜色
this.speed=-0.2; //移动速度
this.percent=0;//百分比
this.offsetX=0;//开始X坐标
for(var key in o){//循环new时候传入的参数,如果存在,则覆盖,没有传则使用默认
if(typeof this[key] !=='undefined'){
this[key] = o[key];
}
}
}
2.添加一个render绘制函数
//绘制曲线
drawSin.prototype.render=function(c){
c.save();
c.beginPath();
var y=0;
for(var x=this.offsetX;x<W+this.offsetX;x+=0.01){
//正弦曲线公式:y = A sin(Bx + C) + D
//振幅是 A,A 值越大,曲线更陡峭
//B值越大 周期越短
//C水平位移
//垂直位移是 D,控制曲线上下移动
y = this.A*Math.sin(this.B*(x+this.offsetX) + this.C) + this.D;
c.lineTo(x,y);
}
c.lineTo(W,H);
c.lineTo(0,H);
c.fillStyle = this.color;
c.stroke()
c.closePath();
c.restore();
return this;
}
3.生成一根正弦曲线
var sin1 = new drawSin({
A:20,B:0.025,
C:0,D:H/2-6,
color:'#3399FF'
}).render(ctx);
4.看一下现在的效果
扫描二维码关注公众号,回复:
12395289 查看本文章
5.加上流动代码
drawSin.prototype.update=function(){
this.C+=this.speed;//设定横向移动递增
}
function move(){
//执行动画帧
window.requestAnimationFrame(move);
//清理画布
ctx.clearRect(0,0,W,H);
//更新
sin1.update();
//绘制
sin1.render(ctx);
}
window.requestAnimationFrame(move);
6.加上颜色
裁剪成圆形
draw();
function draw(){//画圆
ctx.strokeStyle='rgb(250,235,215)';
ctx.lineWidth=10;
ctx.beginPath();
ctx.arc(W/2,H/2,160,0,Math.PI*2,true);
ctx.stroke();
ctx.clip();
}
效果如下
加上百分比
<canvas id='canvas'></canvas>
<div id='percent'>
<input type='text' value=0 oninput="doInput(this)" style="display:none;" >
<p style="text-align: center;color:orange;"></p>
</div>
//显示的百分比
function text(val){
if(inputClick)return ;
percent.children[1].innerText=val;
percent.children[0].value=val;
}
function doClick(e){
var p=percent.children[1],input=percent.children[0];
var e=e||window.event;
var target=e.currentTarget;
e.stopPropagation();//阻止冒泡
if(target.tagName&&target.tagName.toUpperCase()==='DIV'){
if(input.style.display==''){
return;
}
//显示input
input.style.display='';
p.style.display='none';
input.value=p.innerText;
input.focus();
inputClick=true;
}else{
if(input.style.display==''){
p.style.display='';
//隐藏input
input.style.display='none';
p.innerText=input.value;
//处理百分比
editPercent();
}
}
}
function editPercent(){
var p=percent.children[1],input=percent.children[0];
//执行动画
sin1.change=parseInt(p.innerText);
sin2.change=parseInt(p.innerText);
}
//控制文本输入
function doInput(obj){
obj.value=obj.value.replace(/[^\d]/g,'');
if(obj.value=='')obj.value=0;
var value = parseInt(obj.value);
if(value>100){
obj.value=100;
}else if(value<=0){
obj.value=0;
}
}
//百分比点击事件
percent.addEventListener('click',doClick);
document.addEventListener('click',doClick);
看下效果
加多一条曲线、百分比可以编辑就完成了
换其他图形试试
1.三角形
2.长方形
3.心形
全部代码:
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="GBK">
<title></title>
<style>
*{
margin: 0;
padding: 0;
}
canvas{
left:30px;
position: absolute;
border:1px solid ;
}
#percent{
width: 90px;
height: 90px;
position: absolute;
left: 190px;
top: 230px;
font-size: 50px;
cursor: pointer;
}
#percent input{
width: 90px;
height: 90px;
border-radius: 10px;
border: 1px solid #EEEEEE;
text-align:center;
font-size: 50px;
}
</style>
</head>
<body>
<canvas id='canvas'></canvas>
<div id='percent'>
<input type='text' value=0 oninput="doInput(this)" style="display:none;" >
<p style="text-align: center;color:orange;"></p>
</div>
<script type="text/javascript">
var percent = document.getElementById('percent');
var canvas = document.getElementById('canvas')
var W = canvas.width = 400
var H = canvas.height = 400
var ctx = canvas.getContext('2d');
var inputClick=false;//控制百分比内容是否可以被更新
draw();
function draw(){//画圆
ctx.strokeStyle='rgb(250,235,215)';
ctx.lineWidth=10;
ctx.beginPath();
ctx.arc(W/2,H/2,160,0,Math.PI*2,true);
ctx.stroke();
ctx.clip();
}
//drawTriangle();
function drawTriangle(){//画三角形
ctx.strokeStyle='rgb(250,235,215)';
ctx.lineWidth=10;
ctx.beginPath();
ctx.moveTo(W/2,40);
ctx.lineTo(100,360);
ctx.lineTo(300,360);
ctx.closePath();
ctx.stroke();
ctx.clip();
}
//drawRect();
function drawRect(){//画方形
ctx.strokeStyle='rgb(250,235,215)';
ctx.lineWidth=10;
ctx.beginPath();
ctx.rect(140,40,120,320);
ctx.closePath();
ctx.stroke();
ctx.clip();
}
//drawHeart();
function drawHeart(){//画心形
ctx.strokeStyle='rgb(250,235,215)';
ctx.lineWidth=10;
ctx.beginPath();
ctx.lineCap='round';
ctx.moveTo(200, 100);
ctx.bezierCurveTo(50,-120,-80,260, 200, 360);
ctx.moveTo(200, 100);
ctx.bezierCurveTo(350,-120,W+80,260, 200, 360);
ctx.stroke();
ctx.clip();
}
//sin曲线构造函数
function drawSin(option){
this.init(option);
}
//初始化
drawSin.prototype.init=function(o){
this.A=6;//振幅
this.B=0.02;//周期
this.C=0;//水平位移
this.D=H/2;//垂直位移
this.color='orange';//填充颜色
this.speed=-0.2; //移动速度
this.percent=0;//百分比
this.offsetX=0;//开始X坐标
this.moveFlag=false;//页面加载时是否执行移动动画
this.move={//定义移动动画的相关参数
start:360,//开始位置
end:200,//结束位置
total:320,//总高度
dis:40,//距离画布底部的高度
speed:4//美移动动画速度
};
for(var key in o){//循环new时候传入的参数,如果存在,则覆盖,没有传则使用默认
if(typeof this[key] !=='undefined'){
this[key] = o[key];
}
}
if(this.moveFlag){//如果有移动标示,则sin曲线的Y位置更新为初始位置
this.D=this.move.start;
}else {//否则执行更新函数
this.update();
}
}
drawSin.prototype.update=function(){
this.C+=this.speed;//设定横向移动递增
if(typeof this.change=='number'){//这个是修改百分比执行的更新块
var temp = this.change*this.move.total/100;//计算当前百分比应该占用总高度的实值
var changePos=this.move.start-temp;//计算应该处于的位置
if(changePos>this.move.end){//水波往下
this.D+=this.move.speed;
if(this.D>=changePos){//执行到位置后释放相关参数
this.change=undefined;
this.move.end=this.D;//设置结束位置
inputClick=false;
}
}else if(changePos<this.move.end){
this.D-=this.move.speed;
if(this.D<=changePos){
this.change=undefined;
this.move.end=this.D;
inputClick=false;
}
}else {
this.change=undefined;
inputClick=false;
}
//设定最终百分比
this.percent = this.change;
}else{
if(this.moveFlag && this.D>this.move.end){//如果没有执行到终点,就继续执行
this.D-=this.move.speed;
}
//设定百分比
this.percent =Math.round((this.move.total+this.move.dis-this.D)/this.move.total*100);
//显示百分比
text(this.percent);
}
}
//绘制曲线
drawSin.prototype.render=function(c){
c.save();
c.beginPath();
var y=0;
for(var x=this.offsetX;x<W+this.offsetX;x+=0.01){
//正弦曲线公式:y = A sin(Bx + C) + D
//振幅是 A,A 值越大,曲线更陡峭
//B值越大 周期越短
//C水平位移
//垂直位移是 D,控制曲线上下移动
y = this.A*Math.sin(this.B*(x+this.offsetX) + this.C) + this.D;
c.lineTo(x,y);
}
c.lineTo(W,H);
c.lineTo(0,H);
c.fillStyle = this.color;
c.fill();
c.closePath();
c.restore();
return this;
}
//显示的百分比
function text(val){
if(inputClick)return ;
percent.children[1].innerText=val;
percent.children[0].value=val;
}
//创建sin曲线1
var sin1 = new drawSin({
A:10,B:0.025,
C:0,D:H/2-6,
color:'#3399FF',
speed:-0.1,
moveFlag:true
}).render(ctx);
//创建sin曲线2
var sin2 = new drawSin({
A:10,B:0.025,
C:0,D:H/2,
color:'#3366FF',
speed:-0.1,
offsetX:40,
moveFlag:true
}).render(ctx);
function move(){
//执行动画帧
window.requestAnimationFrame(move);
//清理画布
ctx.clearRect(0,0,W,H);
//更新
sin1.update();
//绘制
sin1.render(ctx);
sin2.update();
sin2.render(ctx);
}
window.requestAnimationFrame(move);
function doClick(e){
var p=percent.children[1],input=percent.children[0];
var e=e||window.event;
var target=e.currentTarget;
e.stopPropagation();//阻止冒泡
if(target.tagName&&target.tagName.toUpperCase()==='DIV'){
if(input.style.display==''){
return;
}
//显示input
input.style.display='';
p.style.display='none';
input.value=p.innerText;
input.focus();
inputClick=true;
}else{
if(input.style.display==''){
p.style.display='';
//隐藏input
input.style.display='none';
p.innerText=input.value;
//处理百分比
editPercent();
}
}
}
function editPercent(){
var p=percent.children[1],input=percent.children[0];
//执行动画
sin1.change=parseInt(p.innerText);
sin2.change=parseInt(p.innerText);
}
//控制文本输入
function doInput(obj){
obj.value=obj.value.replace(/[^\d]/g,'');
if(obj.value=='')obj.value=0;
var value = parseInt(obj.value);
if(value>100){
obj.value=100;
}else if(value<=0){
obj.value=0;
}
}
//百分比点击事件
percent.addEventListener('click',doClick);
document.addEventListener('click',doClick);
</script>
</body>
</html>