{"version":3,"file":"Protractor-Bsrkny9y.cjs","sources":["../app/components/protractor/Protractor.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useMemo, useRef, useState } from \"react\";\nimport RotateHandle from \"../ui/RotateHandle\";\nimport { useWindowStore } from \"../windows/windowStore\";\n\ntype ProtractorProps = {\n  windowId?: string;\n  radiusPx?: number;\n};\n\nexport default function Protractor({\n  windowId,\n  radiusPx = 300,\n}: ProtractorProps) {\n  const containerRef = useRef<HTMLDivElement | null>(null);\n  // Use ratio-based geometry derived from the given radius\n  const R = radiusPx;\n  const margin = Math.max(8, R * 0.03);\n  const bodyThickness = Math.max(6, R * 0.033);\n  // Standard-like tick proportions: major:medium:minor ≈ 1.0 : 0.6 : 0.35\n  const majorTickLength = Math.max(12, R * 0.1);\n  const mediumTickLength = Math.max(8, majorTickLength * 0.6);\n  const minorTickLength = Math.max(5, majorTickLength * 0.35);\n  const labelPaddingOuter = Math.max(6, R * 0.025);\n  const labelRadius = R - majorTickLength - labelPaddingOuter;\n  const strokeMajor = Math.max(1.25, R * 0.0045);\n  const strokeMedium = Math.max(0.9, R * 0.003);\n  const strokeMinor = Math.max(0.6, R * 0.002);\n  const labelFontSize = Math.max(9, R * 0.035);\n\n  const [size, setSize] = useState({\n    width: R * 2 + margin * 2,\n    height: R + margin + bodyThickness,\n  });\n  const rotationDeg = useWindowStore((s) =>\n    windowId ? s.windows[windowId]?.rotationDeg ?? 0 : 0\n  );\n  const updateRotation = useWindowStore((s) => s.updateRotation);\n\n  useEffect(() => {\n    const el = containerRef.current;\n    if (!el) return;\n    const obs = new ResizeObserver((entries) => {\n      const cr = entries[0]?.contentRect;\n      if (!cr) return;\n      setSize((s) => ({\n        width: Math.max(cr.width, R * 2 + margin * 2),\n        height: s.height,\n      }));\n    });\n    obs.observe(el);\n    return () => obs.disconnect();\n  }, [R, margin]);\n\n  const ticks = useMemo(() => {\n    const arr: { angle: number; kind: \"major\" | \"medium\" | \"minor\" }[] = [];\n    for (let deg = 0; deg <= 180; deg += 1) {\n      const kind =\n        deg % 10 === 0 ? \"major\" : deg % 5 === 0 ? \"medium\" : \"minor\";\n      arr.push({ angle: deg, kind });\n    }\n    return arr;\n  }, []);\n\n  const cx = R + margin;\n  const cy = R + margin;\n\n  return (\n    <div\n      ref={containerRef}\n      className=\"relative h-full w-full select-none text-foreground\"\n      style={{ background: \"transparent\" }}\n      aria-label=\"Protractor\"\n    >\n      {windowId && (\n        <RotateHandle\n          className=\"no-drag absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 h-6 w-6 rounded-full bg-card/70 border border-border shadow\"\n          title=\"Rotate\"\n          initialDeg={rotationDeg}\n          getCenter={() => {\n            const root = containerRef.current;\n            if (!root) return null;\n            const rect = root.getBoundingClientRect();\n            return {\n              x: rect.left + rect.width / 2,\n              y: rect.top + rect.height / 2,\n            };\n          }}\n          onChange={(deg) => updateRotation(windowId, deg)}\n        />\n      )}\n      <svg\n        width={size.width}\n        height={size.height}\n        role=\"img\"\n        aria-label=\"Protractor graphic\"\n        style={{ display: \"block\" }}\n      >\n        <g shapeRendering=\"geometricPrecision\">\n          <path\n            d={`M ${cx - R} ${cy} A ${R} ${R} 0 0 1 ${cx + R} ${cy} L ${\n              cx + R\n            } ${cy + bodyThickness} L ${cx - R} ${cy + bodyThickness} Z`}\n            fill=\"rgba(255,255,255,0.05)\"\n            stroke=\"currentColor\"\n            strokeOpacity={0.6}\n            strokeWidth={Math.max(0.5, R * 0.0015)}\n          />\n          {/* Tick marks on the rim: 1° (minor), 5° (medium), 10° (major) */}\n          {ticks.map(({ angle, kind }) => {\n            const rad = (angle * Math.PI) / 180;\n            const len =\n              kind === \"major\"\n                ? majorTickLength\n                : kind === \"medium\"\n                ? mediumTickLength\n                : minorTickLength;\n            const x1 = cx + Math.cos(Math.PI - rad) * (R - len);\n            const y1 = cy - Math.sin(rad) * (R - len);\n            const x2 = cx + Math.cos(Math.PI - rad) * R;\n            const y2 = cy - Math.sin(rad) * R;\n            return (\n              <line\n                key={angle}\n                x1={x1}\n                y1={y1}\n                x2={x2}\n                y2={y2}\n                stroke=\"currentColor\"\n                strokeOpacity={0.8}\n                strokeWidth={\n                  kind === \"major\"\n                    ? strokeMajor\n                    : kind === \"medium\"\n                    ? strokeMedium\n                    : strokeMinor\n                }\n              />\n            );\n          })}\n          {/* Major angle labels: outer 0→180, inner 180→0 */}\n          {ticks\n            .filter((t) => t.kind === \"major\")\n            .map(({ angle }) => {\n              const rad = (angle * Math.PI) / 180;\n              const outerR = labelRadius;\n              const innerR =\n                labelRadius - Math.max(labelFontSize * 1.15, R * 0.055);\n              const outerX = cx + Math.cos(Math.PI - rad) * outerR;\n              const outerY = cy - Math.sin(rad) * outerR;\n              const innerX = cx + Math.cos(Math.PI - rad) * innerR;\n              const innerY = cy - Math.sin(rad) * innerR;\n              const innerValue = 180 - angle;\n              return (\n                <g key={`lbl-${angle}`}>\n                  <text\n                    x={outerX}\n                    y={outerY}\n                    fontSize={labelFontSize}\n                    textAnchor=\"middle\"\n                    dominantBaseline=\"central\"\n                    fill=\"currentColor\"\n                    fillOpacity={0.85}\n                  >\n                    {angle}\n                  </text>\n                  <text\n                    x={innerX}\n                    y={innerY}\n                    fontSize={labelFontSize}\n                    textAnchor=\"middle\"\n                    dominantBaseline=\"central\"\n                    fill=\"currentColor\"\n                    fillOpacity={0.65}\n                  >\n                    {innerValue}\n                  </text>\n                </g>\n              );\n            })}\n\n          {/* Inner arc to mirror common protractor guides */}\n          <path\n            d={`M ${cx - (R - majorTickLength)} ${cy} A ${\n              R - majorTickLength\n            } ${R - majorTickLength} 0 0 1 ${cx + (R - majorTickLength)} ${cy}`}\n            fill=\"none\"\n            stroke=\"currentColor\"\n            strokeOpacity={0.35}\n            strokeWidth={Math.max(0.5, R * 0.001)}\n          />\n\n          {/* Baseline (diameter) */}\n          <line\n            x1={cx - R}\n            y1={cy}\n            x2={cx + R}\n            y2={cy}\n            stroke=\"currentColor\"\n            strokeOpacity={0.5}\n            strokeWidth={Math.max(1, R * 0.002)}\n          />\n\n          {/* Interior radial guide lines at each 10° */}\n          {ticks\n            .filter((t) => t.kind === \"major\")\n            .map(({ angle }) => {\n              const rad = (angle * Math.PI) / 180;\n              const xEnd = cx + Math.cos(Math.PI - rad) * (R - majorTickLength);\n              const yEnd = cy - Math.sin(rad) * (R - majorTickLength);\n              const isAxis = angle === 0 || angle === 90 || angle === 180;\n              return (\n                <line\n                  key={`rad-${angle}`}\n                  x1={cx}\n                  y1={cy}\n                  x2={xEnd}\n                  y2={yEnd}\n                  stroke=\"currentColor\"\n                  strokeOpacity={isAxis ? 0.5 : 0.25}\n                  strokeWidth={\n                    isAxis ? Math.max(1, R * 0.002) : Math.max(0.5, R * 0.001)\n                  }\n                />\n              );\n            })}\n\n          {/* Fine interior lines at each degree for a realistic grid */}\n          {ticks\n            .filter((t) => t.kind !== \"major\")\n            .map(({ angle }) => {\n              const rad = (angle * Math.PI) / 180;\n              const xEnd = cx + Math.cos(Math.PI - rad) * (R - minorTickLength);\n              const yEnd = cy - Math.sin(rad) * (R - minorTickLength);\n              return (\n                <line\n                  key={`rad-min-${angle}`}\n                  x1={cx}\n                  y1={cy}\n                  x2={xEnd}\n                  y2={yEnd}\n                  stroke=\"currentColor\"\n                  strokeOpacity={0.15}\n                  strokeWidth={Math.max(0.5, R * 0.0008)}\n                />\n              );\n            })}\n\n          {/* Center hole */}\n          <circle\n            cx={cx}\n            cy={cy}\n            r={Math.max(2, R * 0.02)}\n            fill=\"none\"\n            stroke=\"currentColor\"\n            strokeOpacity={0.6}\n            strokeWidth={Math.max(0.75, R * 0.0015)}\n          />\n        </g>\n      </svg>\n    </div>\n  );\n}\n"],"names":["Protractor","windowId","radiusPx","containerRef","useRef","R","margin","bodyThickness","majorTickLength","mediumTickLength","minorTickLength","labelPaddingOuter","labelRadius","strokeMajor","strokeMedium","strokeMinor","labelFontSize","size","setSize","useState","rotationDeg","useWindowStore","s","updateRotation","useEffect","el","obs","entries","cr","ticks","useMemo","arr","deg","kind","cx","cy","jsxs","jsx","RotateHandle","root","rect","angle","rad","len","x1","y1","x2","y2","t","outerR","innerR","outerX","outerY","innerX","innerY","innerValue","xEnd","yEnd","isAxis"],"mappings":"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"}