由canvas實現btn效果有感

前言

最近項目上有個工業自動化的需求,作一個按鈕,有按下彈起效果,你確定會說這不是so easy嗎?是的,沒錯,用css,分分鐘寫一個,不過咱們是作的拓撲圖,用的canvas,所以我就想css畫圖也是gpu繪製,css能作的效果,我大canvas理應也能實現,因而我試着用css的實現方式作了一個canvas版的按鈕效果。javascript

css3版的立體按鈕效果

想一想咱們用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;
}
複製代碼

這是咱們的按鈕基礎樣式就完成了,以下所示:

F3oaF0.png

接下來咱們在來爲按鈕添加陰影

.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,這樣效果以下所示:

F3oWY6.gif

canvas版的按鈕效果

css的按鈕咱們已經知道了其實也就是利用box-shadow繪製陰影來實現按鈕的樣式,那麼canvas咱們怎麼繪製陰影呢?翻一翻萬能的mdn

shadowOffsetX = float

shadowOffsetXshadowOffsetY用來設定陰影在 X 和 Y 軸的延伸距離,它們是不受變換矩陣所影響的。負值表示陰影會往上或左延伸,正值則表示會往下或右延伸,它們默認都爲 0

shadowOffsetY = float

shadowOffsetX 和 shadowOffsetY用來設定陰影在 X 和 Y 軸的延伸距離,它們是不受變換矩陣所影響的。負值表示陰影會往上或左延伸,正值則表示會往下或右延伸,它們默認都爲 0

shadowBlur = float

shadowBlur 用於設定陰影的模糊程度,其數值並不跟像素數量掛鉤,也不受變換矩陣的影響,默認爲 0

shadowColor = color

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:

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;
        },
複製代碼

效果以下:

F8GQ4U.gif

不太完美,有時間在繼續優化,動畫的發光仍是不太柔和,與css比效果仍是有點欠缺,之後再優化,先mark一下,不喜勿噴。

總結

知識都是由互通性的,多學習多思考,不能學了這個忘那個,要能融會貫通(互相抄襲借鑑)

參考連接

developer.mozilla.org/zh-CN/docs/…

developer.mozilla.org/zh-CN/docs/…

相關文章
相關標籤/搜索