當初在掘金看到那個小熊的登陸頁面,不少人都很喜歡,因而恬不知恥的說了一句要用canvas來實現一遍,真的是給本身立了個flag,還好結果很糟糕。javascript
各位觀衆大老爺,這多是你見過最慘淡的demo了,但願不要嫌棄vue
首先看看別人的效果圖java
進行思考作出一些邏輯上的思索與排除git
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;
}
複製代碼
經過輸入向量與角度值,來進行計算,生成座標在空間旋轉後的座標,此處使用的計算公式爲旋轉矩陣,矩陣並未單獨抽離爲單獨類。github
看過上一篇2d向量講解的會知道,咱們在使用向量來處理時,是要對每個向量點進行處理,因此咱們無法直接使用如fillRect
等的方法,這裏我使用了貝茲曲線來繪製圖形。canvas
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(深度)
來進行渲染,產生遮擋的效果。瀏覽器
這樣咱們將能夠經過以下方式來建立形狀svg
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來寫的頁面,經過監聽輸入框的文本長度來計算,(文本的長度*字體的大小)+左邊距=焦點座標。字體
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'
}
}
}
})
複製代碼
而後咱們就能夠把全部的東西交給瀏覽器了ui
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();
複製代碼
總結
其實這東西挺很差作的,之前用PS或者AE作動效的時候,只想着如何來美化效果,動手實現以後才感受圖形引擎那羣人真的牛逼,從開始打算作到簡單實現,花了接近半天,中間推倒了不少想法,而後再去整理,雖然最後的效果不怎麼樣,可是吧,我仍是恬不知恥但願能夠誘惑到一些大佬們加入canvas的隊伍中,一塊兒來寫有趣的東西。
不按期更新canvas與svg的相關技術教程,有實戰型,也會有主原理型的,2d 2.5d 3d都會包含到,同時涉及的有 線性代數 物理 圖形學等相關的基礎知識。
歡迎各位客官收藏關注 投硬幣包養