vue+canvas如何實現b站萌系登入介面

山鬼發表於2019-03-04

當初在掘金看到那個小熊的登入頁面,很多人都很喜歡,於是恬不知恥的說了一句要用canvas來實現一遍,真的是給自己立了個flag,還好結果很糟糕。

各位觀眾大老爺,這可能是你見過最慘淡的demo了,希望不要嫌棄

首先看看別人的效果圖

vue+canvas如何實現b站萌系登入介面
進行思考

  1. 為什麼小熊會跟著輸入框的輸入而移動。
  2. 為什麼小熊的耳朵會移動到前面
  3. 小熊的移動規律是什麼

做出一些邏輯上的思索與排除

  1. 2d
  2. 3d
  3. 判斷文字框的焦點座標,從而給小熊旋轉等動作的資料支援

實現3d的向量類

var eyeLength = 250, centerX = 200/ 2, centerY = 200 / 2;
//設定視距,中心點的座標

  function Vector3(x, y, z) {
    this.x = x;
    this.y = y;
    this.z = z;
    this._get2d = function() {
    //將空間左邊進行縮放後生成平面檢視中的座標
      var scale = eyeLength / (eyeLength + this.z);
      var x = centerX + this.x * scale;
      var y = centerY + this.y * scale;
      return { x: x, 
              y: y };
    }
  }
複製程式碼

對物體進行空間的旋轉

function rotateX(vec3,angleX) {
    var cos = Math.cos(angleX);
    var sin = Math.sin(angleX);
 
      var y1 = vec3.y * cos - vec3.z * sin;
      var z1 = vec3.z * cos + vec3.y * sin;
      vec3.y = y1;
      vec3.z = z1;

  }

  function rotateY(vec3,angleY) {
    var cos = Math.cos(angleY);
    var sin = Math.sin(angleY);

      var x1 = vec3.x * cos - vec3.z * sin;
      var z1 = vec3.z * cos + vec3.x * sin;
      vec3.x = x1;
      vec3.z = z1;
  }
複製程式碼

通過輸入向量與角度值,來進行計算,生成座標在空間旋轉後的座標,此處使用的計算公式為旋轉矩陣,矩陣並未單獨抽離為單獨類。

形狀類

看過上一篇2d向量講解的會知道,我們在使用向量來處理時,是要對每一個向量點進行處理,所以我們沒法直接使用如fillRect等的方法,這裡我使用了貝茲曲線來繪製圖形。

function shape(option) {
	this.points=[];
	this.site=new Vector3(0,0,0);
	this.create(option);
	this.face=[];
	this.ctx={};
}
shape.prototype.render = function(ctx) {
	this.ctx=ctx;
    for(let f =0;f<this.paths.length;f++){
    	this.face[f]=new Face(this.ctx,this.color,...this.paths[f]);
    }
    this.face.sort(function(a,b){
    	return a-b;
    })
    this.face.forEach( function(face, index) {
    	face.draw(ctx);
    });
  }
複製程式碼

我們通過捕獲paths中的向量,生成一個面,然後由面去構成物體,並且在同一形狀中進行面重排,是為了使面在繪製的時候依據z(深度)來進行渲染,產生遮擋的效果。

這樣我們將可以通過如下方式來建立形狀

var face=new shape({
		paths:[[new Vector3(-50,0,4),new Vector3(-50,-70,4),new Vector3(50,-70,4),new Vector3(50,0,4)]],
		color:"#3366C"
	})
	var eyes=new shape({
		paths:[[new Vector3(-54,0,6),new Vector3(-54,-8,6),new Vector3(-46,-4,6),new Vector3(-46,0,6)],
		[new Vector3(-54,0,6),new Vector3(-54,8,6),new Vector3(-46,4,6),new Vector3(-46,0,6)]],
		color:"white"
	})
複製程式碼

vue+canvas如何實現b站萌系登入介面
對於這種繪製的最快方法,就是先在紙面上進行座標繪製,再用程式碼實現。

實現了繪製與變換之後,下一步就是進行互動,這裡我使用vue來寫的頁面,通過監聽輸入框的文字長度來計算,(文字的長度*字型的大小)+左邊距=焦點座標。

var vm=new Vue({
		el:'#bod',
		data:{
			username:"",//記錄輸入框
			left:0,//距離左邊的長度,用於判斷旋轉何時結束
			len:0,//焦點座標
			pos:0,//是否開始選擇
			dir:'left'//旋轉的方向
		},
		computed:{
		//計算文字長度
			roate:function (argument) {
				this.len=this.username.length;
			}
		},
		watch:{
		//監聽len的值,判斷是增還是減
			len:function(o,n){
				this.pos=1;
				if(n<o){
					this.dir='right';
				}else {
					this.dir='left'
				}
			}
		}
	})
複製程式碼

然後我們就可以把所有的東西交給瀏覽器了

function anima(){
		if(vm.pos===1){//如果可以旋轉
			if(vm.left<r){//如果長度不夠,繼續旋轉
				ctx.clearRect(0,0,200,200);
				switch (vm.dir) {//判斷方向
					case 'right':
						face.rotate(0,r);
						eyes.rotate(0,r);
						face.render(ctx);
						eyes.render(ctx);
						vm.left+=r/5;
						break;
					case 'left':
						face.rotate(0,-r);
						eyes.rotate(0,-r);
						face.render(ctx);
						eyes.render(ctx);
						vm.left+=r/5;
						break;
				}
			}else{//長度達到後則重置資料
				vm.left=0;
				vm.pos=0;
			}
		}
		requestAnimationFrame(anima)
	}
	anima();
複製程式碼

不足

  1. 畫的有點醜,不太可以很清晰的有那種感覺
  2. 只對單個物體進行了深度渲染,未實現空間深度的渲染
  3. 向量與形狀的功能不完善,使得效果侷限性很大

vue+canvas如何實現b站萌系登入介面
這是未輸入時的樣子,為了對比明顯,我講旋轉的角度調大了

vue+canvas如何實現b站萌系登入介面
原始碼在此:原始碼

總結

其實這東西挺不好做的,以前用PS或者AE做動效的時候,只想著如何來美化效果,動手實現之後才感覺圖形引擎那群人真的牛逼,從開始打算做到簡單實現,花了接近半天,中間推倒了很多想法,然後再去整理,雖然最後的效果不怎麼樣,但是吧,我還是恬不知恥希望可以誘惑到一些大佬們加入canvas的隊伍中,一起來寫有趣的東西。

不定期更新canvas與svg的相關技術教程,有實戰型,也會有主原理型的,2d 2.5d 3d都會包含到,同時涉及的有 線性代數 物理 圖形學等相關的基礎知識。

歡迎各位客官收藏關注 投硬幣包養

相關文章