[fix] polygon bounds (#2378)

This PR fixes the bounds calculation for polygons. It solves the bug
reported here: https://github.com/tldraw/tldraw/issues/2309 . Note that
this may produce visual changes for hexagons and other shapes.

![Kapture 2023-12-24 at 10 35
13](https://github.com/tldraw/tldraw/assets/23072548/773e89ee-f8c3-4875-b942-30860b1cdf22)

### Change Type

- [x] `patch` — Bug fix

### Test Plan

1. Create a hexagon shape with a label.
2. The label should be correctly centered.

### Release Notes

- Fixed a bug with the bounds calculation for polygons.
This commit is contained in:
Steve Ruiz 2023-12-24 11:53:15 +00:00 committed by GitHub
parent e5232e3513
commit 3f90fbf5b0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 37 additions and 4 deletions

View file

@ -314,8 +314,11 @@ export function getPolygonVertices(width: number, height: number, sides: number)
const cx = width / 2 const cx = width / 2
const cy = height / 2 const cy = height / 2
const pointsOnPerimeter: Vec2d[] = [] const pointsOnPerimeter: Vec2d[] = []
let minX = Infinity let minX = Infinity
let maxX = -Infinity
let minY = Infinity let minY = Infinity
let maxY = -Infinity
for (let i = 0; i < sides; i++) { for (let i = 0; i < sides; i++) {
const step = PI2 / sides const step = PI2 / sides
const t = -TAU + i * step const t = -TAU + i * step
@ -323,14 +326,25 @@ export function getPolygonVertices(width: number, height: number, sides: number)
const y = cy + cy * Math.sin(t) const y = cy + cy * Math.sin(t)
if (x < minX) minX = x if (x < minX) minX = x
if (y < minY) minY = y if (y < minY) minY = y
if (x > maxX) maxX = x
if (y > maxY) maxY = y
pointsOnPerimeter.push(new Vec2d(x, y)) pointsOnPerimeter.push(new Vec2d(x, y))
} }
if (minX !== 0 || minY !== 0) { // Bounds of calculated points
const w = maxX - minX
const h = maxY - minY
// Difference between input bounds and calculated bounds
const dx = width - w
const dy = height - h
// If there's a difference, scale the points to the input bounds
if (dx !== 0 || dy !== 0) {
for (let i = 0; i < pointsOnPerimeter.length; i++) { for (let i = 0; i < pointsOnPerimeter.length; i++) {
const pt = pointsOnPerimeter[i] const pt = pointsOnPerimeter[i]
pt.x -= minX pt.x = ((pt.x - minX) / w) * width
pt.y -= minY pt.y = ((pt.y - minY) / h) * height
} }
} }

View file

@ -20,6 +20,7 @@ import {
TLOnResizeHandler, TLOnResizeHandler,
TLShapeUtilCanvasSvgDef, TLShapeUtilCanvasSvgDef,
Vec2d, Vec2d,
VecLike,
geoShapeMigrations, geoShapeMigrations,
geoShapeProps, geoShapeProps,
getDefaultColorTheme, getDefaultColorTheme,
@ -321,11 +322,13 @@ export class GeoShapeUtil extends BaseBoxShapeUtil<TLGeoShape> {
const labelSize = getLabelSize(this.editor, shape) const labelSize = getLabelSize(this.editor, shape)
const labelWidth = Math.min(w, Math.max(labelSize.w, Math.min(32, Math.max(1, w - 8)))) const labelWidth = Math.min(w, Math.max(labelSize.w, Math.min(32, Math.max(1, w - 8))))
const labelHeight = Math.min(h, Math.max(labelSize.h, Math.min(32, Math.max(1, w - 8)))) const labelHeight = Math.min(h, Math.max(labelSize.h, Math.min(32, Math.max(1, w - 8)))) // not sure if bug
const lines = getLines(shape.props, strokeWidth) const lines = getLines(shape.props, strokeWidth)
const edges = lines ? lines.map((line) => new Polyline2d({ points: line })) : [] const edges = lines ? lines.map((line) => new Polyline2d({ points: line })) : []
// todo: use centroid for label position
return new Group2d({ return new Group2d({
children: [ children: [
body, body,
@ -1151,3 +1154,19 @@ function getCheckBoxLines(w: number, h: number) {
], ],
] ]
} }
/**
* Get the centroid of a regular polygon.
* @param points - The points that make up the polygon.
* @internal
*/
export function getCentroidOfRegularPolygon(points: VecLike[]) {
const len = points.length
let x = 0
let y = 0
for (let i = 0; i < len; i++) {
x += points[i].x
y += points[i].y
}
return new Vec2d(x / len, y / len)
}