在canvas的繪圖api中旋轉(rotate)與縮放(scale),如果直接調用的話是得不到想要的效果的,必須經過相應設置(偏移或其它)之后才能得到想要的效果。
下面記錄一下canvas中隨物體中心縮放的處理。
縮放的步驟:
1.先執行縮放
2.對畫布進行偏移(translate):
x: - (物體中心(x軸) * (x軸的縮放值 - 1)) / x軸的縮放值
y: - (物體中心 (y軸) * (y軸的縮放值 - 1)) / y軸的縮放值
3. 進行普通的繪圖操作
具體實現:
html:
<canvas class="cv"></canvas>
javascript:
let cv = document.querySelector('.cv'), ctx = cv.getContext('2d'), /* * @param Number sx 物體開始繪制的x點 * @param Number sy 物體開始繪制的y點 * @param Number width 物體開始繪制的寬 * @param Number height 物體開始繪制的高 */ getCenter = (sx, sy, width, height) => { // 返回物體的中心點 return { x: sx + (width / 2), y: sy + (height / 2) }; }, /* * 繪制圖形 */ draw = () => { let arc_x = 150, // 圓心x軸 arc_y = 150, // 圓心y軸 arc_r = 20, // 圓半徑 s = { // 縮放值 x: 2, y: 2 }, arc_center = getCenter(arc_x - arc_r, arc_y - arc_r, 2 * arc_r, 2 * arc_r); // 圓心 ctx.clearRect(0, 0, cv.width, cv.height); // 繪制圓 ctx.save(); // 保存狀態,以免影響其它物體 ctx.scale(s.x, s.y); // 執行縮放 ctx.translate(- (arc_center.x * (s.x - 1)) / s.x, - (arc_center.y * (s.y - 1)) / s.y); // 縮放后的差偏移回來 ctx.beginPath(); // 開啟路徑 ctx.arc(arc_x, arc_y, arc_r, 0, 2 * Math.PI); // 繪制圓 ctx.closePath(); // 關閉路徑 ctx.stroke(); // 描邊繪制 ctx.restore();// 恢復狀態 }; // 畫布大小 cv.width = 800; cv.height = 500; draw(); // 開始繪制縮放
其它物體(圓、矩形、直線)的縮放的完整實現:
<!DOCTYPE html> <html> <head> <title></title> </head> <body> <canvas class="cv"></canvas> <script type="text/javascript"> let cv = document.querySelector('.cv'), ctx = cv.getContext('2d'), sv = 0, // 縮放的增加值 speed = 0.01, // 縮放增加速度 /* * @param Number sx 物體開始繪制的x點 * @param Number sy 物體開始繪制的y點 * @param Number width 物體開始繪制的寬 * @param Number height 物體開始繪制的高 */ getCenter = (sx, sy, width, height) => { // 返回物體的中心點 return { x: sx + (width / 2), y: sy + (height / 2) }; }, /* * 繪制圖形 */ draw = () => { let arc_x = 150, // 圓心x軸 arc_y = 150, // 圓心y軸 arc_r = 20, // 圓半徑 rect_x = 300, // 矩形x軸 rect_y = 100,// 矩形y軸 rect_width = 50,// 矩形的寬 rect_height = 50,// 矩形的高 line_sx = 500, // 直線起點x軸 line_sy = 100, // 直線起點y軸 line_ex = 600, // 直線終點x軸 line_ey = 210, // 直線終點y軸 s = { // 縮放值 x: 1 + sv, y: 1 + sv }, arc_center = getCenter(arc_x - arc_r, arc_y - arc_r, 2 * arc_r, 2 * arc_r), // 圓心 rect_center = getCenter(rect_x, rect_y, rect_width, rect_height), // 矩形中心 line_center = getCenter(line_sx, line_sy, line_ex - line_sx, line_ey - line_sy); // 直線中心 ctx.clearRect(0, 0, cv.width, cv.height); // 繪制圓 ctx.save(); // 保存狀態,以免影響其它物體 ctx.scale(s.x, s.y); // 執行縮放 ctx.translate(- (arc_center.x * (s.x - 1)) / s.x, - (arc_center.y * (s.y - 1)) / s.y); // 縮放后的差偏移回來 ctx.beginPath(); // 開啟路徑 ctx.arc(arc_x, arc_y, arc_r, 0, 2 * Math.PI); // 繪制圓 ctx.closePath(); // 關閉路徑 ctx.stroke(); // 描邊繪制 ctx.restore();// 恢復狀態 // 繪制矩形 ctx.save(); ctx.scale(s.x, s.y); ctx.translate(- (rect_center.x * (s.x - 1)) / s.x, - (rect_center.y * (s.y - 1)) / s.y); ctx.beginPath(); ctx.strokeRect(rect_x, rect_y, rect_width, rect_height); ctx.closePath(); ctx.restore(); // 繪制直線 ctx.save(); ctx.scale(s.x, s.y); ctx.translate(- (line_center.x * (s.x - 1)) / s.x, - (line_center.y * (s.y - 1)) / s.y); ctx.beginPath(); ctx.moveTo(line_sx, line_sy); ctx.lineTo(line_ex, line_ey); ctx.closePath(); ctx.stroke(); // 繪制線的外框,以便明顯線的縮放 ctx.beginPath(); ctx.strokeStyle = '#bbb'; ctx.strokeRect(line_sx, line_sy, line_ex - line_sx, line_ey - line_sy); ctx.closePath(); ctx.restore(); sv += speed; if (sv <= 2) { requestAnimationFrame(draw); } }; // 畫布大小 cv.width = 800; cv.height = 500; window.requestAnimationFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function (callback) { callback && setTimeout(callback, 1000 / 60); }; draw(); // 開始繪制縮放 </script> </body> </html>