2D人体姿势生成器:一个简单而强大的Web工具
在数字艺术和动画领域,快速创建和调整人体姿势是一项常见而重要的任务。今天,我们将介绍一个简单但功能强大的工具:2D人体姿势生成器。这个基于Web的工具允许用户轻松创建、调整和导出2D人体姿势,非常适合艺术家、动画师或任何需要快速草绘人体姿势的人使用。
功能特点
- 交互式火柴人: 用户可以通过拖拽关节点来自由调整火柴人的姿势。
- 直观的头部控制: 通过移动头顶和颈部节点来调整头部的角度和位置。
- 完整的人体结构: 包括头部、躯干、手臂和腿部,共11个可调节的关节点。
- 图片导出: 一键将当前姿势导出为PNG格式的图片,背景为白色,便于进一步编辑或使用。
- 轻量级设计: 纯HTML、CSS和JavaScript实现,无需任何外部依赖。
技术实现
这个工具主要使用HTML5 Canvas来绘制火柴人,并通过JavaScript来处理用户交互。下面是一些关键代码片段及其解释:
1. 关节点定义
const joints = [
{
x: 200, y: 50, name: 'headTop'}, // 头顶
{
x: 200, y: 100, name: 'neck'}, // 颈部
{
x: 200, y: 200, name: 'hip'}, // 臀部
// ... 其他关节点
];
这个数组定义了火柴人的所有关节点,包括它们的初始位置和名称。
2. 绘制函数
function drawStickman(fillBackground = false) {
// ... 绘制代码
}
这个函数负责在Canvas上绘制火柴人。它可以选择是否填充白色背景(用于导出图片时)。
3. 用户交互
canvas.addEventListener('mousedown', (e) => {
// ... 鼠标按下事件处理
});
canvas.addEventListener('mousemove', (e) => {
// ... 鼠标移动事件处理
});
canvas.addEventListener('mouseup', () => {
// ... 鼠标松开事件处理
});
这些事件监听器处理用户的鼠标交互,允许用户拖动和调整关节点的位置。
4. 图片导出
downloadBtn.addEventListener('click', () => {
drawStickman(true); // 绘制带白色背景的图像
const dataUrl = canvas.toDataURL('image/png');
// ... 创建下载链接
});
这段代码处理图片导出功能,将Canvas内容转换为PNG格式的数据URL,并触发下载。
完整代码
以下是这个2D人体姿势生成器的完整HTML代码,包括HTML结构、CSS样式和JavaScript逻辑:
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>高级2D人体姿势生成器</title>
<style>
body {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 100vh;
margin: 0;
background-color: #f0f0f0;
font-family: Arial, sans-serif;
}
#canvas {
border: 1px solid #000;
background-color: #fff;
margin-bottom: 10px;
}
#downloadBtn {
padding: 10px 20px;
font-size: 16px;
background-color: #4CAF50;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
transition: background-color 0.3s;
}
#downloadBtn:hover {
background-color: #45a049;
}
</style>
</head>
<body>
<canvas id="canvas" width="400" height="400"></canvas>
<button id="downloadBtn">下载姿势图片</button>
<script>
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
const downloadBtn = document.getElementById('downloadBtn');
// 定义关节点
const joints = [
{
x: 200, y: 50, name: 'headTop'}, // 头顶
{
x: 200, y: 100, name: 'neck'}, // 颈部
{
x: 200, y: 200, name: 'hip'}, // 臀部
{
x: 150, y: 150, name: 'leftElbow'}, // 左肘
{
x: 100, y: 200, name: 'leftHand'}, // 左手
{
x: 250, y: 150, name: 'rightElbow'}, // 右肘
{
x: 300, y: 200, name: 'rightHand'}, // 右手
{
x: 175, y: 300, name: 'leftKnee'}, // 左膝
{
x: 150, y: 380, name: 'leftFoot'}, // 左脚
{
x: 225, y: 300, name: 'rightKnee'}, // 右膝
{
x: 250, y: 380, name: 'rightFoot'} // 右脚
];
function drawStickman(fillBackground = false) {
if (fillBackground) {
// 如果需要填充背景,则填充白色
ctx.fillStyle = 'white';
ctx.fillRect(0, 0, canvas.width, canvas.height);
} else {
// 否则清除画布
ctx.clearRect(0, 0, canvas.width, canvas.height);
}
ctx.strokeStyle = 'black';
ctx.fillStyle = 'black';
// 绘制身体
ctx.beginPath();
ctx.moveTo(joints[1].x, joints[1].y); // 从颈部开始
ctx.lineTo(joints[2].x, joints[2].y); // 到臀部
ctx.moveTo(joints[1].x, joints[1].y);
ctx.lineTo(joints[3].x, joints[3].y); // 到左肘
ctx.lineTo(joints[4].x, joints[4].y); // 到左手
ctx.moveTo(joints[1].x, joints[1].y);
ctx.lineTo(joints[5].x, joints[5].y); // 到右肘
ctx.lineTo(joints[6].x, joints[6].y); // 到右手
ctx.moveTo(joints[2].x, joints[2].y);
ctx.lineTo(joints[7].x, joints[7].y); // 到左膝
ctx.lineTo(joints[8].x, joints[8].y); // 到左脚
ctx.moveTo(joints[2].x, joints[2].y);
ctx.lineTo(joints[9].x, joints[9].y); // 到右膝
ctx.lineTo(joints[10].x, joints[10].y); // 到右脚
ctx.stroke();
// 绘制头部
const headAngle = Math.atan2(joints[0].y - joints[1].y, joints[0].x - joints[1].x);
const headMidX = (joints[0].x + joints[1].x) / 2;
const headMidY = (joints[0].y + joints[1].y) / 2;
ctx.save();
ctx.translate(headMidX, headMidY);
ctx.rotate(headAngle + Math.PI / 2);
ctx.beginPath();
ctx.ellipse(0, 0, 15, 20, 0, 0, 2 * Math.PI);
ctx.stroke();
ctx.restore();
// 绘制从颈部到头顶的线
ctx.beginPath();
ctx.moveTo(joints[1].x, joints[1].y);
ctx.lineTo(joints[0].x, joints[0].y);
ctx.stroke();
// 绘制关节点
joints.forEach(joint => {
ctx.beginPath();
ctx.arc(joint.x, joint.y, 5, 0, Math.PI * 2);
ctx.fill();
});
}
let dragging = false;
let selectedJoint = null;
// 鼠标按下事件
canvas.addEventListener('mousedown', (e) => {
const rect = canvas.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
joints.forEach(joint => {
if (Math.abs(x - joint.x) < 10 && Math.abs(y - joint.y) < 10) {
dragging = true;
selectedJoint = joint;
}
});
});
// 鼠标移动事件
canvas.addEventListener('mousemove', (e) => {
if (dragging && selectedJoint) {
const rect = canvas.getBoundingClientRect();
selectedJoint.x = e.clientX - rect.left;
selectedJoint.y = e.clientY - rect.top;
drawStickman();
}
});
// 鼠标松开事件
canvas.addEventListener('mouseup', () => {
dragging = false;
selectedJoint = null;
});
// 下载按钮点击事件
downloadBtn.addEventListener('click', () => {
drawStickman(true); // 绘制带白色背景的图像
const dataUrl = canvas.toDataURL('image/png');
const link = document.createElement('a');
link.download = 'stick-figure-pose.png';
link.href = dataUrl;
link.click();
drawStickman(); // 重新绘制不带背景的图像,以便继续编辑
});
// 初始绘制
drawStickman();
</script>
</body>
</html>
如何使用
- 调整姿势: 点击并拖动任意关节点来调整火柴人的姿势。头部可以通过移动头顶和颈部节点来调整角度和位置。
- 导出图片: 当你对姿势满意时,点击"下载姿势图片"按钮。你的浏览器会自动下载一个名为"stick-figure-pose.png"的PNG图片文件,其中包含当前的火柴人姿势,背景为白色。
如何运行
要运行这个2D人体姿势生成器,只需将上面的完整代码保存为一个HTML文件(例如pose-generator.html
),然后用现代浏览器(如Chrome、Firefox、Safari或Edge)打开这个文件即可。
结论
这个2D人体姿势生成器虽然简单,但展示了Web技术在创意工具开发中的潜力。通过组合HTML5 Canvas和JavaScript,我们创建了一个直观、易用且功能强大的工具。无论你是数字艺术家、动画师,还是just for fun,希望这个工具能为你的创作过程带来便利和乐趣。