Skip to content

fix(select): support circle resize on globe and web-mercator projections#846

Open
Remenby31 wants to merge 2 commits intoJamesLMilner:mainfrom
Remenby31:fix/globe-circle-resize
Open

fix(select): support circle resize on globe and web-mercator projections#846
Remenby31 wants to merge 2 commits intoJamesLMilner:mainfrom
Remenby31:fix/globe-circle-resize

Conversation

@Remenby31
Copy link
Copy Markdown

@Remenby31 Remenby31 commented Mar 25, 2026

Problem

Circle features created with TerraDrawCircleMode are distorted into ovals when resized via TerraDrawSelectMode with resizable: "center".

This happens because the resize behavior (DragCoordinateResizeBehavior) treats circles as generic polygons and applies bbox-based coordinate scaling. Since a circle is a polygon with 64 evenly-spaced vertices, scaling X and Y independently — especially in Web Mercator where latitude distortion is non-linear — deforms the circle into an ellipse.

On globe projection, resizing throws an error entirely:

Error: Globe is currently unsupported projection for resizable

This is tracked in #436.

Solution

When a resizable feature is detected as a circle (has properties.mode === "circle" and properties.radiusKilometers), bypass the generic bbox scaling and instead:

  1. Capture the circle center at drag start (via centroid of the polygon), stored in a private field circleResizeCenter
  2. On each drag event, compute the new radius as the haversine distance from the stored center to the cursor position
  3. Regenerate the circle using the existing circle() (globe) or circleWebMercator() (web-mercator) functions with the new radius
  4. Update the radiusKilometers property on the feature to keep it in sync
  5. Reset the stored center on drag end

The center is captured once at drag start rather than recomputed each frame to prevent centroid drift — the arithmetic mean of polygon vertices is not exactly the geodesic center, and progressive recomputation causes the circle to slowly migrate.

Changes

packages/terra-draw/src/modes/select/select.mode.ts — 1 file, ~100 lines added

  • Added circleResizeCenter: Position | null field to TerraDrawSelectMode
  • In onDragStart: capture center when starting a circle resize
  • In onDrag: detect circles and call resizeCircle() instead of bbox scaling — for both globe and web-mercator projections
  • In onDragEnd: reset stored center
  • Added private method resizeCircle() that regenerates the geodesic/web-mercator circle from center + haversine distance to cursor

Testing

Tested manually with MapLibre GL JS v5.21 + globe projection:

  • Draw a circle → Select → Resize by dragging a selection point → circle stays round
  • Center remains fixed during resize (no drift)
  • radiusKilometers property updates correctly
  • Works on both globe and flat (web-mercator) projections
  • Existing rectangle/polygon resize is not affected
  • Circle drag/move still works as before

@Remenby31 Remenby31 force-pushed the fix/globe-circle-resize branch 2 times, most recently from b28ae6a to 837a606 Compare March 25, 2026 10:50
Circle features were distorted into ovals when resized because the
select mode used generic bbox-based coordinate scaling. On globe
projection, resizing threw an error entirely.

This fix detects circle features (via the `radiusKilometers` property)
and regenerates the circle from its center + new radius instead of
scaling individual coordinates. The center is captured once at drag
start to prevent centroid drift during progressive updates.

Works for both `globe` (geodesic circle) and `web-mercator` projections.

Closes JamesLMilner#436
@Remenby31 Remenby31 force-pushed the fix/globe-circle-resize branch from 837a606 to 8e4fc98 Compare March 25, 2026 10:52
@Remenby31 Remenby31 marked this pull request as ready for review March 25, 2026 10:59
@JamesLMilner
Copy link
Copy Markdown
Owner

Thanks for this, I appreciate your thought and input here on the topic and your interest more broadly in the project.

I am just on my phone and I need to write this up on the issue but I've wanted to avoid mode specific logic in TerraDrawSelectMode as it is a powerful property that the mode is agnostic to what it is interacting with (I.e. it doesn't know about other modes you may or may not be using). I'll provide more detailed response at a later date when I have more free time to dig into this more thoroughly.

Just speaking off the cuff, I feel like we might be able to fix globe projection resizing to respect geodesic resizing for circles without knowledge of circle mode. Another option might be to allow custom functions that allow people to modify the geometry/properties as they wish. Again though I'll think about this all when I get a moment!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants