åå½¢ Transformations
卿¬æç¨åé¢çé¨åä¸ï¼æä»¬å·²ç»äºè§£äº Canvas ç½æ ¼ååæ ç©ºé´ãå°ç®å为æ¢ï¼æä»¬åªæ¯æ ¹æ®æä»¬çéè¦ä½¿ç¨é»è®¤çç½æ ¼ï¼æ¹åæ´ä¸ªç»å¸ç大å°ãåå½¢æ¯ä¸ç§æ´å¼ºå¤§çæ¹æ³ï¼å¯ä»¥å°åç¹ç§»å¨å°å¦ä¸ç¹ãå¯¹ç½æ ¼è¿è¡æè½¬å缩æ¾ã
ç¶æçä¿å忢å¤
å¨äºè§£åå½¢ä¹åï¼æå ä»ç»ä¸¤ä¸ªå¨ä½ å¼å§ç»å¶å¤æå¾å½¢æ¶å¿ ä¸å¯å°çæ¹æ³ã
save()-
ä¿åç»å¸ (canvas) çææç¶æ
restore()-
save å restore æ¹æ³æ¯ç¨æ¥ä¿ååæ¢å¤ canvas ç¶æçï¼é½æ²¡æåæ°ãCanvas çç¶æå°±æ¯å½åç»é¢åºç¨çæææ ·å¼ååå½¢çä¸ä¸ªå¿«ç §ã
Canvas ç¶æåå¨å¨æ ä¸ï¼æ¯å½save()æ¹æ³è¢«è°ç¨åï¼å½åçç¶æå°±è¢«æ¨éå°æ ä¸ä¿åãä¸ä¸ªç»ç»ç¶æå
æ¬ï¼
- å½ååºç¨çåå½¢ï¼å³ç§»å¨ï¼æè½¬å缩æ¾ï¼è§ä¸ï¼
- 以åä¸é¢è¿äºå±æ§ï¼
strokeStyle,fillStyle,globalAlpha,lineWidth,lineCap,lineJoin,miterLimit,lineDashOffset,shadowOffsetX,shadowOffsetY,shadowBlur,shadowColor,globalCompositeOperation,font,textAlign,textBaseline,direction,imageSmoothingEnabled - å½åçè£åè·¯å¾ï¼clipping pathï¼ï¼ä¼å¨ä¸ä¸èä»ç»
ä½ å¯ä»¥è°ç¨ä»»æå¤æ¬¡ saveæ¹æ³ãæ¯ä¸æ¬¡è°ç¨ restore æ¹æ³ï¼ä¸ä¸ä¸ªä¿åçç¶æå°±ä»æ ä¸å¼¹åºï¼ææè®¾å®é½æ¢å¤ã
save å restore çåºç¨ç¤ºä¾
æä»¬å°è¯ç¨è¿ä¸ªè¿ç»ç©å½¢çä¾åæ¥æè¿° canvas çç¶ææ æ¯å¦ä½å·¥ä½çã
ç¬¬ä¸æ¥æ¯ç¨é»è®¤è®¾ç½®ç»ä¸ä¸ªå¤§åæ¹å½¢ï¼ç¶åä¿åä¸ä¸ç¶æãæ¹åå¡«å é¢è²ç»ç¬¬äºä¸ªå°ä¸ç¹çèè²åæ¹å½¢ï¼ç¶ååä¿åä¸ä¸ç¶æã忬¡æ¹åå¡«å é¢è²ç»å¶æ´å°ä¸ç¹çåéæçç½è²åæ¹å½¢ã
å°ç®åä¸ºæ¢æåçå¨ä½ååé¢ç« èçé½å¾ç±»ä¼¼ãä¸è¿ä¸æ¦æä»¬è°ç¨ restoreï¼ç¶ææ 䏿åçç¶æä¼å¼¹åºï¼å¹¶æ¢å¤ææè®¾ç½®ã妿䏿¯ä¹åç¨ save ä¿åäºç¶æï¼é£ä¹æä»¬å°±éè¦æå¨æ¹å设置æ¥åå°åä¸ä¸ªç¶æï¼è¿ä¸ªå¯¹äºä¸¤ä¸ä¸ªå±æ§çæ¶åè¿æ¯éç¨çï¼ä¸æ¦å¤äºï¼æä»¬ç代ç å°ä¼ç涨ã
å½ç¬¬äºæ¬¡è°ç¨ restore æ¶ï¼å·²ç»æ¢å¤å°æåçç¶æï¼å æ¤æåæ¯å䏿¬¡ç»å¶åºä¸ä¸ªé»è²ç忹形ã
function draw() {
var ctx = document.getElementById("canvas").getContext("2d");
ctx.fillRect(0, 0, 150, 150); // 使ç¨é»è®¤è®¾ç½®ç»å¶ä¸ä¸ªç©å½¢
ctx.save(); // ä¿åé»è®¤ç¶æ
ctx.fillStyle = "#09F"; // å¨åæé
ç½®åºç¡ä¸å¯¹é¢è²åæ¹å
ctx.fillRect(15, 15, 120, 120); // ä½¿ç¨æ°ç设置ç»å¶ä¸ä¸ªç©å½¢
ctx.save(); // ä¿åå½åç¶æ
ctx.fillStyle = "#FFF"; // 忬¡æ¹åé¢è²é
ç½®
ctx.globalAlpha = 0.5;
ctx.fillRect(30, 30, 90, 90); // ä½¿ç¨æ°çé
ç½®ç»å¶ä¸ä¸ªç©å½¢
ctx.restore(); // éæ°å è½½ä¹åçé¢è²ç¶æ
ctx.fillRect(45, 45, 60, 60); // 使ç¨ä¸ä¸æ¬¡çé
ç½®ç»å¶ä¸ä¸ªç©å½¢
ctx.restore(); // å è½½é»è®¤é¢è²é
ç½®
ctx.fillRect(60, 60, 30, 30); // 使ç¨å è½½çé
ç½®ç»å¶ä¸ä¸ªç©å½¢
}
ç§»å¨
æä»¬å
ä»ç» translate æ¹æ³ï¼å®ç¨æ¥ç§»å¨ canvas åå®çåç¹å°ä¸ä¸ªä¸åçä½ç½®ã
translate(x, y)-
translateæ¹æ³æ¥åä¸¤ä¸ªåæ°ã*x *æ¯å·¦å³åç§»éï¼y æ¯ä¸ä¸åç§»éï¼å¦å³å¾æç¤ºã

å¨ååå½¢ä¹åå ä¿åç¶ææ¯ä¸ä¸ªè¯å¥½çä¹ æ¯ã大夿°æ åµä¸ï¼è°ç¨ restore æ¹æ³æ¯æå¨æ¢å¤åå çç¶æè¦ç®åå¾å¤ãåï¼å¦æä½ æ¯å¨ä¸ä¸ªå¾ªç¯ä¸åä½ç§»ä½æ²¡æä¿ååæ¢å¤ canvas çç¶æï¼å¾å¯è½å°æåä¼åç°æä¹æäºä¸è¥¿ä¸è§äºï¼é£æ¯å 为å®å¾å¯è½å·²ç»è¶ åº canvas èå´ä»¥å¤äºã
translate ç示ä¾
è¿ä¸ªä¾åæ¾ç¤ºäºä¸äºç§»å¨ canvas åç¹ç好å¤ã妿ä¸ä½¿ç¨ translate æ¹æ³ï¼é£ä¹ææç©å½¢é½å°è¢«ç»å¶å¨ç¸åçä½ç½®ï¼0,0ï¼ãtranslate æ¹æ³åæ¶è®©æä»¬å¯ä»¥ä»»ææ¾ç½®è¿äºå¾æ¡ï¼èä¸éè¦å¨ fillRect() æ¹æ³ä¸æå·¥è°æ´åæ å¼ï¼æ¢å¥½çè§£ä¹æ¹ä¾¿ä½¿ç¨ã
æå¨ draw æ¹æ³ä¸è°ç¨ fillRect() æ¹æ³ 9 次ï¼ç¨äº 2 å±å¾ªç¯ãæ¯ä¸æ¬¡å¾ªç¯ï¼å
ç§»å¨ canvasï¼ç»èºæå¾æ¡ï¼ç¶åæ¢å¤å°åå§ç¶æã
function draw() {
var ctx = document.getElementById("canvas").getContext("2d");
for (var i = 0; i < 3; i++) {
for (var j = 0; j < 3; j++) {
ctx.save();
ctx.fillStyle = "rgb(" + 51 * i + ", " + (255 - 51 * i) + ", 255)";
ctx.translate(10 + j * 50, 10 + i * 50);
ctx.fillRect(0, 0, 25, 25);
ctx.restore();
}
}
}
æè½¬ Rotating

第äºä¸ªä»ç» rotateæ¹æ³ï¼å®ç¨äºä»¥åç¹ä¸ºä¸å¿æè½¬ canvasã
rotate(angle)-
è¿ä¸ªæ¹æ³åªæ¥åä¸ä¸ªåæ°ï¼æè½¬çè§åº¦ (angle)ï¼å®æ¯é¡ºæ¶éæ¹åçï¼ä»¥å¼§åº¦ä¸ºåä½çå¼ã
æè½¬çä¸å¿ç¹å§ç»æ¯ canvas çåç¹ï¼å¦æè¦æ¹åå®ï¼æä»¬éè¦ç¨å° translateæ¹æ³ã
rotate ç示ä¾
å¨è¿ä¸ªä¾åéï¼æä»¬å°ä¼ä½¿ç¨ rotate() æ¹æ³æ¥ç»åå¹¶ææå形徿¡ãå½ç¶ä½ ä¹å¯ä»¥åå«è®¡ç®åº x å y åæ ï¼x = r*Math.cos(a); y = r*Math.sin(a)ï¼ãè¿éæ 论ç¨ä»ä¹æ¹æ³é½æ æè°çï¼å 为æä»¬ç»çæ¯åã计ç®åæ çç»æåªæ¯æè½¬åå¿ä½ç½®ï¼è䏿¯åæ¬èº«ãå³ä½¿ç¨ rotateæè½¬ä¸¤è
ï¼é£äºåçä¸å»è¿æ¯ä¸æ ·çï¼ä¸ç®¡å®ä»¬ç»ä¸å¿æè½¬æå¤è¿ã
è¿éæä»¬åç¨å°äºä¸¤å±å¾ªç¯ã第ä¸å±å¾ªç¯å³å®ç¯çæ°éï¼ç¬¬äºå±å¾ªç¯å³å®æ¯ç¯æå¤å°ä¸ªç¹ãæ¯ç¯å¼å§ä¹åï¼æé½ä¿åä¸ä¸ canvas çç¶æï¼è¿æ ·æ¢å¤èµ·æ¥æ¹ä¾¿ãæ¯æ¬¡ç»åç¹ï¼æé½ä»¥ä¸å®å¤¹è§æ¥æè½¬ canvasï¼èè¿ä¸ªå¤¹è§åæ¯ç±ç¯ä¸çåç¹æ°ç®çå³å®çãæéå±çç¯æ 6 个åç¹ï¼è¿æ ·ï¼æ¯æ¬¡æè½¬ç夹è§å°±æ¯ 360/6 = 60 度ãå¾å¤æ¯ä¸ç¯çåç¹æ°ç®æ¯éé¢ä¸ç¯ç 2 åï¼é£ä¹æ¯æ¬¡æè½¬ç夹è§éä¹ååã
function draw() {
const ctx = document.getElementById("canvas").getContext("2d");
// left rectangles, rotate from canvas origin
ctx.save();
// blue rect
ctx.fillStyle = "#0095DD";
ctx.fillRect(30, 30, 100, 100);
ctx.rotate((Math.PI / 180) * 25);
// grey rect
ctx.fillStyle = "#4D4E53";
ctx.fillRect(30, 30, 100, 100);
ctx.restore();
// right rectangles, rotate from rectangle center
// draw blue rect
ctx.fillStyle = "#0095DD";
ctx.fillRect(150, 30, 100, 100);
ctx.translate(200, 80); // translate to rectangle center
// x = x + 0.5 * width
// y = y + 0.5 * height
ctx.rotate((Math.PI / 180) * 25); // rotate
ctx.translate(-200, -80); // translate back
// draw grey rect
ctx.fillStyle = "#4D4E53";
ctx.fillRect(150, 30, 100, 100);
}
缩æ¾
æ¥çæ¯ç¼©æ¾ãæä»¬ç¨å®æ¥å¢åå¾å½¢å¨ canvas ä¸çåç´ æ°ç®ï¼å¯¹å½¢ç¶ï¼ä½å¾è¿è¡ç¼©å°æè æ¾å¤§ã
scale(x, y)-
scaleæ¹æ³å¯ä»¥ç¼©æ¾ç»å¸çæ°´å¹³ååç´çåä½ãä¸¤ä¸ªåæ°é½æ¯å®æ°ï¼å¯ä»¥ä¸ºè´æ°ï¼x 为水平缩æ¾å åï¼y 为åç´ç¼©æ¾å åï¼å¦ææ¯ 1 å°ï¼ä¼ç¼©å°å¾å½¢ï¼å¦ææ¯ 1 大伿¾å¤§å¾å½¢ãé»è®¤å¼ä¸º 1ï¼ä¸ºå®é 大å°ã
ç»å¸åå§æ
åµä¸ï¼æ¯ä»¥å·¦ä¸è§åæ 为åç¹ç第ä¸è±¡éãå¦æåæ°ä¸ºè´å®æ°ï¼ç¸å½äºä»¥ x æ y è½´ä½ä¸ºå¯¹ç§°è½´éåå转ï¼ä¾å¦ï¼ä½¿ç¨translate(0,canvas.height); scale(1,-1); 以 y è½´ä½ä¸ºå¯¹ç§°è½´éåå转ï¼å°±å¯å¾å°èåçç¬å¡å°åæ ç³»ï¼å·¦ä¸è§ä¸ºåç¹ï¼ã
é»è®¤æ åµä¸ï¼canvas ç 1 个åä½ä¸º 1 个åç´ ã举ä¾è¯´ï¼å¦ææä»¬è®¾ç½®ç¼©æ¾å 忝 0.5ï¼1 个åä½å°±åæå¯¹åº 0.5 个åç´ ï¼è¿æ ·ç»å¶åºæ¥çå½¢ç¶å°±ä¼æ¯åå çä¸åãåçï¼è®¾ç½®ä¸º 2.0 æ¶ï¼1 个åä½å°±å¯¹åºåæäº 2 åç´ ï¼ç»å¶çç»æå°±æ¯å¾å½¢æ¾å¤§äº 2 åã
scale ç示ä¾
è¿æåçä¾åéï¼æä»¬ç¨ä¸åçç¼©æ¾æ¹å¼æ¥ç»ä¸¤ä¸ªå¾å½¢ã
function draw() {
var ctx = document.getElementById("canvas").getContext("2d");
// draw a simple rectangle, but scale it.
ctx.save();
ctx.scale(10, 3);
ctx.fillRect(1, 10, 10, 10);
ctx.restore();
// mirror horizontally
ctx.scale(-1, 1);
ctx.font = "48px serif";
ctx.fillText("MDN", -135, 120);
}
åå½¢
æåä¸ä¸ªæ¹æ³å 许对åå½¢ç©éµç´æ¥ä¿®æ¹ã
transform(a, b, c, d, e, f)-
è¿ä¸ªæ¹æ³æ¯å°å½åçåå½¢ç©éµä¹ä¸ä¸ä¸ªåºäºèªèº«åæ°çç©éµï¼å¦ä¸é¢çç©éµæç¤ºï¼
妿任æä¸ä¸ªåæ°æ¯
Infinityï¼åå½¢ç©éµä¹å¿ 须被æ 记为æ é大ï¼å¦å伿åºå¼å¸¸ãè¿ä¸ªå½æ°çåæ°åèªä»£è¡¨å¦ä¸ï¼
setTransform(a, b, c, d, e, f)-
è¿ä¸ªæ¹æ³ä¼å°å½åçåå½¢ç©éµé置为åä½ç©éµï¼ç¶åç¨ç¸åçåæ°è°ç¨
transformæ¹æ³ã妿任æä¸ä¸ªåæ°æ¯æ é大ï¼é£ä¹åå½¢ç©éµä¹å¿ 须被æ 记为æ é大ï¼å¦å伿åºå¼å¸¸ã仿 ¹æ¬ä¸æ¥è¯´ï¼è¯¥æ¹æ³æ¯åæ¶äºå½ååå½¢ï¼ç¶å设置为æå®çåå½¢ï¼ä¸æ¥å®æã resetTransform()-
éç½®å½åå形为åä½ç©éµï¼å®åè°ç¨ä»¥ä¸è¯å¥æ¯ä¸æ ·çï¼
ctx.setTransform(1, 0, 0, 1, 0, 0);
transform å setTransform ç示ä¾
function draw() {
var ctx = document.getElementById("canvas").getContext("2d");
var sin = Math.sin(Math.PI / 6);
var cos = Math.cos(Math.PI / 6);
ctx.translate(100, 100);
var c = 0;
for (var i = 0; i <= 12; i++) {
c = Math.floor((255 / 12) * i);
ctx.fillStyle = "rgb(" + c + "," + c + "," + c + ")";
ctx.fillRect(0, 0, 100, 10);
ctx.transform(cos, sin, -sin, cos, 0, 0);
}
ctx.setTransform(-1, 0, 0, 1, 100, 100);
ctx.fillStyle = "rgba(255, 128, 255, 0.5)";
ctx.fillRect(0, 50, 100, 100);
}