1. 程式人生 > >手把手教你用canvas畫動態直線

手把手教你用canvas畫動態直線

自己閒來無事的時候,就想學學熱火了好久的H5

然後就看了下canvas

不看不知道,一看下一條,H5我以為沒啥,原來都開始提供各種介面和函數了,我滴乖乖

canvas主要是用來畫圖的,結合定時器(setInterval)函式能夠作出精美的動畫

下面我就簡單的給大家介紹下canvas怎麼使用

vanvas的介紹這裡就不多說了,大家可以自行百度。

1.jsp頁面

首先,jsp頁面很簡單

<body>
	<div class="container">
		輸入漢字<input id="inputSomeThing" oninput="getInput(this.value)"></input>
		輸入個數<input id="numOfTranIO"></input>
		<input onclick="draw()" value="生成" type="button" />
		<canvas id="myCanvas" width="1150" height="500"
			style="border:1px solid #000000;">
		</canvas>
		<input onclick="draw()" value="111" type="button" />
	</div>
</body>

我們添加了一個輸入漢字的input和一個輸入個數的input,還有一個id為myCanvas的畫布

2.js部分

首先看js程式碼第一部分

2.1 全域性變數

全域性變數定義如下所示

var ctx;//全域性的畫布標識
var width=1150; //設定線條獲得區域寬度
var height=500; //設定線條獲得區域高度
var x; //設定線條起點

var i = 0; //記錄線條長度
var exp=1; //設定線條每次移動畫素大小
var string;//用來儲存使用者輸入的值

var tranIOLenth; //第二段橫線之間的間隔
var tranIOZuoBiao = {}; //用來儲存第二段橫線的起始點座標,用map形式儲存
var tnumOfTranIO; //儲存第二段輸入的值的個數
每個引數的代表的含義如註釋所示

2.2 document.ready

頁面初始化,當載入完成後,獲取畫布資訊,並初始化一些引數

$(document).ready(function(){
	/*var numOfTranIO = 4;*/
	var c=document.getElementById("myCanvas");
	ctx=c.getContext("2d");
	ctx.strokeStyle = "blue"; //定義顏色		
});

2.3 監控使用者輸入

當用戶在輸入漢字的時候,呼叫了oninput裡定義的getInput()方法,實現如下

function getInput(something){
	string = something;
	ctx.clearRect(0,0,width,height); 
	ctx.textBaseline="middle"; 
	ctx.font="30px sans-serif";
	ctx.fillText(something,10,250);
	x = ctx.measureText(something).width+10;
}
這樣就實現了,使用者輸入時,能夠實時顯示到螢幕中間

注意:有些人會說,為什麼這麼麻煩,不直接在canvas中巢狀html,其實這樣是行不通的,因為canvas不支援巢狀html,會將其覆蓋,所以我們使用

<span style="color:#000000;">fillText()</span>

方法來進行寫漢字。

這樣就出現瞭如下圖所示的效果,我們輸入HELLO

我們將輸入的字元顯示到了畫布上

2.4 動態顯示畫橫線

廢話不多說,直接看程式碼
//動態畫橫線
function drawRowLine(startX,startY,length){	
	var iLen = 0;
	var flag = 0;
	function rowLine(){
		if(iLen<=length){
			ctx.moveTo(startX,startY);
			ctx.lineTo(++startX,startY);
			iLen++;
			ctx.stroke();
		}else{
		}	
	}
	setInterval(rowLine,5);
}
傳入引數x,y和長度,通過setInterval函式來進行動態畫圖,我們設定5ms就執行一次rowLine函式,記住這裡引數裡面rowLine不能加(),不然代表函式執行,不是函式。

在rowLine函式裡面,我們通過iLen<=Length來判斷是否到達長度,沒到達繼續畫,到達了則停止,停止我這裡為了方便沒寫,大家可以自行在else裡面加上clearInterval()函式

接著,moveto設定起點,lineto設定終點,這裡因為是畫橫線,所以縱座標不動,橫座標每次加1,再呼叫ctx.stroke()再次畫圖即可。

2.5 動態顯示畫豎線

和上面畫橫線一樣,我們這裡分成畫豎線,分別是向上畫豎線和向下畫豎線,函式如下所示

//動態畫向上豎線
function drawColUpLine(startX,startY,length){
	var iLen = 0;
	function colUpLine(){
		if(iLen<=length){
			ctx.moveTo(startX,startY);
			ctx.lineTo(startX,--startY);
			iLen++;
			ctx.stroke();
		}		
	}
	setInterval(colUpLine,5);
}


//動態畫向下豎線
function drawColDownLine(startX,startY,length){
	var iLen = 0;
	function colDownLine(){
		if(iLen<=length){
			ctx.moveTo(startX,startY);
			ctx.lineTo(startX,++startY);
			iLen++;
			ctx.stroke();
		}		
	}
	setInterval(colDownLine,5);
}

無非就是橫縱座標是否變,長度如何控制之類的方法。

到這裡,我們基本上需要的方法都有了

2.6 根據使用者輸入的個數來計算間距

這裡,為了更加具有擴充套件性,我們根據使用者輸入的個數來計算縱向的間距,並平均分佈,再向右延伸,造成如下所示的效果


可見,當我輸入4以後,又出現了4條橫線,並向右延伸~

這裡所有的畫線都是動態的

那麼如何動態的計算這個間距呢/

我封裝到一個函數了,函式如下所示’

function calcTranIO(TranIOX,numOfTranIO){
	tranIOLenth = 500/(numOfTranIO+1);
	var m = new Array();
	for(i=0;i<numOfTranIO;i++){
		m =[];
		m.push(TranIOX);
		m.push(tranIOLenth*(1+i));	
		tranIOZuoBiao[i] = m;
	}
}
傳入的引數分別是x,和個數,x這裡是橫座標,我麼不變,主要對個數進行處理

通過迴圈,我們把起始點的座標存到tranIOZuoBiao的map裡面,每個key是序號,如0,1,2之類,value就是座標,如[10,12],[10,22],[10,33]這樣的方式,簡單來說就是map儲存如下所示

{“0”:[10,12,“1”:[10,12],[10,22],......}這樣的

其中tranIOLenth這個全域性變數就是儲存的每一段的長度,注意這裡計算是用500/(個數+1),為什麼加1,大家可以自己想一下

得到了這個以後就好辦了,我們就開始裝配這些零件,進行畫圖了

2.7 裝配零件,進行畫圖

同樣的直接通過程式碼來說明
function draw(){
	drawRowLine(x,250,100);
	tnumOfTranIO =	parseInt($("#numOfTranIO").val());
	x+=100;//就是下一段的出示x值
	calcTranIO(x,tnumOfTranIO);
	//畫第一個豎線,表示交易介面的
	setTimeout(function(){
		//畫第一段豎線
			drawColUpLine(x,250,250-tranIOLenth);
			drawColDownLine(x,250,250-tranIOLenth);
		//畫第一段橫線,根據number
	},1300);
	
	setTimeout(function(){
		for(i=0;i<tnumOfTranIO;i++){
                        //通過全域性變數取出x和y座標
                       var zuobiao = tranIOZuoBiao[i];
			var zuobiaoX=zuobiao[0];
			var zuobiaoY=zuobiao[1];

                       drawRowLine(zuobiaoX,zuobiaoY,500);
		}		
	},3000);
}
這個draw方法,首先呼叫drawRowLine來畫第一條橫線,其中x就是2.3裡面所呼叫的程式碼記錄的動態根據使用者輸入的字元長度來進行測算開始的橫座標
x = ctx.measureText(something).width+10;
接著,tnumOfTranIO儲存了使用者輸入的個數

因為第一段橫線長度寫死了,為100,所以更新x座標,為x+=100;

接著就是畫第一個豎線,分為上線兩條,從中間向上下兩邊延伸,

注意:這裡不可以直接呼叫drawCOlLine這樣的方法,要設定setTimeout來實現,因為不管是settimeout還是setinterval都有種非同步的假象,它

將執行的方法存入到佇列中執行,後面的函式會提前執行,所以,我們這裡需要根據長度來測算時延,我這裡設定了1300,就是大概第一段橫線畫完需要1300ms,也就是1.3s

畫豎線的引數設定如上所示,長度設定為250-tranIOLenth是因為避免多於的線條

最後就是呼叫緊接著的幾段畫橫線

同樣的設定setTimeout方法以後,

通過迴圈來多次drawRowLine,正如前面所說的,這裡是類似於非同步,所以這些線都是一起畫的效果

通過全域性變數取出對應第i條線的起點座標,在呼叫drawrow方法即可

Tips:因為這個我也是才學,還在摸索中,所以也及時和大家聊一聊這門技術,感覺學好了可以做很多事,包括動態製作頁面元素,製作2d遊戲等等,還是很有意思的~~

歡迎交流