146 lines
3.5 KiB
TypeScript
146 lines
3.5 KiB
TypeScript
"use client";
|
|
|
|
import { JSX } from "react";
|
|
|
|
interface RulerProps {
|
|
orientation: "horizontal" | "vertical";
|
|
length: number; // mm 단위
|
|
offset?: number; // 스크롤 오프셋 (px)
|
|
}
|
|
|
|
export function Ruler({ orientation, length, offset = 0 }: RulerProps) {
|
|
// mm를 px로 변환 (1mm = 3.7795px, 96dpi 기준)
|
|
const mmToPx = (mm: number) => mm * 3.7795;
|
|
|
|
const lengthPx = mmToPx(length);
|
|
const isHorizontal = orientation === "horizontal";
|
|
|
|
// 눈금 생성 (10mm 단위 큰 눈금, 5mm 단위 중간 눈금, 1mm 단위 작은 눈금)
|
|
const renderTicks = () => {
|
|
const ticks: JSX.Element[] = [];
|
|
const maxMm = length;
|
|
|
|
for (let mm = 0; mm <= maxMm; mm++) {
|
|
const px = mmToPx(mm);
|
|
|
|
// 10mm 단위 큰 눈금
|
|
if (mm % 10 === 0) {
|
|
ticks.push(
|
|
<div
|
|
key={`major-${mm}`}
|
|
className="absolute bg-gray-700"
|
|
style={
|
|
isHorizontal
|
|
? {
|
|
left: `${px}px`,
|
|
top: "0",
|
|
width: "1px",
|
|
height: "12px",
|
|
}
|
|
: {
|
|
top: `${px}px`,
|
|
left: "0",
|
|
height: "1px",
|
|
width: "12px",
|
|
}
|
|
}
|
|
/>,
|
|
);
|
|
|
|
// 숫자 표시 (10mm 단위)
|
|
if (mm > 0) {
|
|
ticks.push(
|
|
<div
|
|
key={`label-${mm}`}
|
|
className="absolute text-[9px] text-gray-600"
|
|
style={
|
|
isHorizontal
|
|
? {
|
|
left: `${px + 2}px`,
|
|
top: "0px",
|
|
}
|
|
: {
|
|
top: `${px + 2}px`,
|
|
left: "0px",
|
|
writingMode: "vertical-lr",
|
|
}
|
|
}
|
|
>
|
|
{mm}
|
|
</div>,
|
|
);
|
|
}
|
|
}
|
|
// 5mm 단위 중간 눈금
|
|
else if (mm % 5 === 0) {
|
|
ticks.push(
|
|
<div
|
|
key={`medium-${mm}`}
|
|
className="absolute bg-gray-500"
|
|
style={
|
|
isHorizontal
|
|
? {
|
|
left: `${px}px`,
|
|
top: "4px",
|
|
width: "1px",
|
|
height: "8px",
|
|
}
|
|
: {
|
|
top: `${px}px`,
|
|
left: "4px",
|
|
height: "1px",
|
|
width: "8px",
|
|
}
|
|
}
|
|
/>,
|
|
);
|
|
}
|
|
// 1mm 단위 작은 눈금
|
|
else {
|
|
ticks.push(
|
|
<div
|
|
key={`minor-${mm}`}
|
|
className="absolute bg-gray-400"
|
|
style={
|
|
isHorizontal
|
|
? {
|
|
left: `${px}px`,
|
|
top: "8px",
|
|
width: "1px",
|
|
height: "4px",
|
|
}
|
|
: {
|
|
top: `${px}px`,
|
|
left: "8px",
|
|
height: "1px",
|
|
width: "4px",
|
|
}
|
|
}
|
|
/>,
|
|
);
|
|
}
|
|
}
|
|
|
|
return ticks;
|
|
};
|
|
|
|
return (
|
|
<div
|
|
className="relative bg-gray-100 select-none"
|
|
style={
|
|
isHorizontal
|
|
? {
|
|
width: `${lengthPx}px`,
|
|
height: "20px",
|
|
}
|
|
: {
|
|
width: "20px",
|
|
height: `${lengthPx}px`,
|
|
}
|
|
}
|
|
>
|
|
{renderTicks()}
|
|
</div>
|
|
);
|
|
}
|