国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

聊聊 Container 的實(shí)現(xiàn)

mudiyouyou / 2173人閱讀

摘要:原生實(shí)現(xiàn)只存在于渲染引擎,原生是不存在的。假設(shè)有以下的代碼包括了,換種說法是劃分在同一組。于是,實(shí)現(xiàn)了一群粒子做同一件事其實(shí)就是實(shí)現(xiàn)了原生下的容器。不過,容器除了嵌套行為,它還有并列的行為兄弟容器。當(dāng)作一次記憶加深的過程。

查了一下有道:

Container
n. 集裝箱;容器

DisplayObject 實(shí)例分類

我目前用到過的 DisplayObject 有5種:Bitmap, Shape, Text, MovieClip 和 Container。(好像 CreateJS 就只有這5種 DisplayObject)。不過,MovieClip 其實(shí)繼承自 Container,所以 MovieClip 可以當(dāng)作一個 Container。

與 HTML 做個類比:

Bitmap & Shape == ;

Text == 文本;

Container ==

很容易發(fā)現(xiàn)除了 Container 能嵌套子元素外,其它 4 種都不能。按這個維度分類,DisplayObject 有兩類:

容器:Container

粒子:Bitmap, Shape, Text, MovieClip

「容器」的作用是分組管理「粒子」。CreateJS 的 Stage 就是最著名的一個容器。

But...原生 Canvas 并沒有粒子與容器的概念,它有繪制圖片圖形等底層APIs。類似于 CreateJS 的 Canvas 渲染引擎的厲害之處就在于把底層 APIs 封裝起來并使之有了對象(容器與粒子)的概念。面對對象的好處大家都是知道的。

原生 APIs 實(shí)現(xiàn) Container

Container 只存在于渲染引擎,原生 Canvas 是不存在的。「粒子」也不存在于原生 Canvas,但是如果把 MovieClip 剔除,其它三個「粒子」其實(shí)都有對應(yīng)的原生 Canvas APIs:

Bitmap ------ drawImage

Shape ------ rect/arc/moveTo/lineTo...

Text ---- fillText

由于有一一對應(yīng)的 API,所以粒子在實(shí)現(xiàn)就是一個一一對應(yīng)搬 APIs 的過程。但是「容器」就需要討論一下了。

假設(shè)有以下的 HTML 代碼:


    Text...
    
    

包括了 Text... & & ,換種說法是:Text... & & 劃分在同一組。從管理的角度上說,劃分一組后,可以對一組粒子統(tǒng)一進(jìn)行以下操作:

透明度

可見性

矩陣轉(zhuǎn)換

什么是矩陣轉(zhuǎn)換?
一個圖形的位移(translate)與形變(scale, rotate, skew)可以統(tǒng)一用一個矩陣來表示,所以「矩陣轉(zhuǎn)換」就是位移和形變的統(tǒng)稱。原生 Canvas 的 提供了矩陣轉(zhuǎn)換 API:

scale() 縮放當(dāng)前繪圖至更大或更小

rotate() 旋轉(zhuǎn)當(dāng)前繪圖

translate() 重新映射畫布上的 (0,0) 位置

transform() 替換繪圖的當(dāng)前轉(zhuǎn)換矩陣

setTransform() 將當(dāng)前轉(zhuǎn)換重置為單位矩陣。然后運(yùn)行 transform()

具體可以參見:http://www.w3school.com.cn/ta...

原生 Canvas 存在一個全局矩陣,通過上面的「矩陣轉(zhuǎn)換」API 可以修改這個全局矩陣。「矩陣轉(zhuǎn)換」在使用過程中有以下兩個特點(diǎn):

「矩陣轉(zhuǎn)換」后不影響已繪制的圖像圖形,它只作用于之后繪制 API;

「矩陣轉(zhuǎn)換」對全局矩陣的轉(zhuǎn)換是累加性的;

以下代碼可以驗(yàn)證上面兩個特性:

var ctx = canvas.getContext("2d"); 
ctx.rect(150, 150, 400, 400); 
ctx.fillStyle = "#d00000"; 
ctx.fill(); 
// 縮小一倍
ctx.beginPath(); 
ctx.scale(.5, .5); 
ctx.rect(150, 150, 400, 400); 
ctx.fillStyle = "#00d000"; 
ctx.fill(); 

// 縮小一倍
ctx.beginPath(); 
ctx.scale(.5, .5); 
ctx.rect(150, 150, 400, 400); 
ctx.fillStyle = "#0000d0"; 
ctx.fill(); 

截圖如下:

分「容器」后的「粒子」可以統(tǒng)一做同一件事,那么統(tǒng)一做同一件事的一群「粒子」不就可以認(rèn)為是一個「容器」。于是,實(shí)現(xiàn)了一群「粒子」做同一件事其實(shí)就是實(shí)現(xiàn)了原生 Canvas 下的「容器」。

「矩陣轉(zhuǎn)換」的第一個特性像極了「容器」的行為,第二個特性像極了「容器」嵌套「容器」的行為。不過,「容器」除了嵌套行為,它還有并列的行為(兄弟容器)。

如何實(shí)現(xiàn)「容器」并列?
兄弟「容器」A 與 B,A 比 B 早出現(xiàn)在畫布上;作為兄弟「容器」,A 的「矩陣轉(zhuǎn)換」不能對 B 產(chǎn)生影響,這好像跟第二個特性沖突了?。。?!不過,能累加的東西就有辦法可以反向累加,如下:

var ctx = canvas.getContext("2d");
// 縮小一倍
ctx.beginPath(); 
ctx.scale(.5, .5); 
ctx.rect(150, 150, 400, 400); 
ctx.fillStyle = "#00d000"; 
ctx.fill(); 

// 反向累加 ----- 消除上次的轉(zhuǎn)換
ctx.scale(2, 2); 

// 縮小一倍
ctx.beginPath(); 
ctx.scale(.5, .5); 
ctx.rect(600, 150, 400, 400); 
ctx.fillStyle = "#0000d0"; 
ctx.fill();

效果截圖如下:

理論上通過反向累加可以實(shí)現(xiàn)矩陣回退的效果,但在嵌套復(fù)雜的情況下,這個方案比較復(fù)雜而麻煩。But...別忘了 Canvas 有一對兄弟 APIs: save & restore。

save() 保存當(dāng)前環(huán)境的狀態(tài)

restore() 回退到上一次 save 保存的狀態(tài)

通過這兩個 APIs 可以輕松地實(shí)現(xiàn)「全局矩陣」的回退,從而達(dá)到實(shí)現(xiàn)「兄弟容器」目的,如下:

var ctx = canvas.getContext("2d");

// 保存狀態(tài)
ctx.save(); 
// 縮小一倍
ctx.beginPath(); 
ctx.scale(.5, .5); 
ctx.rect(150, 150, 400, 400); 
ctx.fillStyle = "#00d000"; 
ctx.fill(); 

// 恢復(fù)到上一次狀態(tài)
ctx.restore(); 

// 縮小一倍
ctx.beginPath(); 
ctx.scale(.5, .5); 
ctx.rect(600, 150, 400, 400); 
ctx.fillStyle = "#0000d0"; 
ctx.fill();

截圖與使用反向累加一樣。

如果讓我用原生 canvas 來實(shí)現(xiàn)「容器」,我會這樣設(shè)計(jì):

「容器」是存放子元素(「粒子」與「子容器」)的數(shù)組

「粒子」是一個繪制具體任務(wù)的 Funtion

子元素由 ctx.save() 開始,ctx.restore()結(jié)束

以下是偽代碼:

var ctx = canvas.getContext("2d");
let [containerA, containerB, stage] = [[], [], [containerA, containerB]]; 
// 粒子是一個繪制圖形的 function
let particleA1 = () => {
    ctx.rect(x, y, w, h); 
    ctx.fillStyle = "#d00000"; 
    ctx.fill();  
}
let particleA2 = () => ...; 
let particleB1 = () => ...; 
let particleB2 = () => ...; 

containerA = [particleA1, particleA2]; 
containerB = [particleB1, particleB2]; 

// 繪制 container
let renderContainer = container => container.forEach(
    child => {
        // 保存狀態(tài)
        ctx.save(); 
        // 子元素是容器
        if(isContainer(child)) renderContainer(child); 
        // 粒子
        else renderParticle(child);
        // 恢復(fù)狀態(tài)
        ctx.restore(); 
    }
); 

// 吐出 stage 
renderContainer(stage);
CreateJS 的 Container

來看一下 CreateJS 是怎么實(shí)現(xiàn) Container的,如下:


https://www.createjs.com/docs...

跟我的設(shè)計(jì)其實(shí)是類似的。上圖紅框的 updateContext 其實(shí)就是處理「矩陣轉(zhuǎn)換」如下:


https://www.createjs.com/docs...

結(jié)語

本來想隨手寫寫的,沒想到寫得有點(diǎn)長。當(dāng)作一次記憶加深的過程。

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/89641.html

相關(guān)文章

  • 聊聊Tomcat架構(gòu)設(shè)計(jì)

    摘要:本篇文章主要是跟大家聊聊的內(nèi)部架構(gòu)體系,讓大家對有個整體的認(rèn)知。方法會創(chuàng)建一個對象,調(diào)用它的方法將字節(jié)流封裝成對象,在創(chuàng)建組件時,會將組件添加到組件中組件而組件在連接器初始化時就已經(jīng)創(chuàng)建好了目前為止,只有一個實(shí)現(xiàn)類,就是。 微信公眾號「后端進(jìn)階」,專注后端技術(shù)分享:Java、Golang、WEB框架、分布式中間件、服務(wù)治理等等。 老司機(jī)傾囊相授,帶你一路進(jìn)階,來不及解釋了快上車! T...

    cnio 評論0 收藏0
  • 簡單聊聊瀏覽器JS事件觸發(fā)機(jī)制

    摘要:事件冒泡由微軟提出,事件會從最內(nèi)從的元素開始發(fā)生,再向外傳播,正好與事件捕獲相反。為了解決上述問題,我們可以利用事件委托的思想,在父級注冊一個事件監(jiān)聽器,統(tǒng)一進(jìn)行子元素的事件處理。 原理 事件捕獲 由網(wǎng)景最先提出,事件會從最外層開始發(fā)生,直到最具體的元素,也就是說假如父元素與子元素都綁定有點(diǎn)擊事件,又互相重疊,那么先出發(fā)的會是父元素的事件,然后再傳遞到子元素。 事件冒泡 由微軟提出,事...

    enrecul101 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<