canvas实现中心旋转,各个顶点缩放
canvas有自带的 scale 方法和 rotate 方法可以实现缩放旋转,但是其作用极其简陋,要想方便调用需要自己封装。
·
前言
canvas有自带的 scale 方法和 rotate 方法可以实现缩放旋转,但是其作用极其简陋,要想方便调用需要自己封装。
1. 中心点旋转
思路很简单,先将画布移动到物体中心,然后旋转,再返回原处,再绘制物体即可,代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>旋转</title>
<style>
#myCanvas {
border: 1px solid black;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="400" height="400"></canvas>
<script>
const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');
let x = 100;
let y = 100;
let width = 100;
let height = 100;
// 绘制旋转的矩形
function drawRectangle() {
ctx.fillStyle = 'red'; // 设置填充颜色为红色
ctx.fillRect(x, y, width, height); // 绘制矩形
}
/**
* 中心点旋转
* @param {CanvasRenderingContext2D} ctx canvas 2D 上下文
* @param {Function} callback 绘制旋转矩形的回调函数
* @param {Object} setting 旋转设置
* @param {Number} setting.angle 旋转角度,弧度制
*/
function rotateCenterPoint(ctx, setting, callback) {
const { rectX, rectY, width, height, angle } = setting;
ctx.save();
ctx.translate(rectX + width / 2, rectY + height / 2); // 平移到 (100, 100)
ctx.rotate(setting.angle); // 旋转 90 度
ctx.translate(-(rectX + width / 2), -(rectY + height / 2)); // 平移回到原点
callback(); // 绘制旋转矩形
ctx.restore(); // 恢复原始状态
}
drawRectangle()
rotateCenterPoint(ctx, { rectX: 100, rectY: 100, width: 100, height: 100, angle: 45 * Math.PI / 180 }, drawRectangle)
</script>
</body>
</html>
2. 各个顶点缩放
思路和旋转一样,也是先平移,缩放,回到原处,绘制物体,不同的是需要根据模式判断是从什么点缩放的,随后需要平移补偿缩放的距离,具体代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>缩放</title>
<style>
#myCanvas {
border: 1px solid black;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="400" height="400"></canvas>
<script>
const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');
let x = 100;
let y = 100;
let width = 100;
let height = 100;
// 绘制旋转的矩形
function drawRectangle() {
ctx.fillStyle = 'red'; // 设置填充颜色为红色
ctx.fillRect(x, y, width, height); // 绘制矩形
}
/**
* 缩放功能
* callback 绘制旋转矩形的函数
* mode 从什么地方缩放
* setting.rectX 矩形 x 坐标
* setting.rectY 矩形 y 坐标
* setting.width 矩形宽度
* setting.height 矩形高度
* setting.scaleX 缩放比例 x
* setting.scaleY 缩放比例 y
*/
function scaleRect(ctx, setting, callback) {
const { rectX, rectY, width, height, scaleX, scaleY, scaleMode } = setting;
ctx.save();
ctx.translate(rectX, rectY); // 平移到 (0, 0)
ctx.scale(scaleX, scaleY);
let translateX = 0;
let translateY = 0;
if (scaleMode === 'left-top') {
// 左上角点固定的缩放
} else if (scaleMode == 'right-top') {
// 右上角点固定的缩放
translateX = (width - width * scaleX) / scaleX; // 补偿偏移量
} else if (scaleMode == 'left-bottom') {
// 左下角点固定的缩放
translateY = (height - height * scaleY) / scaleY; // 补偿偏移量
} else if (scaleMode == 'right-bottom') {
// 右下角点固定的缩放
translateX = (width - width * scaleX) / scaleX; // 补偿偏移量
translateY = (height - height * scaleY) / scaleY; // 补偿偏移量
}
ctx.translate(translateX, translateY);
ctx.translate(-rectX, -rectY); // 平移回到原点
callback();
ctx.restore(); // 恢复原始状态
return {
rectX: rectX + translateX * scaleX,
rectY: rectY + translateY * scaleY,
width: width * scaleX,
height: height * scaleY,
}
}
// scaleRect(ctx, {
// rectX: x,
// rectY: y,
// width: width,
// height: height,
// scaleX: 1.5,
// scaleY: 1.5,
// scaleMode: 'left-top',
// }, drawRectangle)
scaleRect(ctx, {
rectX: x,
rectY: y,
width: width,
height: height,
scaleX: 1.5,
scaleY: 1.5,
scaleMode: 'left-bottom',
}, drawRectangle)
ctx.fillStyle = 'yellow'; // 设置填充颜色为红色
ctx.fillRect(100, 100, 100, 100); // 绘制矩形
</script>
</body>
</html>
左下角缩放图:
3. 同时旋转缩放
先缩放,然后再将缩放得到的新坐标用于旋转即可。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>混合旋转缩放</title>
<style>
#myCanvas {
border: 1px solid black;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="400" height="400"></canvas>
<script>
const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');
// 绘制旋转的矩形
function drawRectangle(x, y, width, height, color = 'red') {
ctx.fillStyle = color; // 设置填充颜色为红色
ctx.fillRect(x, y, width, height); // 绘制矩形
}
/**
* 中心点旋转
* @param {CanvasRenderingContext2D} ctx canvas 2D 上下文
* @param {Function} callback 绘制旋转矩形的回调函数
* @param {Object} setting 旋转设置
* @param {Number} setting.angle 旋转角度,弧度制
*/
function rotateCenterPoint(ctx, setting, callback) {
const { rectX, rectY, width, height, angle } = setting;
ctx.save();
ctx.translate(rectX + width / 2, rectY + height / 2); // 平移到 (100, 100)
ctx.rotate(setting.angle); // 旋转 90 度
ctx.translate(-(rectX + width / 2), -(rectY + height / 2)); // 平移回到原点
callback(); // 绘制旋转矩形
ctx.restore(); // 恢复原始状态
}
drawRectangle(100, 100, 100, 100, 'yellow')
/**
* 缩放功能
* callback 绘制旋转矩形的函数
* mode 从什么地方缩放
* setting.rectX 矩形 x 坐标
* setting.rectY 矩形 y 坐标
* setting.width 矩形宽度
* setting.height 矩形高度
* setting.scaleX 缩放比例 x
* setting.scaleY 缩放比例 y
*/
function scaleRect(ctx, setting, callback) {
const { rectX, rectY, width, height, scaleX, scaleY, scaleMode } = setting;
ctx.save();
ctx.translate(rectX, rectY); // 平移到 (0, 0)
ctx.scale(scaleX, scaleY);
let translateX = 0;
let translateY = 0;
if (scaleMode === 'left-top') {
// 左上角点固定的缩放
} else if (scaleMode == 'right-top') {
// 右上角点固定的缩放
translateX = (width - width * scaleX) / scaleX; // 补偿偏移量
} else if (scaleMode == 'left-bottom') {
// 左下角点固定的缩放
translateY = (height - height * scaleY) / scaleY; // 补偿偏移量
} else if (scaleMode == 'right-bottom') {
// 右下角点固定的缩放
translateX = (width - width * scaleX) / scaleX; // 补偿偏移量
translateY = (height - height * scaleY) / scaleY; // 补偿偏移量
}
ctx.translate(translateX, translateY);
ctx.translate(-rectX, -rectY); // 平移回到原点
callback();
ctx.restore(); // 恢复原始状态
return {
rectX: rectX + translateX * scaleX,
rectY: rectY + translateY * scaleY,
width: width * scaleX,
height: height * scaleY,
}
}
/**
* 混合旋转缩放
*/
function mixinRotateAndScale(ctx, setting, callback) {
const { rectX, rectY, width, height, angle = 0, scaleX, scaleY, scaleMode } = setting;
// 先得到缩放后的新坐标
const scaleInfo = scaleRect(ctx, { rectX, rectY, width, height, scaleX, scaleY, scaleMode }, callback);
console.log(scaleInfo)
// 再旋转并绘画
rotateCenterPoint(ctx, { ...scaleInfo, angle },
callback.bind(null, scaleInfo.rectX, scaleInfo.rectY, scaleInfo.width, scaleInfo.height)
)
}
mixinRotateAndScale(ctx, { rectX: 100, rectY: 100, width: 100, height: 100, angle: 45 * Math.PI / 180, scaleX: 0.5, scaleY: 1.5, scaleMode: 'right-top' }, drawRectangle)
</script>
</body>
</html>
—
theme: smartblue
前言
canvas有自带的 scale 方法和 rotate 方法可以实现缩放旋转,但是其作用极其简陋,要想方便调用需要自己封装。
1. 中心点旋转
思路很简单,先将画布移动到物体中心,然后旋转,再返回原处,再绘制物体即可,代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>旋转</title>
<style>
#myCanvas {
border: 1px solid black;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="400" height="400"></canvas>
<script>
const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');
let x = 100;
let y = 100;
let width = 100;
let height = 100;
// 绘制旋转的矩形
function drawRectangle() {
ctx.fillStyle = 'red'; // 设置填充颜色为红色
ctx.fillRect(x, y, width, height); // 绘制矩形
}
/**
* 中心点旋转
* @param {CanvasRenderingContext2D} ctx canvas 2D 上下文
* @param {Function} callback 绘制旋转矩形的回调函数
* @param {Object} setting 旋转设置
* @param {Number} setting.angle 旋转角度,弧度制
*/
function rotateCenterPoint(ctx, setting, callback) {
const { rectX, rectY, width, height, angle } = setting;
ctx.save();
ctx.translate(rectX + width / 2, rectY + height / 2); // 平移到 (100, 100)
ctx.rotate(setting.angle); // 旋转 90 度
ctx.translate(-(rectX + width / 2), -(rectY + height / 2)); // 平移回到原点
callback(); // 绘制旋转矩形
ctx.restore(); // 恢复原始状态
}
drawRectangle()
rotateCenterPoint(ctx, { rectX: 100, rectY: 100, width: 100, height: 100, angle: 45 * Math.PI / 180 }, drawRectangle)
</script>
</body>
</html>
2. 各个顶点缩放
思路和旋转一样,也是先平移,缩放,回到原处,绘制物体,不同的是需要根据模式判断是从什么点缩放的,随后需要平移补偿缩放的距离,具体代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>缩放</title>
<style>
#myCanvas {
border: 1px solid black;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="400" height="400"></canvas>
<script>
const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');
let x = 100;
let y = 100;
let width = 100;
let height = 100;
// 绘制旋转的矩形
function drawRectangle() {
ctx.fillStyle = 'red'; // 设置填充颜色为红色
ctx.fillRect(x, y, width, height); // 绘制矩形
}
/**
* 缩放功能
* callback 绘制旋转矩形的函数
* mode 从什么地方缩放
* setting.rectX 矩形 x 坐标
* setting.rectY 矩形 y 坐标
* setting.width 矩形宽度
* setting.height 矩形高度
* setting.scaleX 缩放比例 x
* setting.scaleY 缩放比例 y
*/
function scaleRect(ctx, setting, callback) {
const { rectX, rectY, width, height, scaleX, scaleY, scaleMode } = setting;
ctx.save();
ctx.translate(rectX, rectY); // 平移到 (0, 0)
ctx.scale(scaleX, scaleY);
let translateX = 0;
let translateY = 0;
if (scaleMode === 'left-top') {
// 左上角点固定的缩放
} else if (scaleMode == 'right-top') {
// 右上角点固定的缩放
translateX = (width - width * scaleX) / scaleX; // 补偿偏移量
} else if (scaleMode == 'left-bottom') {
// 左下角点固定的缩放
translateY = (height - height * scaleY) / scaleY; // 补偿偏移量
} else if (scaleMode == 'right-bottom') {
// 右下角点固定的缩放
translateX = (width - width * scaleX) / scaleX; // 补偿偏移量
translateY = (height - height * scaleY) / scaleY; // 补偿偏移量
}
ctx.translate(translateX, translateY);
ctx.translate(-rectX, -rectY); // 平移回到原点
callback();
ctx.restore(); // 恢复原始状态
return {
rectX: rectX + translateX * scaleX,
rectY: rectY + translateY * scaleY,
width: width * scaleX,
height: height * scaleY,
}
}
// scaleRect(ctx, {
// rectX: x,
// rectY: y,
// width: width,
// height: height,
// scaleX: 1.5,
// scaleY: 1.5,
// scaleMode: 'left-top',
// }, drawRectangle)
scaleRect(ctx, {
rectX: x,
rectY: y,
width: width,
height: height,
scaleX: 1.5,
scaleY: 1.5,
scaleMode: 'left-bottom',
}, drawRectangle)
ctx.fillStyle = 'yellow'; // 设置填充颜色为红色
ctx.fillRect(100, 100, 100, 100); // 绘制矩形
</script>
</body>
</html>
左下角缩放图:
3. 同时旋转缩放
先缩放,然后再将缩放得到的新坐标用于旋转即可。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>混合旋转缩放</title>
<style>
#myCanvas {
border: 1px solid black;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="400" height="400"></canvas>
<script>
const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');
// 绘制旋转的矩形
function drawRectangle(x, y, width, height, color = 'red') {
ctx.fillStyle = color; // 设置填充颜色为红色
ctx.fillRect(x, y, width, height); // 绘制矩形
}
/**
* 中心点旋转
* @param {CanvasRenderingContext2D} ctx canvas 2D 上下文
* @param {Function} callback 绘制旋转矩形的回调函数
* @param {Object} setting 旋转设置
* @param {Number} setting.angle 旋转角度,弧度制
*/
function rotateCenterPoint(ctx, setting, callback) {
const { rectX, rectY, width, height, angle } = setting;
ctx.save();
ctx.translate(rectX + width / 2, rectY + height / 2); // 平移到 (100, 100)
ctx.rotate(setting.angle); // 旋转 90 度
ctx.translate(-(rectX + width / 2), -(rectY + height / 2)); // 平移回到原点
callback(); // 绘制旋转矩形
ctx.restore(); // 恢复原始状态
}
drawRectangle(100, 100, 100, 100, 'yellow')
/**
* 缩放功能
* callback 绘制旋转矩形的函数
* mode 从什么地方缩放
* setting.rectX 矩形 x 坐标
* setting.rectY 矩形 y 坐标
* setting.width 矩形宽度
* setting.height 矩形高度
* setting.scaleX 缩放比例 x
* setting.scaleY 缩放比例 y
*/
function scaleRect(ctx, setting, callback) {
const { rectX, rectY, width, height, scaleX, scaleY, scaleMode } = setting;
ctx.save();
ctx.translate(rectX, rectY); // 平移到 (0, 0)
ctx.scale(scaleX, scaleY);
let translateX = 0;
let translateY = 0;
if (scaleMode === 'left-top') {
// 左上角点固定的缩放
} else if (scaleMode == 'right-top') {
// 右上角点固定的缩放
translateX = (width - width * scaleX) / scaleX; // 补偿偏移量
} else if (scaleMode == 'left-bottom') {
// 左下角点固定的缩放
translateY = (height - height * scaleY) / scaleY; // 补偿偏移量
} else if (scaleMode == 'right-bottom') {
// 右下角点固定的缩放
translateX = (width - width * scaleX) / scaleX; // 补偿偏移量
translateY = (height - height * scaleY) / scaleY; // 补偿偏移量
}
ctx.translate(translateX, translateY);
ctx.translate(-rectX, -rectY); // 平移回到原点
callback();
ctx.restore(); // 恢复原始状态
return {
rectX: rectX + translateX * scaleX,
rectY: rectY + translateY * scaleY,
width: width * scaleX,
height: height * scaleY,
}
}
/**
* 混合旋转缩放
*/
function mixinRotateAndScale(ctx, setting, callback) {
const { rectX, rectY, width, height, angle = 0, scaleX, scaleY, scaleMode } = setting;
// 先得到缩放后的新坐标
const scaleInfo = scaleRect(ctx, { rectX, rectY, width, height, scaleX, scaleY, scaleMode }, callback);
console.log(scaleInfo)
// 再旋转并绘画
rotateCenterPoint(ctx, { ...scaleInfo, angle },
callback.bind(null, scaleInfo.rectX, scaleInfo.rectY, scaleInfo.width, scaleInfo.height)
)
}
mixinRotateAndScale(ctx, { rectX: 100, rectY: 100, width: 100, height: 100, angle: 45 * Math.PI / 180, scaleX: 0.5, scaleY: 1.5, scaleMode: 'right-top' }, drawRectangle)
</script>
</body>
</html>
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
已为社区贡献4条内容
所有评论(0)