html canvas 让物体随物体中心缩放
在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>