最近项目上有个工业自动化的需求,作一个按钮,有按下弹起效果,你确定会说这不是so easy吗?是的,没错,用css,分分钟写一个,不过咱们是作的拓扑图,用的canvas,所以我就想css画图也是gpu绘制,css能作的效果,我大canvas理应也能实现,因而我试着用css的实现方式作了一个canvas版的按钮效果。javascript
想一想咱们用css怎么作一个按钮,首先咱们就能想到按钮须要有阴影,咱们可使用box-shadow,他的语法以下:css
/* x偏移量 | y偏移量 | 阴影颜色 */ box-shadow: 60px -16px teal;java
/* x偏移量 | y偏移量 | 阴影模糊半径 | 阴影颜色 */ box-shadow: 10px 5px 5px black;css3
/* x偏移量 | y偏移量 | 阴影模糊半径 | 阴影扩散半径 | 阴影颜色 */ box-shadow: 2px 2px 2px 1px rgba(0, 0, 0, 0.2);git
/* 插页(阴影向内) | x偏移量 | y偏移量 | 阴影颜色 */ box-shadow: inset 5em 1em gold;github
/* 任意数量的阴影,以逗号分隔 */ box-shadow: 3px 3px red, -1em 0 0.4em olive;web
/* 全局关键字 */ box-shadow: inherit; box-shadow: initial; box-shadow: unset;canvas
首先咱们定义一个btn类,先画出一个按钮的基础样式学习
.btn {
border-radius: 5px;
padding: 15px 25px;
font-size: 22px;
text-decoration: none;
margin: 20px;
color: #fff;
position: relative;
display: inline-block;
}
复制代码
而后咱们定义一下按钮的背景色优化
.blue {
background-color: #55acee;
}
复制代码
这是咱们的按钮基础样式就完成了,以下所示:
接下来咱们在来为按钮添加阴影
.btn:active {
transform: translate(0px, 5px);
-webkit-transform: translate(0px, 5px);
box-shadow: 0px 1px 0px 0px;
}
.blue {
background-color: #55acee;
box-shadow: 0px 5px 0px 0px #3C93D5;
}
复制代码
给y方向5px的偏移,就会有阴影的效果,有点立体感受,而后按下按钮以后咱们还要去掉阴影,而后按钮的位置要向下偏移响应的5px,这样效果以下所示:
css的按钮咱们已经知道了其实也就是利用box-shadow绘制阴影来实现按钮的样式,那么canvas咱们怎么绘制阴影呢?翻一翻万能的mdn
shadowOffsetX
和shadowOffsetY
用来设定阴影在 X 和 Y 轴的延伸距离,它们是不受变换矩阵所影响的。负值表示阴影会往上或左延伸,正值则表示会往下或右延伸,它们默认都为0
。shadowOffsetX 和
shadowOffsetY
用来设定阴影在 X 和 Y 轴的延伸距离,它们是不受变换矩阵所影响的。负值表示阴影会往上或左延伸,正值则表示会往下或右延伸,它们默认都为0
。shadowBlur 用于设定阴影的模糊程度,其数值并不跟像素数量挂钩,也不受变换矩阵的影响,默认为
0
。shadowColor 是标准的 CSS 颜色值,用于设定阴影颜色效果,默认是全透明的黑色。
第一步咱们先绘制矩形,绘制矩形咱们使用moveTo和lineTo,由于按钮通常是带有圆角的,因此咱们封装一个绘制圆角矩形的
createPath: function (x, y, width, height, radius) {
this.ctx.moveTo(x, y + radius);
this.ctx.lineTo(x, y + height - radius);
this.ctx.quadraticCurveTo(x, y + height, x + radius, y + height);
this.ctx.lineTo(x + width - radius, y + height);
this.ctx.quadraticCurveTo(x + width, y + height, x + width, y + height - radius);
this.ctx.lineTo(x + width, y + radius);
this.ctx.quadraticCurveTo(x + width, y, x + width - radius, y);
this.ctx.lineTo(x + radius, y);
this.ctx.quadraticCurveTo(x, y, x, y + radius);
},
复制代码
圆角矩形绘制完成后咱们在接着绘制阴影,
setShadow: function (xoffset, yoffset) {
var style = this.style;
this.ctx.shadowOffsetX = xoffset || 0;
this.ctx.shadowOffsetY = yoffset || 5;
this.ctx.shadowBlur = 0;
this.ctx.shadowColor = style.shadowColor;
},
复制代码
阴影绘制完后咱们还要绘制文本,毕竟是canvas,绘制文本不像css那么方便,咱们须要计算文字宽度来定位,代码以下:
drawText: function () {
var xoffset = this.ctx.measureText(this.text).width;
var x = this.x,
y = this.y;
if (this.state === 'active') {
y = y + 5;
}
this.ctx.save();
this.ctx.beginPath();
this.ctx.font = "30px Micosoft yahei";
this.ctx.fillStyle = this.fontColor;
this.ctx.textBaseline = 'middle';
this.ctx.textAlign = 'center';
this.ctx.fillText(this.text, x + (this.width - xoffset) / 2 + 10, y + (this.height - 22) / 2 + 5, this.width);
this.ctx.closePath();
this.ctx.restore();
},
复制代码
另附textAlign和textBaseLine的说明:
textAlign:
textBaseLine:
这样效果就基本大功告成了
canvas事件能够具体看个人代码和我之前的博客
上面介绍了如何绘制canvas阴影立体按钮,接下来咱们来实现试试更进一步的效果,多层阴影叠加效果,在css中咱们的box-shadow能够叠加多层阴影效果,而且经过逗号分隔。那么咱们canvas是否是也能够一样实现呢?咱们知道canvas是基于状态的,咱们若是要绘制多层阴影叠加,那么就须要保存每次绘制的阴影,层叠在一块儿,那么咱们改下代码,每画一层阴影就须要保存一次canvas状态:
drawText: function (shadowx, shadowy, blur, shadowColor) {
var xoffset = this.ctx.measureText(this.text).width;
var x = this.x,
y = this.y;
this.ctx.save();
this.ctx.beginPath();
this.setShadow(shadowx, shadowy, blur, shadowColor);
this.ctx.font = "300px Micosoft yahei";
this.ctx.fillStyle = this.fontColor;
this.ctx.textBaseline = 'middle';
this.ctx.textAlign = 'center';
this.ctx.fillText(this.text, x + (this.width - xoffset) / 2 + 10, y + (this.height - 22) / 2 + 5, this.width);
this.ctx.closePath();
this.ctx.restore();
},
setShadow: function (shadowx, shadowy, blur, shadowColor) {
this.ctx.shadowOffsetX = shadowx || 0;
this.ctx.shadowOffsetY = shadowy || 0;
this.ctx.shadowBlur = blur || 10;
this.ctx.shadowColor = shadowColor;
},
复制代码
效果以下:
不太完美,有时间在继续优化,动画的发光仍是不太柔和,与css比效果仍是有点欠缺,之后再优化,先mark一下,不喜勿喷。
知识都是由互通性的,多学习多思考,不能学了这个忘那个,要能融会贯通(互相抄袭借鉴)