Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 77 additions & 2 deletions src/components/EditPlacementOverlay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,11 @@ export const EditPlacementOverlay = ({
dragEnd: { x: number; y: number }
edit_event_id: string
} | null>(null)
const [rotationState, setRotationState] = useState<{
pcb_component_id: string
edit_event_id: string
original_rotation: number
} | null>(null)
const isPcbComponentActive = activePcbComponentId !== null
const in_edit_mode = useGlobalStore((s) => s.in_edit_mode)
const in_move_footprint_mode = useGlobalStore((s) => s.in_move_footprint_mode)
Expand Down Expand Up @@ -115,6 +120,27 @@ export const EditPlacementOverlay = ({
}
}}
onMouseMove={(e) => {
if (rotationState) {
const rect = e.currentTarget.getBoundingClientRect()
const x = e.clientX - rect.left
const y = e.clientY - rect.top
if (Number.isNaN(x) || Number.isNaN(y)) return
const rwMousePoint = applyToPoint(inverse(transform!), { x, y })
const component = soup.find(
(c) =>
c.type === "pcb_component" &&
c.pcb_component_id === rotationState.pcb_component_id,
) as PcbComponent | undefined
if (!component) return
const angle = Math.atan2(
rwMousePoint.y - component.center.y,
rwMousePoint.x - component.center.x,
)
onModifyEditEvent({
edit_event_id: rotationState.edit_event_id,
new_rotation: rotationState.original_rotation + angle,
} as any)
Comment on lines +135 to +142
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The current rotation implementation causes an abrupt snap when rotation begins because it doesn't account for the initial angle between the mouse and component center.

To create a smoother rotation experience:

  1. Store the initial mouse-to-component angle when rotation starts:
onMouseDown={(e) => {
  // existing code...
  const initialAngle = Math.atan2(
    mouseY - component.center.y,
    mouseX - component.center.x
  );
  setRotationState({
    pcb_component_id: activePcbComponentId!,
    edit_event_id,
    original_rotation,
    initialMouseAngle: initialAngle
  });
}
  1. Then calculate rotation based on the difference between current and initial angles:
onMouseMove={(e) => {
  // existing code...
  const currentAngle = Math.atan2(
    rwMousePoint.y - component.center.y,
    rwMousePoint.x - component.center.x
  );
  const angleDelta = currentAngle - rotationState.initialMouseAngle;
  onModifyEditEvent({
    edit_event_id: rotationState.edit_event_id,
    new_rotation: rotationState.original_rotation + angleDelta,
  });
}

This approach preserves the component's initial orientation and allows for more intuitive rotation control.

Spotted by Graphite Agent

Fix in Graphite


Is this helpful? React 👍 or 👎 to let us know.

}
if (!activePcbComponentId || !dragState) return
const rect = e.currentTarget.getBoundingClientRect()
const x = e.clientX - rect.left
Expand All @@ -140,6 +166,13 @@ export const EditPlacementOverlay = ({
})
}}
onMouseUp={(e) => {
if (rotationState) {
onModifyEditEvent({
edit_event_id: rotationState.edit_event_id,
in_progress: false,
})
setRotationState(null)
}
if (!activePcbComponentId) return
setActivePcbComponent(null)
setIsMovingComponent(false)
Expand Down Expand Up @@ -171,14 +204,56 @@ export const EditPlacementOverlay = ({
top: projectedCenter.y,
width: e.width * transform.a + 20,
height: e.height * transform.a + 20,
transform: "translate(-50%, -50%)",
transform: `translate(-50%, -50%) rotate(${
(e as any).rotation ?? 0
}rad)`,
background:
isPcbComponentActive &&
activePcbComponentId === e.pcb_component_id
? "rgba(255, 0, 0, 0.2)"
: "",
}}
/>
>
{isPcbComponentActive &&
activePcbComponentId === e.pcb_component_id && (
<div
style={{
position: "absolute",
top: 0,
right: 0,
width: 10,
height: 10,
background: "gray",
borderRadius: "50%",
cursor: "pointer",
pointerEvents: "all",
}}
onMouseDown={(e) => {
e.stopPropagation()
cancelPanDrag()
const edit_event_id = Math.random().toString()
const component = soup.find(
(c) =>
c.type === "pcb_component" &&
c.pcb_component_id === activePcbComponentId,
) as PcbComponent | undefined
const original_rotation = (component as any)?.rotation ?? 0
setRotationState({
pcb_component_id: activePcbComponentId!,
edit_event_id,
original_rotation,
})
onCreateEditEvent({
edit_event_id,
edit_event_type: "edit_pcb_component_rotation",
pcb_component_id: activePcbComponentId!,
original_rotation,
new_rotation: original_rotation,
} as any)
}}
/>
)}
</div>
)
})}
</div>
Expand Down