最近項目上有個工業自動化的需求,作一個按鈕,有按下彈起效果,你確定會說這不是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一下,不喜勿噴。
知識都是由互通性的,多學習多思考,不能學了這個忘那個,要能融會貫通(互相抄襲借鑑)