白鷺引擎(egret,以下簡稱egret)中對錨點(anchorOffsetX,anchorOffsetY)的使用目的,基本是和CSS3屬性中的transform-origin是一致的,大多是基于元素中心的旋轉(zhuǎn)和放大。但使用方法上是有區(qū)別的,比如,egret的默認錨點在左上角,而transform-origin默認在元素中心。此外,egret這類工具(還有createjs,pixi等)本身是基于canvas/webgl的畫布上進行繪制,如果使用chrome這些調(diào)試工具直接調(diào)試的話,元素信息無法被瀏覽器獲取,必然給調(diào)試增加難度。
紙上得來終覺淺,絕知此事要躬行
1. 錨點的作用
我們以一根線段旋轉(zhuǎn)90度為例:先繪制一根水平的直線,長度為100
protected startCreateScene(): void {
this.drawOneLine();
}
protected drawOneLine(){
let ns = new egret.Shape();
ns.x = 100;
ns.y = 100;
ns.graphics.lineStyle(2,0xFF0000);
ns.graphics.moveTo(0,0);
ns.graphics.lineTo(100,0);
this.addChild(ns);
}

現(xiàn)在我們修改下代碼,在默認錨點的情況下,旋轉(zhuǎn)90度。為了方便觀察,我給線段做了漸變處理,越靠近90度的線段顏色越淺:
protected startCreateScene(): void {
this.drawLine(0);
}
protected drawLine(angle): void {
let ns = new egret.Shape();
ns.x = 100;
ns.y = 100;
ns.graphics.lineStyle(2,0xFF0000);
ns.graphics.moveTo(0,0);
ns.graphics.lineTo(100,0);
ns.alpha = 1-(angle/90)*0.9;
ns.rotation = angle;
this.addChild(ns);
if(angle < 90){
this.drawLine(angle+15);
}
}

從圖片中我們可以觀察到:線段順時針旋轉(zhuǎn)了90度,中心點位于線段左邊的端點
現(xiàn)在我們設(shè)置錨點,將中心點居中
protected startCreateScene(): void {
this.drawLine(0);
this.drawLineCenter(0);
}
protected drawLineCenter(angle): void {
let ns = new egret.Shape();
ns.x = 100;
ns.y = 300;
ns.anchorOffsetX = 50; // 設(shè)置錨點橫坐標(biāo),位于線段中心
ns.graphics.lineStyle(2,0x000000);
ns.graphics.moveTo(0,0);
ns.graphics.lineTo(100,0);
ns.alpha = 1-(angle/90)*0.9;
ns.rotation = angle;
this.addChild(ns);
if(angle < 90){
this.drawLineCenter(angle+15);
}
}

好了,錨點的示例到此為止。
接下來說這篇文章的關(guān)鍵,上圖中,有一個不太正常的地方,即黑色線段往左偏移,這個對于剛接觸錨點概念的同學(xué)來說,無疑是非常殘忍的,說白了就是個坑。明明所有元素都放在其應(yīng)該出現(xiàn)的位置上,并且實現(xiàn)了動效,所有的屬性設(shè)置也都正確,怎么元素就偏了呢?我最初發(fā)生這種事(createjs里),很不理解,結(jié)果從最基礎(chǔ)的圖片素材開始,把尺寸和位置重新計算一遍,反復(fù)查看代碼中一切有的沒的的配置,最后一點點去掉所有頁面中不相關(guān)的元素,才能發(fā)現(xiàn)是錨點惹的禍。
2. 錨點的正確打開方式
現(xiàn)在,我們?nèi)匀灰蚤L度100的水平線段為例,將錨點依次設(shè)置為0,50,100,觀察這三根線段的情況,代碼如下:
protected startCreateScene(): void {
this.drawLineAnchor(100,100,0);
this.drawLineAnchor(100,150,50);
this.drawLineAnchor(100,200,100);
}
protected drawLineAnchor(x,y,anchorX):void{
let ns = new egret.Shape();
ns.x = x;
ns.y = y;
ns.anchorOffsetX = anchorX;
ns.graphics.lineStyle(2,0x000000);
ns.graphics.moveTo(0,0);
ns.graphics.lineTo(100,0);
this.addChild(ns);
}

從上圖中可以很明顯的看到錨點對于畫面中真實繪制出線段的影響
即,有元素a,a在畫面中實際的橫坐標(biāo)為
x',則x' = a.x - a.anchorOffsetX
關(guān)鍵代碼實際在于moveTo那一行,比如,當(dāng)元素根據(jù)屬性被定位到x=100,y=100后,由于其左上角的錨點由于被設(shè)置為anchorOffsetX=50,anchorOffsetY=0的關(guān)系,當(dāng)代碼進行到moveTo時,會按照錨點的坐標(biāo)向左偏移50位置開始繪制初始點。
所以,如果我們必須改變moveTo的初始點和重點,或者改變元素本身的x坐標(biāo),才能達到和原線段相同的位置:
protected startCreateScene(): void {
this.drawLineAnchor(100, 100, 0);
this.drawLineAnchorFixMove(100, 150, 50); // 修改起點終點
this.drawLineAnchorFixX(100, 200, 100); // 修改x坐標(biāo)
}
protected drawLineAnchor(){...} // 方法略
protected drawLineAnchorFixMove(x, y, anchorX): void {
let ns = new egret.Shape();
ns.x = x;
ns.y = y;
ns.anchorOffsetX = anchorX;
ns.graphics.lineStyle(1, 0x000000);
ns.graphics.moveTo(0 + anchorX, 0); // 修改線段起始點
ns.graphics.lineTo(100 + anchorX, 0); // 修改線段終點
this.addChild(ns);
}
protected drawLineAnchorFixX(x, y, anchorX): void {
let ns = new egret.Shape();
ns.x = x + anchorX; // 修改整個容器的橫坐標(biāo)
ns.y = y;
ns.anchorOffsetX = anchorX;
ns.graphics.lineStyle(1, 0x000000);
ns.graphics.moveTo(0, 0);
ns.graphics.lineTo(100, 0);
this.addChild(ns);
}

同理,我們可以得知如果修改了anchorOffsetY會發(fā)生怎樣的變化,
有元素
a,a在畫面中實際的橫坐標(biāo)為x',縱坐標(biāo)為y',則
x' = a.x - a.anchorOffsetX
y' = a.y - a.anchorOffsetY
現(xiàn)在大家應(yīng)該能理解設(shè)置錨點之后元素的具體位置了??傊?dāng)設(shè)置了錨點后,為了回到原位,最通用最簡單的做法,就是將其x,y減去自己對應(yīng)的anchorOffset屬性。
以上。