openpose-editor
Version:
A pose editor library made with React and TypeScript
184 lines (174 loc) • 7.67 kB
JavaScript
;
var React = require('react');
/******************************************************************************
Copyright (c) Microsoft Corporation.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */
/* global Reflect, Promise, SuppressedError, Symbol, Iterator */
var __assign = function() {
__assign = Object.assign || function __assign(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
var e = new Error(message);
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
};
var PoseEditor = function (_a) {
var imageSrc = _a.imageSrc, poseData = _a.poseData, onPoseChange = _a.onPoseChange, _b = _a.width, width = _b === void 0 ? 640 : _b, _c = _a.height, height = _c === void 0 ? 480 : _c, styles = _a.styles;
var canvasRef = React.useRef(null);
var _d = React.useState(poseData), pose = _d[0], setPose = _d[1];
var _e = React.useState({
isDragging: false,
keypointIndex: null,
}), dragging = _e[0], setDragging = _e[1];
// 관절 그리기 함수
var drawKeypoints = function (keypoints, ctx) {
keypoints.forEach(function (keypoint) {
var _a = keypoint.position, x = _a.x, y = _a.y;
ctx.beginPath();
ctx.arc(x, y, 5, 0, 2 * Math.PI);
ctx.fillStyle = 'red';
ctx.fill();
});
};
// 뼈대 그리기 함수
var drawSkeleton = function (keypoints, ctx) {
var adjacentKeyPoints = [
['nose', 'leftEye'],
['nose', 'rightEye'],
['leftEye', 'leftEar'],
['rightEye', 'rightEar'],
['nose', 'neck'], // 코에서 목으로 연결
['neck', 'leftShoulder'], // 목에서 왼쪽 어깨로 연결
['neck', 'rightShoulder'], // 목에서 오른쪽 어깨로 연결
['leftShoulder', 'rightShoulder'], // 어깨끼리 연결
['leftShoulder', 'leftElbow'], // 왼쪽 팔 연결
['leftElbow', 'leftWrist'], // 왼쪽 팔꿈치에서 손목 연결
['rightShoulder', 'rightElbow'], // 오른쪽 팔 연결
['rightElbow', 'rightWrist'], // 오른쪽 팔꿈치에서 손목 연결
['torso', 'leftHip'], // 몸통 중심에서 왼쪽 힙으로 연결
['torso', 'rightHip'], // 몸통 중심에서 오른쪽 힙으로 연결
['leftHip', 'rightHip'], // 양쪽 힙을 연결
['leftHip', 'leftKnee'], // 왼쪽 다리 연결
['leftKnee', 'leftAnkle'], // 왼쪽 무릎에서 발목 연결
['rightHip', 'rightKnee'], // 오른쪽 다리 연결
['rightKnee', 'rightAnkle'], // 오른쪽 무릎에서 발목 연결
];
adjacentKeyPoints.forEach(function (_a) {
var partA = _a[0], partB = _a[1];
var keypointA = keypoints.find(function (kp) { return kp.part === partA; });
var keypointB = keypoints.find(function (kp) { return kp.part === partB; });
if (keypointA && keypointB) {
ctx.beginPath();
ctx.moveTo(keypointA.position.x, keypointA.position.y);
ctx.lineTo(keypointB.position.x, keypointB.position.y);
ctx.strokeStyle = 'blue';
ctx.lineWidth = 2;
ctx.stroke();
}
});
};
// 마우스 좌표 계산 함수
var getMousePos = function (canvas, evt) {
var rect = canvas.getBoundingClientRect();
var clientX, clientY;
if (evt instanceof MouseEvent) {
clientX = evt.clientX;
clientY = evt.clientY;
}
else {
clientX = evt.touches[0].clientX;
clientY = evt.touches[0].clientY;
}
return {
x: clientX - rect.left,
y: clientY - rect.top,
};
};
// 이벤트 핸들러
var handleMouseDown = function (e) {
e.preventDefault();
if (!canvasRef.current)
return;
var mousePos = getMousePos(canvasRef.current, e);
var radius = 5;
var keypointIndex = pose.keypoints.findIndex(function (keypoint) {
var dx = keypoint.position.x - mousePos.x;
var dy = keypoint.position.y - mousePos.y;
return dx * dx + dy * dy < radius * radius;
});
if (keypointIndex !== -1) {
setDragging({ isDragging: true, keypointIndex: keypointIndex });
}
};
var handleMouseMove = function (e) {
e.preventDefault();
if (!canvasRef.current || !dragging.isDragging)
return;
var mousePos = getMousePos(canvasRef.current, e);
var updatedPose = __assign({}, pose);
updatedPose.keypoints[dragging.keypointIndex].position = {
x: mousePos.x,
y: mousePos.y,
};
setPose(updatedPose);
// 포즈 변경 콜백 호출
if (onPoseChange) {
onPoseChange(updatedPose);
}
};
var handleMouseUp = function (e) {
e.preventDefault();
if (dragging.isDragging) {
setDragging({ isDragging: false, keypointIndex: null });
}
};
// 이미지 로드 및 그리기
React.useEffect(function () {
var canvas = canvasRef.current;
if (!canvas)
return;
var context = canvas === null || canvas === void 0 ? void 0 : canvas.getContext('2d');
if (!context)
return;
var image = new Image();
image.src = imageSrc;
image.onload = function () {
context.clearRect(0, 0, canvas.width, canvas.height);
context.drawImage(image, 0, 0, canvas.width, canvas.height);
drawKeypoints(pose.keypoints, context);
drawSkeleton(pose.keypoints, context);
};
}, [pose, imageSrc]);
// 마우스 이벤트 핸들러 등록
React.useEffect(function () {
var canvas = canvasRef.current;
if (!canvas)
return;
canvas.addEventListener('mousedown', handleMouseDown);
canvas.addEventListener('mousemove', handleMouseMove);
canvas.addEventListener('mouseup', handleMouseUp);
return function () {
canvas.removeEventListener('mousedown', handleMouseDown);
canvas.removeEventListener('mousemove', handleMouseMove);
canvas.removeEventListener('mouseup', handleMouseUp);
};
}, [pose, dragging]);
return (React.createElement("canvas", { ref: canvasRef, width: width, height: height, style: styles }));
};
exports.PoseEditor = PoseEditor;
//# sourceMappingURL=openpose-editor.cjs.js.map