@tldraw/editor 5.4.0-next.ef99ab47e5ce → 5.5.0-next.6d9e51e9f3f7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist-cjs/index.d.ts +119 -49
- package/dist-cjs/index.js +4 -1
- package/dist-cjs/index.js.map +2 -2
- package/dist-cjs/lib/TldrawEditor.js +7 -2
- package/dist-cjs/lib/TldrawEditor.js.map +2 -2
- package/dist-cjs/lib/components/MenuClickCapture.js +6 -8
- package/dist-cjs/lib/components/MenuClickCapture.js.map +2 -2
- package/dist-cjs/lib/components/default-components/CanvasOverlays.js +1 -3
- package/dist-cjs/lib/components/default-components/CanvasOverlays.js.map +2 -2
- package/dist-cjs/lib/components/default-components/DefaultErrorFallback.js +1 -1
- package/dist-cjs/lib/components/default-components/DefaultErrorFallback.js.map +1 -1
- package/dist-cjs/lib/config/TLUserPreferences.js +6 -2
- package/dist-cjs/lib/config/TLUserPreferences.js.map +2 -2
- package/dist-cjs/lib/config/createTLStore.js +1 -1
- package/dist-cjs/lib/config/createTLStore.js.map +2 -2
- package/dist-cjs/lib/constants.js +2 -0
- package/dist-cjs/lib/constants.js.map +2 -2
- package/dist-cjs/lib/editor/Editor.js +184 -296
- package/dist-cjs/lib/editor/Editor.js.map +2 -2
- package/dist-cjs/lib/editor/derivations/shapeIdsInCurrentPage.js +7 -3
- package/dist-cjs/lib/editor/derivations/shapeIdsInCurrentPage.js.map +2 -2
- package/dist-cjs/lib/editor/managers/ClickManager/ClickManager.js +3 -3
- package/dist-cjs/lib/editor/managers/ClickManager/ClickManager.js.map +2 -2
- package/dist-cjs/lib/editor/managers/CollaboratorsManager/CollaboratorsManager.js +8 -8
- package/dist-cjs/lib/editor/managers/CollaboratorsManager/CollaboratorsManager.js.map +2 -2
- package/dist-cjs/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.js +10 -6
- package/dist-cjs/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.js.map +2 -2
- package/dist-cjs/lib/editor/managers/FontManager/FontManager.js +2 -1
- package/dist-cjs/lib/editor/managers/FontManager/FontManager.js.map +2 -2
- package/dist-cjs/lib/editor/managers/InputsManager/InputsManager.js +79 -6
- package/dist-cjs/lib/editor/managers/InputsManager/InputsManager.js.map +2 -2
- package/dist-cjs/lib/editor/managers/ScribbleManager/ScribbleManager.js +7 -0
- package/dist-cjs/lib/editor/managers/ScribbleManager/ScribbleManager.js.map +2 -2
- package/dist-cjs/lib/editor/managers/SnapManager/BoundsSnaps.js +0 -2
- package/dist-cjs/lib/editor/managers/SnapManager/BoundsSnaps.js.map +2 -2
- package/dist-cjs/lib/editor/managers/TextManager/TextManager.js +1 -2
- package/dist-cjs/lib/editor/managers/TextManager/TextManager.js.map +2 -2
- package/dist-cjs/lib/editor/managers/ThemeManager/ThemeManager.js +7 -3
- package/dist-cjs/lib/editor/managers/ThemeManager/ThemeManager.js.map +2 -2
- package/dist-cjs/lib/editor/managers/TickManager/TickManager.js +6 -3
- package/dist-cjs/lib/editor/managers/TickManager/TickManager.js.map +2 -2
- package/dist-cjs/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.js +12 -1
- package/dist-cjs/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.js.map +2 -2
- package/dist-cjs/lib/editor/overlays/OverlayManager.js +3 -7
- package/dist-cjs/lib/editor/overlays/OverlayManager.js.map +2 -2
- package/dist-cjs/lib/editor/overlays/strokeShapeIndicators.js +0 -1
- package/dist-cjs/lib/editor/overlays/strokeShapeIndicators.js.map +2 -2
- package/dist-cjs/lib/editor/shapes/BaseFrameLikeShapeUtil.js +3 -1
- package/dist-cjs/lib/editor/shapes/BaseFrameLikeShapeUtil.js.map +2 -2
- package/dist-cjs/lib/editor/shapes/shared/getPerfectDashProps.js +1 -0
- package/dist-cjs/lib/editor/shapes/shared/getPerfectDashProps.js.map +2 -2
- package/dist-cjs/lib/editor/tools/BaseBoxShapeTool/children/Pointing.js +1 -1
- package/dist-cjs/lib/editor/tools/BaseBoxShapeTool/children/Pointing.js.map +2 -2
- package/dist-cjs/lib/editor/tools/StateNode.js +3 -2
- package/dist-cjs/lib/editor/tools/StateNode.js.map +2 -2
- package/dist-cjs/lib/globals/editors.js +57 -0
- package/dist-cjs/lib/globals/editors.js.map +7 -0
- package/dist-cjs/lib/globals/menus.js +9 -4
- package/dist-cjs/lib/globals/menus.js.map +2 -2
- package/dist-cjs/lib/hooks/useCanvasEvents.js +2 -0
- package/dist-cjs/lib/hooks/useCanvasEvents.js.map +2 -2
- package/dist-cjs/lib/hooks/useDocumentEvents.js +39 -9
- package/dist-cjs/lib/hooks/useDocumentEvents.js.map +2 -2
- package/dist-cjs/lib/hooks/useLocalStore.js +10 -6
- package/dist-cjs/lib/hooks/useLocalStore.js.map +2 -2
- package/dist-cjs/lib/hooks/usePassThroughWheelEvents.js +1 -0
- package/dist-cjs/lib/hooks/usePassThroughWheelEvents.js.map +2 -2
- package/dist-cjs/lib/hooks/usePeerIds.js +2 -1
- package/dist-cjs/lib/hooks/usePeerIds.js.map +2 -2
- package/dist-cjs/lib/license/LicenseManager.js +9 -2
- package/dist-cjs/lib/license/LicenseManager.js.map +2 -2
- package/dist-cjs/lib/license/LicenseProvider.js +16 -3
- package/dist-cjs/lib/license/LicenseProvider.js.map +2 -2
- package/dist-cjs/lib/license/useLicenseManagerState.js +5 -4
- package/dist-cjs/lib/license/useLicenseManagerState.js.map +2 -2
- package/dist-cjs/lib/primitives/Box.js +2 -1
- package/dist-cjs/lib/primitives/Box.js.map +2 -2
- package/dist-cjs/lib/primitives/Vec.js +4 -3
- package/dist-cjs/lib/primitives/Vec.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/Arc2d.js +1 -1
- package/dist-cjs/lib/primitives/geometry/Arc2d.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/CubicBezier2d.js +1 -1
- package/dist-cjs/lib/primitives/geometry/CubicBezier2d.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/Edge2d.js +1 -1
- package/dist-cjs/lib/primitives/geometry/Edge2d.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/Group2d.js +71 -26
- package/dist-cjs/lib/primitives/geometry/Group2d.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/Point2d.js +1 -1
- package/dist-cjs/lib/primitives/geometry/Point2d.js.map +2 -2
- package/dist-cjs/lib/primitives/utils.js +2 -1
- package/dist-cjs/lib/primitives/utils.js.map +2 -2
- package/dist-cjs/lib/utils/deepLinks.js +5 -1
- package/dist-cjs/lib/utils/deepLinks.js.map +2 -2
- package/dist-cjs/lib/utils/normalizeWheel.js +2 -0
- package/dist-cjs/lib/utils/normalizeWheel.js.map +2 -2
- package/dist-cjs/lib/utils/rotation.js +1 -9
- package/dist-cjs/lib/utils/rotation.js.map +2 -2
- package/dist-cjs/lib/utils/sync/TLLocalSyncClient.js +17 -0
- package/dist-cjs/lib/utils/sync/TLLocalSyncClient.js.map +2 -2
- package/dist-cjs/lib/utils/sync/alerts.js +1 -1
- package/dist-cjs/lib/utils/sync/alerts.js.map +1 -1
- package/dist-cjs/version.js +3 -3
- package/dist-cjs/version.js.map +1 -1
- package/dist-esm/index.d.mts +119 -49
- package/dist-esm/index.mjs +9 -2
- package/dist-esm/index.mjs.map +2 -2
- package/dist-esm/lib/TldrawEditor.mjs +9 -4
- package/dist-esm/lib/TldrawEditor.mjs.map +2 -2
- package/dist-esm/lib/components/MenuClickCapture.mjs +6 -8
- package/dist-esm/lib/components/MenuClickCapture.mjs.map +2 -2
- package/dist-esm/lib/components/default-components/CanvasOverlays.mjs +1 -3
- package/dist-esm/lib/components/default-components/CanvasOverlays.mjs.map +2 -2
- package/dist-esm/lib/components/default-components/DefaultErrorFallback.mjs +1 -1
- package/dist-esm/lib/components/default-components/DefaultErrorFallback.mjs.map +1 -1
- package/dist-esm/lib/config/TLUserPreferences.mjs +6 -2
- package/dist-esm/lib/config/TLUserPreferences.mjs.map +2 -2
- package/dist-esm/lib/config/createTLStore.mjs +1 -1
- package/dist-esm/lib/config/createTLStore.mjs.map +2 -2
- package/dist-esm/lib/constants.mjs +2 -0
- package/dist-esm/lib/constants.mjs.map +2 -2
- package/dist-esm/lib/editor/Editor.mjs +193 -297
- package/dist-esm/lib/editor/Editor.mjs.map +2 -2
- package/dist-esm/lib/editor/derivations/shapeIdsInCurrentPage.mjs +7 -3
- package/dist-esm/lib/editor/derivations/shapeIdsInCurrentPage.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/ClickManager/ClickManager.mjs +3 -3
- package/dist-esm/lib/editor/managers/ClickManager/ClickManager.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/CollaboratorsManager/CollaboratorsManager.mjs +9 -9
- package/dist-esm/lib/editor/managers/CollaboratorsManager/CollaboratorsManager.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.mjs +10 -6
- package/dist-esm/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/FontManager/FontManager.mjs +2 -1
- package/dist-esm/lib/editor/managers/FontManager/FontManager.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/InputsManager/InputsManager.mjs +81 -8
- package/dist-esm/lib/editor/managers/InputsManager/InputsManager.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/ScribbleManager/ScribbleManager.mjs +7 -0
- package/dist-esm/lib/editor/managers/ScribbleManager/ScribbleManager.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/SnapManager/BoundsSnaps.mjs +0 -2
- package/dist-esm/lib/editor/managers/SnapManager/BoundsSnaps.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/TextManager/TextManager.mjs +2 -3
- package/dist-esm/lib/editor/managers/TextManager/TextManager.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/ThemeManager/ThemeManager.mjs +7 -3
- package/dist-esm/lib/editor/managers/ThemeManager/ThemeManager.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/TickManager/TickManager.mjs +6 -3
- package/dist-esm/lib/editor/managers/TickManager/TickManager.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.mjs +12 -1
- package/dist-esm/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.mjs.map +2 -2
- package/dist-esm/lib/editor/overlays/OverlayManager.mjs +3 -7
- package/dist-esm/lib/editor/overlays/OverlayManager.mjs.map +2 -2
- package/dist-esm/lib/editor/overlays/strokeShapeIndicators.mjs +0 -1
- package/dist-esm/lib/editor/overlays/strokeShapeIndicators.mjs.map +2 -2
- package/dist-esm/lib/editor/shapes/BaseFrameLikeShapeUtil.mjs +3 -1
- package/dist-esm/lib/editor/shapes/BaseFrameLikeShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/editor/shapes/shared/getPerfectDashProps.mjs +1 -0
- package/dist-esm/lib/editor/shapes/shared/getPerfectDashProps.mjs.map +2 -2
- package/dist-esm/lib/editor/tools/BaseBoxShapeTool/children/Pointing.mjs +1 -1
- package/dist-esm/lib/editor/tools/BaseBoxShapeTool/children/Pointing.mjs.map +2 -2
- package/dist-esm/lib/editor/tools/StateNode.mjs +3 -2
- package/dist-esm/lib/editor/tools/StateNode.mjs.map +2 -2
- package/dist-esm/lib/globals/editors.mjs +37 -0
- package/dist-esm/lib/globals/editors.mjs.map +7 -0
- package/dist-esm/lib/globals/menus.mjs +9 -4
- package/dist-esm/lib/globals/menus.mjs.map +2 -2
- package/dist-esm/lib/hooks/useCanvasEvents.mjs +2 -0
- package/dist-esm/lib/hooks/useCanvasEvents.mjs.map +2 -2
- package/dist-esm/lib/hooks/useDocumentEvents.mjs +40 -10
- package/dist-esm/lib/hooks/useDocumentEvents.mjs.map +2 -2
- package/dist-esm/lib/hooks/useLocalStore.mjs +11 -7
- package/dist-esm/lib/hooks/useLocalStore.mjs.map +2 -2
- package/dist-esm/lib/hooks/usePassThroughWheelEvents.mjs +1 -0
- package/dist-esm/lib/hooks/usePassThroughWheelEvents.mjs.map +2 -2
- package/dist-esm/lib/hooks/usePeerIds.mjs +2 -1
- package/dist-esm/lib/hooks/usePeerIds.mjs.map +2 -2
- package/dist-esm/lib/license/LicenseManager.mjs +9 -2
- package/dist-esm/lib/license/LicenseManager.mjs.map +2 -2
- package/dist-esm/lib/license/LicenseProvider.mjs +16 -3
- package/dist-esm/lib/license/LicenseProvider.mjs.map +2 -2
- package/dist-esm/lib/license/useLicenseManagerState.mjs +5 -4
- package/dist-esm/lib/license/useLicenseManagerState.mjs.map +2 -2
- package/dist-esm/lib/primitives/Box.mjs +2 -1
- package/dist-esm/lib/primitives/Box.mjs.map +2 -2
- package/dist-esm/lib/primitives/Vec.mjs +4 -3
- package/dist-esm/lib/primitives/Vec.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/Arc2d.mjs +1 -1
- package/dist-esm/lib/primitives/geometry/Arc2d.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/CubicBezier2d.mjs +1 -1
- package/dist-esm/lib/primitives/geometry/CubicBezier2d.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/Edge2d.mjs +1 -1
- package/dist-esm/lib/primitives/geometry/Edge2d.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/Group2d.mjs +75 -27
- package/dist-esm/lib/primitives/geometry/Group2d.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/Point2d.mjs +1 -1
- package/dist-esm/lib/primitives/geometry/Point2d.mjs.map +2 -2
- package/dist-esm/lib/primitives/utils.mjs +2 -1
- package/dist-esm/lib/primitives/utils.mjs.map +2 -2
- package/dist-esm/lib/utils/deepLinks.mjs +5 -1
- package/dist-esm/lib/utils/deepLinks.mjs.map +2 -2
- package/dist-esm/lib/utils/normalizeWheel.mjs +2 -0
- package/dist-esm/lib/utils/normalizeWheel.mjs.map +2 -2
- package/dist-esm/lib/utils/rotation.mjs +1 -9
- package/dist-esm/lib/utils/rotation.mjs.map +2 -2
- package/dist-esm/lib/utils/sync/TLLocalSyncClient.mjs +17 -0
- package/dist-esm/lib/utils/sync/TLLocalSyncClient.mjs.map +2 -2
- package/dist-esm/lib/utils/sync/alerts.mjs +1 -1
- package/dist-esm/lib/utils/sync/alerts.mjs.map +1 -1
- package/dist-esm/version.mjs +3 -3
- package/dist-esm/version.mjs.map +1 -1
- package/package.json +13 -7
- package/src/index.ts +6 -1
- package/src/lib/TldrawEditor.tsx +16 -4
- package/src/lib/components/MenuClickCapture.tsx +19 -18
- package/src/lib/components/default-components/CanvasOverlays.tsx +1 -3
- package/src/lib/components/default-components/DefaultErrorFallback.tsx +1 -1
- package/src/lib/config/TLUserPreferences.test.ts +18 -1
- package/src/lib/config/TLUserPreferences.ts +8 -4
- package/src/lib/config/createTLStore.ts +1 -1
- package/src/lib/constants.ts +8 -0
- package/src/lib/editor/Editor.ts +273 -386
- package/src/lib/editor/derivations/shapeIdsInCurrentPage.ts +7 -3
- package/src/lib/editor/managers/ClickManager/ClickManager.ts +5 -3
- package/src/lib/editor/managers/CollaboratorsManager/CollaboratorsManager.ts +9 -9
- package/src/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.test.ts +35 -4
- package/src/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.ts +13 -7
- package/src/lib/editor/managers/FontManager/FontManager.ts +2 -1
- package/src/lib/editor/managers/InputsManager/InputsManager.test.ts +199 -3
- package/src/lib/editor/managers/InputsManager/InputsManager.ts +128 -9
- package/src/lib/editor/managers/ScribbleManager/ScribbleManager.ts +12 -1
- package/src/lib/editor/managers/SnapManager/BoundsSnaps.ts +0 -2
- package/src/lib/editor/managers/TextManager/TextManager.ts +2 -6
- package/src/lib/editor/managers/ThemeManager/ThemeManager.test.ts +53 -0
- package/src/lib/editor/managers/ThemeManager/ThemeManager.ts +9 -3
- package/src/lib/editor/managers/TickManager/TickManager.test.ts +13 -0
- package/src/lib/editor/managers/TickManager/TickManager.ts +9 -3
- package/src/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.test.ts +64 -3
- package/src/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.ts +18 -1
- package/src/lib/editor/overlays/OverlayManager.ts +3 -7
- package/src/lib/editor/overlays/strokeShapeIndicators.ts +0 -1
- package/src/lib/editor/shapes/BaseFrameLikeShapeUtil.tsx +5 -1
- package/src/lib/editor/shapes/shared/getPerfectDashProps.ts +3 -0
- package/src/lib/editor/tools/BaseBoxShapeTool/children/Pointing.ts +4 -1
- package/src/lib/editor/tools/StateNode.test.ts +64 -0
- package/src/lib/editor/tools/StateNode.ts +12 -2
- package/src/lib/globals/editors.test.ts +76 -0
- package/src/lib/globals/editors.ts +53 -0
- package/src/lib/globals/menus.test.ts +33 -0
- package/src/lib/globals/menus.ts +11 -4
- package/src/lib/hooks/useCanvasEvents.ts +2 -0
- package/src/lib/hooks/useDocumentEvents.ts +60 -16
- package/src/lib/hooks/useLocalStore.ts +16 -8
- package/src/lib/hooks/usePassThroughWheelEvents.ts +3 -0
- package/src/lib/hooks/usePeerIds.ts +2 -1
- package/src/lib/license/LicenseManager.test.ts +160 -0
- package/src/lib/license/LicenseManager.ts +13 -4
- package/src/lib/license/LicenseProvider.tsx +24 -3
- package/src/lib/license/useLicenseManagerState.ts +8 -6
- package/src/lib/primitives/Box.test.ts +9 -1
- package/src/lib/primitives/Box.ts +3 -1
- package/src/lib/primitives/Vec.test.ts +10 -0
- package/src/lib/primitives/Vec.ts +4 -4
- package/src/lib/primitives/geometry/Arc2d.test.ts +235 -3
- package/src/lib/primitives/geometry/Arc2d.ts +1 -1
- package/src/lib/primitives/geometry/CubicBezier2d.test.ts +186 -3
- package/src/lib/primitives/geometry/CubicBezier2d.ts +1 -1
- package/src/lib/primitives/geometry/CubicSpline2d.test.ts +160 -3
- package/src/lib/primitives/geometry/Edge2d.test.ts +21 -3
- package/src/lib/primitives/geometry/Edge2d.ts +1 -1
- package/src/lib/primitives/geometry/Ellipse2d.test.ts +243 -3
- package/src/lib/primitives/geometry/Geometry2d.test.ts +553 -1
- package/src/lib/primitives/geometry/Group2d.test.ts +419 -3
- package/src/lib/primitives/geometry/Group2d.ts +81 -34
- package/src/lib/primitives/geometry/Point2d.test.ts +14 -3
- package/src/lib/primitives/geometry/Point2d.ts +1 -1
- package/src/lib/primitives/geometry/Polyline2d.test.ts +207 -0
- package/src/lib/primitives/geometry/Stadium2d.test.ts +191 -3
- package/src/lib/primitives/utils.test.ts +10 -1
- package/src/lib/primitives/utils.ts +4 -1
- package/src/lib/test/useCanvasEvents.test.tsx +74 -0
- package/src/lib/test/useDocumentEvents.test.tsx +107 -0
- package/src/lib/test/usePassThroughWheelEvents.test.tsx +25 -2
- package/src/lib/utils/deepLinks.test.ts +15 -0
- package/src/lib/utils/deepLinks.ts +7 -1
- package/src/lib/utils/normalizeWheel.test.ts +39 -0
- package/src/lib/utils/normalizeWheel.ts +6 -0
- package/src/lib/utils/rotation.ts +4 -12
- package/src/lib/utils/sync/TLLocalSyncClient.test.ts +56 -0
- package/src/lib/utils/sync/TLLocalSyncClient.ts +24 -0
- package/src/lib/utils/sync/alerts.ts +1 -1
- package/src/version.ts +3 -3
- package/src/lib/primitives/geometry/Polyline.test.ts +0 -5
|
@@ -1,5 +1,245 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import { perimeterOfEllipse } from '../utils'
|
|
2
|
+
import { Vec } from '../Vec'
|
|
3
|
+
import { Edge2d } from './Edge2d'
|
|
4
|
+
import { Ellipse2d } from './Ellipse2d'
|
|
5
|
+
import { getVerticesCountForArcLength } from './geometry-constants'
|
|
6
|
+
|
|
7
|
+
// A 100x50 ellipse: centre (50, 25), rx = 50, ry = 25
|
|
8
|
+
const ellipse = () => new Ellipse2d({ width: 100, height: 50, isFilled: false })
|
|
9
|
+
const filled = () => new Ellipse2d({ width: 100, height: 50, isFilled: true })
|
|
10
|
+
|
|
11
|
+
function expectOnEllipse(p: Vec, cx: number, cy: number, rx: number, ry: number) {
|
|
12
|
+
const dx = (p.x - cx) / rx
|
|
13
|
+
const dy = (p.y - cy) / ry
|
|
14
|
+
expect(dx * dx + dy * dy).toBeCloseTo(1, 6)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
describe('Ellipse2d construction', () => {
|
|
18
|
+
it('is always closed and keeps the fill flag from config', () => {
|
|
19
|
+
expect(ellipse()).toMatchObject({ isClosed: true, isFilled: false })
|
|
20
|
+
expect(filled()).toMatchObject({ isClosed: true, isFilled: true })
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
it('passes through the other geometry options', () => {
|
|
24
|
+
const e = new Ellipse2d({
|
|
25
|
+
width: 10,
|
|
26
|
+
height: 10,
|
|
27
|
+
isFilled: true,
|
|
28
|
+
isLabel: true,
|
|
29
|
+
isInternal: true,
|
|
30
|
+
debugColor: 'red',
|
|
31
|
+
ignore: true,
|
|
32
|
+
excludeFromShapeBounds: true,
|
|
33
|
+
})
|
|
34
|
+
expect(e).toMatchObject({
|
|
35
|
+
isLabel: true,
|
|
36
|
+
isInternal: true,
|
|
37
|
+
debugColor: 'red',
|
|
38
|
+
ignore: true,
|
|
39
|
+
excludeFromShapeBounds: true,
|
|
40
|
+
})
|
|
41
|
+
})
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
describe('Ellipse2d.getVertices', () => {
|
|
45
|
+
it('samples one vertex per 20 units of perimeter, starting at the rightmost point', () => {
|
|
46
|
+
const e = ellipse()
|
|
47
|
+
const { vertices } = e
|
|
48
|
+
expect(vertices.length).toBe(getVerticesCountForArcLength(perimeterOfEllipse(50, 25)))
|
|
49
|
+
expect(vertices.length).toBe(13)
|
|
50
|
+
expect(vertices[0]).toMatchObject({ x: 100, y: 25 })
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
it('places every vertex on the ellipse and inside the bounds', () => {
|
|
54
|
+
const { vertices, bounds } = ellipse()
|
|
55
|
+
for (const v of vertices) {
|
|
56
|
+
expectOnEllipse(v, 50, 25, 50, 25)
|
|
57
|
+
expect(bounds.containsPoint(v)).toBe(true)
|
|
58
|
+
}
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
it('walks the ellipse in the positive angular direction', () => {
|
|
62
|
+
const { vertices } = ellipse()
|
|
63
|
+
// second vertex is one step (2π/13) clockwise in screen space, so below the first
|
|
64
|
+
expect(vertices[1].x).toBeLessThan(100)
|
|
65
|
+
expect(vertices[1].y).toBeGreaterThan(25)
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
it('falls back to the minimum vertex count for a tiny ellipse', () => {
|
|
69
|
+
const { vertices } = new Ellipse2d({ width: 1, height: 1, isFilled: false })
|
|
70
|
+
expect(vertices.length).toBe(8)
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
it('does not produce NaNs for a zero size ellipse', () => {
|
|
74
|
+
const e = new Ellipse2d({ width: 0, height: 0, isFilled: false })
|
|
75
|
+
expect(e.vertices.length).toBe(8)
|
|
76
|
+
for (const v of e.vertices) {
|
|
77
|
+
expect(Number.isFinite(v.x)).toBe(true)
|
|
78
|
+
expect(Number.isFinite(v.y)).toBe(true)
|
|
79
|
+
}
|
|
80
|
+
expect(e.bounds).toMatchObject({ x: 0, y: 0, w: 0, h: 0 })
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
it('has a NaN length for a zero size ellipse (known quirk)', () => {
|
|
84
|
+
// perimeterOfEllipse divides by (rx + ry) ** 2, which is zero here
|
|
85
|
+
expect(new Ellipse2d({ width: 0, height: 0, isFilled: false }).getLength()).toBeNaN()
|
|
86
|
+
})
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
describe('Ellipse2d.edges', () => {
|
|
90
|
+
it('connects consecutive vertices and closes back to the first', () => {
|
|
91
|
+
const e = ellipse()
|
|
92
|
+
const { edges, vertices } = e
|
|
93
|
+
expect(edges.length).toBe(vertices.length)
|
|
94
|
+
expect(edges[0]).toBeInstanceOf(Edge2d)
|
|
95
|
+
expect(edges[0].vertices).toEqual([vertices[0], vertices[1]])
|
|
96
|
+
expect(edges[edges.length - 1].vertices).toEqual([vertices[vertices.length - 1], vertices[0]])
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
it('caches the edges', () => {
|
|
100
|
+
const e = ellipse()
|
|
101
|
+
expect(e.edges).toBe(e.edges)
|
|
102
|
+
})
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
describe('Ellipse2d.bounds', () => {
|
|
106
|
+
it('is the width by height box at the origin', () => {
|
|
107
|
+
expect(ellipse().bounds).toMatchObject({ x: 0, y: 0, w: 100, h: 50 })
|
|
108
|
+
expect(ellipse().center).toMatchObject({ x: 50, y: 25 })
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
it('is not affected by the polygon approximation', () => {
|
|
112
|
+
// the bounds come from the config, not from the sampled vertices
|
|
113
|
+
const e = new Ellipse2d({ width: 3, height: 7, isFilled: false })
|
|
114
|
+
expect(e.bounds).toMatchObject({ x: 0, y: 0, w: 3, h: 7 })
|
|
115
|
+
})
|
|
116
|
+
})
|
|
117
|
+
|
|
118
|
+
describe('Ellipse2d.getLength', () => {
|
|
119
|
+
it("uses Ramanujan's perimeter approximation", () => {
|
|
120
|
+
expect(ellipse().length).toBeCloseTo(242.21, 1)
|
|
121
|
+
expect(ellipse().length).toBeCloseTo(perimeterOfEllipse(50, 25))
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
it('matches a circle circumference when width equals height', () => {
|
|
125
|
+
expect(new Ellipse2d({ width: 100, height: 100, isFilled: false }).length).toBeCloseTo(
|
|
126
|
+
Math.PI * 100
|
|
127
|
+
)
|
|
128
|
+
})
|
|
129
|
+
})
|
|
130
|
+
|
|
131
|
+
describe('Ellipse2d.area', () => {
|
|
132
|
+
it('is the area of the inscribed polygon', () => {
|
|
133
|
+
const e = ellipse()
|
|
134
|
+
const n = e.vertices.length
|
|
135
|
+
expect(e.area).toBeCloseTo((n / 2) * 50 * 25 * Math.sin((2 * Math.PI) / n), 5)
|
|
136
|
+
expect(e.area).toBeLessThan(Math.PI * 50 * 25)
|
|
137
|
+
})
|
|
138
|
+
})
|
|
139
|
+
|
|
140
|
+
describe('Ellipse2d.nearestPoint', () => {
|
|
141
|
+
it('returns the vertex when it is the nearest point', () => {
|
|
142
|
+
expect(ellipse().nearestPoint(new Vec(150, 25))).toMatchObject({ x: 100, y: 25 })
|
|
143
|
+
})
|
|
144
|
+
|
|
145
|
+
it('returns a point on the edge polygon nearest to the point', () => {
|
|
146
|
+
const e = ellipse()
|
|
147
|
+
const p = e.nearestPoint(new Vec(50, -10))
|
|
148
|
+
expect(Vec.Dist(p, new Vec(50, 0))).toBeLessThan(1.5)
|
|
149
|
+
expect(e.hitTestPoint(p, 0.001)).toBe(true)
|
|
150
|
+
})
|
|
151
|
+
|
|
152
|
+
it('accepts plain objects', () => {
|
|
153
|
+
expect(ellipse().nearestPoint({ x: 150, y: 25 })).toMatchObject({ x: 100, y: 25 })
|
|
154
|
+
})
|
|
155
|
+
})
|
|
156
|
+
|
|
157
|
+
describe('Ellipse2d.distanceToPoint', () => {
|
|
158
|
+
it('is positive outside', () => {
|
|
159
|
+
expect(ellipse().distanceToPoint(new Vec(150, 25))).toBe(50)
|
|
160
|
+
expect(filled().distanceToPoint(new Vec(150, 25))).toBe(50)
|
|
161
|
+
})
|
|
162
|
+
|
|
163
|
+
it('is zero on a vertex', () => {
|
|
164
|
+
expect(ellipse().distanceToPoint(new Vec(100, 25))).toBe(0)
|
|
165
|
+
})
|
|
166
|
+
|
|
167
|
+
it('is negative inside only when filled or hitInside', () => {
|
|
168
|
+
const unfilledDist = ellipse().distanceToPoint(new Vec(50, 25))
|
|
169
|
+
expect(unfilledDist).toBeGreaterThan(0)
|
|
170
|
+
expect(filled().distanceToPoint(new Vec(50, 25))).toBe(-unfilledDist)
|
|
171
|
+
expect(ellipse().distanceToPoint(new Vec(50, 25), true)).toBe(-unfilledDist)
|
|
172
|
+
})
|
|
173
|
+
})
|
|
174
|
+
|
|
175
|
+
describe('Ellipse2d.hitTestPoint', () => {
|
|
176
|
+
it('hits the interior only when filled or hitInside', () => {
|
|
177
|
+
expect(filled().hitTestPoint(new Vec(50, 25))).toBe(true)
|
|
178
|
+
expect(ellipse().hitTestPoint(new Vec(50, 25))).toBe(false)
|
|
179
|
+
expect(ellipse().hitTestPoint(new Vec(50, 25), 0, true)).toBe(true)
|
|
180
|
+
})
|
|
181
|
+
|
|
182
|
+
it('misses points outside', () => {
|
|
183
|
+
expect(filled().hitTestPoint(new Vec(150, 25))).toBe(false)
|
|
184
|
+
expect(ellipse().hitTestPoint(new Vec(150, 25))).toBe(false)
|
|
185
|
+
})
|
|
186
|
+
|
|
187
|
+
it('misses the bounding box corners, which are outside the ellipse', () => {
|
|
188
|
+
expect(filled().hitTestPoint(new Vec(1, 1))).toBe(false)
|
|
189
|
+
expect(filled().hitTestPoint(new Vec(99, 49))).toBe(false)
|
|
190
|
+
})
|
|
191
|
+
|
|
192
|
+
it('hits the edge', () => {
|
|
193
|
+
expect(ellipse().hitTestPoint(new Vec(100, 25))).toBe(true)
|
|
194
|
+
})
|
|
195
|
+
|
|
196
|
+
it('respects the margin', () => {
|
|
197
|
+
expect(ellipse().hitTestPoint(new Vec(105, 25), 5)).toBe(true)
|
|
198
|
+
expect(ellipse().hitTestPoint(new Vec(105, 25), 4)).toBe(false)
|
|
199
|
+
expect(ellipse().hitTestPoint(new Vec(95, 25), 5)).toBe(true)
|
|
200
|
+
})
|
|
201
|
+
})
|
|
202
|
+
|
|
203
|
+
describe('Ellipse2d.hitTestLineSegment', () => {
|
|
204
|
+
it('hits a segment crossing the edge', () => {
|
|
205
|
+
expect(ellipse().hitTestLineSegment(new Vec(50, -10), new Vec(50, 60))).toBe(true)
|
|
206
|
+
expect(ellipse().hitTestLineSegment(new Vec(90, 25), new Vec(110, 25))).toBe(true)
|
|
207
|
+
})
|
|
208
|
+
|
|
209
|
+
it('misses a segment entirely outside', () => {
|
|
210
|
+
expect(ellipse().hitTestLineSegment(new Vec(150, 0), new Vec(150, 50))).toBe(false)
|
|
211
|
+
})
|
|
212
|
+
|
|
213
|
+
it('misses a segment entirely inside, even when filled', () => {
|
|
214
|
+
expect(ellipse().hitTestLineSegment(new Vec(40, 25), new Vec(60, 25))).toBe(false)
|
|
215
|
+
expect(filled().hitTestLineSegment(new Vec(40, 25), new Vec(60, 25))).toBe(false)
|
|
216
|
+
})
|
|
217
|
+
|
|
218
|
+
it('misses a segment that cuts through a bounding box corner only', () => {
|
|
219
|
+
expect(ellipse().hitTestLineSegment(new Vec(0, 0), new Vec(5, 5))).toBe(false)
|
|
220
|
+
})
|
|
221
|
+
})
|
|
222
|
+
|
|
223
|
+
describe('Ellipse2d.intersectLineSegment', () => {
|
|
224
|
+
it('returns both crossings of a horizontal line through the centre', () => {
|
|
225
|
+
const hits = ellipse().intersectLineSegment(new Vec(-10, 25), new Vec(110, 25))
|
|
226
|
+
expect(hits.length).toBe(2)
|
|
227
|
+
expect(hits.map((h) => h.y)).toEqual([25, 25])
|
|
228
|
+
const xs = hits.map((h) => h.x).sort((a, b) => a - b)
|
|
229
|
+
// the leftmost point is not a vertex, so the polygon edge sits slightly inside the ellipse
|
|
230
|
+
expect(xs[0]).toBeGreaterThanOrEqual(0)
|
|
231
|
+
expect(xs[0]).toBeLessThan(2)
|
|
232
|
+
expect(xs[1]).toBe(100)
|
|
233
|
+
})
|
|
234
|
+
})
|
|
235
|
+
|
|
236
|
+
describe('Ellipse2d.getSvgPathData', () => {
|
|
237
|
+
it('draws two arcs starting from the leftmost point', () => {
|
|
238
|
+
expect(ellipse().getSvgPathData(true)).toBe('M0,25 a50,25,0,1,1,100,0a50,25,0,1,1,-100,0')
|
|
239
|
+
})
|
|
240
|
+
|
|
241
|
+
it('omits the move command when not first', () => {
|
|
242
|
+
expect(ellipse().getSvgPathData()).toBe(' a50,25,0,1,1,100,0a50,25,0,1,1,-100,0')
|
|
243
|
+
expect(ellipse().getSvgPathData(false)).toBe(ellipse().getSvgPathData())
|
|
4
244
|
})
|
|
5
245
|
})
|