前言
最近專案上有個工業自動化的需求,做一個按鈕,有按下彈起效果,你肯定會說這不是so easy嗎?是的,沒錯,用css,分分鐘寫一個,不過我們是做的拓撲圖,用的canvas,因此我就想css畫圖也是gpu繪製,css能做的效果,我大canvas理應也能實現,於是我試著用css的實現方式做了一個canvas版的按鈕效果。
css3版的立體按鈕效果
想想我們用css怎麼做一個按鈕,首先我們就能想到按鈕需要有陰影,我們可以使用box-shadow,他的語法如下:
/* x偏移量 | y偏移量 | 陰影顏色 */ box-shadow: 60px -16px teal;
/* x偏移量 | y偏移量 | 陰影模糊半徑 | 陰影顏色 */ box-shadow: 10px 5px 5px black;
/* x偏移量 | y偏移量 | 陰影模糊半徑 | 陰影擴散半徑 | 陰影顏色 */ box-shadow: 2px 2px 2px 1px rgba(0, 0, 0, 0.2);
/* 插頁(陰影向內) | x偏移量 | y偏移量 | 陰影顏色 */ box-shadow: inset 5em 1em gold;
/* 任意數量的陰影,以逗號分隔 */ box-shadow: 3px 3px red, -1em 0 0.4em olive;
/* 全域性關鍵字 */ box-shadow: inherit; box-shadow: initial; box-shadow: unset;
首先我們定義一個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,這樣效果如下所示:
canvas版的按鈕效果
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發光效果
上面介紹瞭如何繪製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一下,不喜勿噴。
總結
知識都是由互通性的,多學習多思考,不能學了這個忘那個,要能融會貫通(互相抄襲借鑑)