@tldraw/editor 3.13.0-canary.ca982decc2f2 → 3.13.0-canary.cb6b7a41c175
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 +113 -111
- package/dist-cjs/index.js +7 -22
- package/dist-cjs/index.js.map +2 -2
- package/dist-cjs/lib/TldrawEditor.js +2 -1
- package/dist-cjs/lib/TldrawEditor.js.map +2 -2
- package/dist-cjs/lib/components/Shape.js +12 -8
- package/dist-cjs/lib/components/Shape.js.map +2 -2
- package/dist-cjs/lib/components/default-components/DefaultCanvas.js +27 -2
- package/dist-cjs/lib/components/default-components/DefaultCanvas.js.map +2 -2
- package/dist-cjs/lib/components/default-components/DefaultErrorFallback.js +8 -6
- package/dist-cjs/lib/components/default-components/DefaultErrorFallback.js.map +2 -2
- package/dist-cjs/lib/components/default-components/DefaultShapeIndicator.js +17 -11
- package/dist-cjs/lib/components/default-components/DefaultShapeIndicator.js.map +2 -2
- package/dist-cjs/lib/components/default-components/DefaultSpinner.js +1 -1
- package/dist-cjs/lib/components/default-components/DefaultSpinner.js.map +2 -2
- package/dist-cjs/lib/editor/Editor.js +39 -14
- package/dist-cjs/lib/editor/Editor.js.map +2 -2
- package/dist-cjs/lib/editor/managers/SnapManager/HandleSnaps.js.map +2 -2
- package/dist-cjs/lib/editor/managers/TextManager.js +10 -0
- package/dist-cjs/lib/editor/managers/TextManager.js.map +2 -2
- package/dist-cjs/lib/editor/shapes/ShapeUtil.js.map +2 -2
- package/dist-cjs/lib/editor/shapes/shared/getPerfectDashProps.js.map +2 -2
- package/dist-cjs/lib/exports/getSvgJsx.js +12 -3
- package/dist-cjs/lib/exports/getSvgJsx.js.map +2 -2
- package/dist-cjs/lib/hooks/useDocumentEvents.js +3 -2
- package/dist-cjs/lib/hooks/useDocumentEvents.js.map +2 -2
- package/dist-cjs/lib/hooks/useEditorComponents.js +16 -15
- package/dist-cjs/lib/hooks/useEditorComponents.js.map +2 -2
- package/dist-cjs/lib/options.js.map +2 -2
- package/dist-cjs/lib/primitives/Box.js +16 -0
- package/dist-cjs/lib/primitives/Box.js.map +2 -2
- package/dist-cjs/lib/primitives/Mat.js +1 -1
- package/dist-cjs/lib/primitives/Mat.js.map +2 -2
- package/dist-cjs/lib/primitives/Vec.js +20 -0
- package/dist-cjs/lib/primitives/Vec.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/Arc2d.js +2 -2
- package/dist-cjs/lib/primitives/geometry/Arc2d.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/Circle2d.js +1 -1
- package/dist-cjs/lib/primitives/geometry/Circle2d.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/CubicSpline2d.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/Ellipse2d.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/Geometry2d.js +91 -20
- package/dist-cjs/lib/primitives/geometry/Geometry2d.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/Group2d.js +55 -2
- package/dist-cjs/lib/primitives/geometry/Group2d.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/Point2d.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/Polyline2d.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/Stadium2d.js.map +2 -2
- package/dist-cjs/lib/utils/areShapesContentEqual.js +25 -0
- package/dist-cjs/lib/utils/areShapesContentEqual.js.map +7 -0
- package/dist-cjs/lib/utils/debug-flags.js +5 -2
- package/dist-cjs/lib/utils/debug-flags.js.map +2 -2
- package/dist-cjs/lib/utils/dom.js +3 -3
- package/dist-cjs/lib/utils/dom.js.map +2 -2
- package/dist-cjs/lib/utils/nearestMultiple.js +34 -0
- package/dist-cjs/lib/utils/nearestMultiple.js.map +7 -0
- package/dist-cjs/lib/utils/rotation.js +5 -5
- package/dist-cjs/lib/utils/rotation.js.map +2 -2
- package/dist-cjs/version.js +3 -3
- package/dist-cjs/version.js.map +1 -1
- package/dist-esm/index.d.mts +113 -111
- package/dist-esm/index.mjs +9 -41
- package/dist-esm/index.mjs.map +2 -2
- package/dist-esm/lib/TldrawEditor.mjs +2 -1
- package/dist-esm/lib/TldrawEditor.mjs.map +2 -2
- package/dist-esm/lib/components/Shape.mjs +12 -8
- package/dist-esm/lib/components/Shape.mjs.map +2 -2
- package/dist-esm/lib/components/default-components/DefaultCanvas.mjs +27 -2
- package/dist-esm/lib/components/default-components/DefaultCanvas.mjs.map +2 -2
- package/dist-esm/lib/components/default-components/DefaultErrorFallback.mjs +8 -6
- package/dist-esm/lib/components/default-components/DefaultErrorFallback.mjs.map +2 -2
- package/dist-esm/lib/components/default-components/DefaultShapeIndicator.mjs +17 -11
- package/dist-esm/lib/components/default-components/DefaultShapeIndicator.mjs.map +2 -2
- package/dist-esm/lib/components/default-components/DefaultSpinner.mjs +1 -1
- package/dist-esm/lib/components/default-components/DefaultSpinner.mjs.map +2 -2
- package/dist-esm/lib/editor/Editor.mjs +39 -14
- package/dist-esm/lib/editor/Editor.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/SnapManager/HandleSnaps.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/TextManager.mjs +10 -0
- package/dist-esm/lib/editor/managers/TextManager.mjs.map +2 -2
- package/dist-esm/lib/editor/shapes/ShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/editor/shapes/shared/getPerfectDashProps.mjs.map +2 -2
- package/dist-esm/lib/exports/getSvgJsx.mjs +12 -3
- package/dist-esm/lib/exports/getSvgJsx.mjs.map +2 -2
- package/dist-esm/lib/hooks/useDocumentEvents.mjs +3 -2
- package/dist-esm/lib/hooks/useDocumentEvents.mjs.map +2 -2
- package/dist-esm/lib/hooks/useEditorComponents.mjs +16 -15
- package/dist-esm/lib/hooks/useEditorComponents.mjs.map +2 -2
- package/dist-esm/lib/options.mjs.map +2 -2
- package/dist-esm/lib/primitives/Box.mjs +16 -0
- package/dist-esm/lib/primitives/Box.mjs.map +2 -2
- package/dist-esm/lib/primitives/Mat.mjs +1 -1
- package/dist-esm/lib/primitives/Mat.mjs.map +2 -2
- package/dist-esm/lib/primitives/Vec.mjs +20 -0
- package/dist-esm/lib/primitives/Vec.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/Arc2d.mjs +2 -2
- package/dist-esm/lib/primitives/geometry/Arc2d.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/Circle2d.mjs +1 -1
- package/dist-esm/lib/primitives/geometry/Circle2d.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/CubicSpline2d.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/Ellipse2d.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/Geometry2d.mjs +92 -21
- package/dist-esm/lib/primitives/geometry/Geometry2d.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/Group2d.mjs +55 -2
- package/dist-esm/lib/primitives/geometry/Group2d.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/Point2d.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/Polyline2d.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/Stadium2d.mjs.map +2 -2
- package/dist-esm/lib/utils/areShapesContentEqual.mjs +5 -0
- package/dist-esm/lib/utils/areShapesContentEqual.mjs.map +7 -0
- package/dist-esm/lib/utils/debug-flags.mjs +5 -2
- package/dist-esm/lib/utils/debug-flags.mjs.map +2 -2
- package/dist-esm/lib/utils/dom.mjs +3 -3
- package/dist-esm/lib/utils/dom.mjs.map +2 -2
- package/dist-esm/lib/utils/nearestMultiple.mjs +14 -0
- package/dist-esm/lib/utils/nearestMultiple.mjs.map +7 -0
- package/dist-esm/lib/utils/rotation.mjs +5 -5
- package/dist-esm/lib/utils/rotation.mjs.map +2 -2
- package/dist-esm/version.mjs +3 -3
- package/dist-esm/version.mjs.map +1 -1
- package/editor.css +34 -4
- package/package.json +7 -7
- package/src/index.ts +16 -31
- package/src/lib/TldrawEditor.tsx +6 -1
- package/src/lib/components/Shape.tsx +14 -10
- package/src/lib/components/default-components/DefaultCanvas.tsx +32 -2
- package/src/lib/components/default-components/DefaultErrorFallback.tsx +15 -8
- package/src/lib/components/default-components/DefaultShapeIndicator.tsx +17 -8
- package/src/lib/components/default-components/DefaultSpinner.tsx +1 -1
- package/src/lib/editor/Editor.test.ts +1 -1
- package/src/lib/editor/Editor.ts +39 -14
- package/src/lib/editor/managers/SnapManager/HandleSnaps.ts +0 -1
- package/src/lib/editor/managers/TextManager.ts +12 -0
- package/src/lib/editor/shapes/ShapeUtil.ts +22 -2
- package/src/lib/editor/shapes/shared/getPerfectDashProps.ts +9 -9
- package/src/lib/exports/getSvgJsx.tsx +16 -7
- package/src/lib/hooks/useDocumentEvents.ts +7 -2
- package/src/lib/hooks/useEditorComponents.tsx +32 -28
- package/src/lib/options.ts +4 -0
- package/src/lib/primitives/Box.ts +20 -0
- package/src/lib/primitives/Mat.ts +5 -4
- package/src/lib/primitives/Vec.ts +23 -0
- package/src/lib/primitives/geometry/Arc2d.ts +5 -5
- package/src/lib/primitives/geometry/Circle2d.ts +4 -4
- package/src/lib/primitives/geometry/CubicBezier2d.ts +4 -4
- package/src/lib/primitives/geometry/CubicSpline2d.ts +3 -3
- package/src/lib/primitives/geometry/Edge2d.ts +3 -3
- package/src/lib/primitives/geometry/Ellipse2d.ts +3 -3
- package/src/lib/primitives/geometry/Geometry2d.test.ts +42 -0
- package/src/lib/primitives/geometry/Geometry2d.ts +123 -35
- package/src/lib/primitives/geometry/Group2d.ts +70 -7
- package/src/lib/primitives/geometry/Point2d.ts +2 -2
- package/src/lib/primitives/geometry/Polyline2d.ts +3 -3
- package/src/lib/primitives/geometry/Stadium2d.ts +3 -3
- package/src/lib/test/currentToolIdMask.test.ts +1 -1
- package/src/lib/test/user.test.ts +1 -1
- package/src/lib/utils/areShapesContentEqual.ts +4 -0
- package/src/lib/utils/debug-flags.ts +7 -2
- package/src/lib/utils/dom.ts +4 -4
- package/src/lib/utils/nearestMultiple.ts +13 -0
- package/src/lib/utils/rotation.ts +8 -6
- package/src/lib/utils/sync/LocalIndexedDb.test.ts +1 -1
- package/src/lib/utils/sync/TLLocalSyncClient.test.ts +1 -1
- package/src/version.ts +3 -3
|
@@ -22,6 +22,7 @@ import { Vec } from '../../primitives/Vec'
|
|
|
22
22
|
import { toDomPrecision } from '../../primitives/utils'
|
|
23
23
|
import { debugFlags } from '../../utils/debug-flags'
|
|
24
24
|
import { setStyleProperty } from '../../utils/dom'
|
|
25
|
+
import { nearestMultiple } from '../../utils/nearestMultiple'
|
|
25
26
|
import { GeometryDebuggingView } from '../GeometryDebuggingView'
|
|
26
27
|
import { LiveCollaborators } from '../LiveCollaborators'
|
|
27
28
|
import { MenuClickCapture } from '../MenuClickCapture'
|
|
@@ -168,6 +169,7 @@ export function DefaultCanvas({ className }: TLCanvasComponentProps) {
|
|
|
168
169
|
<SnapIndicatorWrapper />
|
|
169
170
|
<SelectionForegroundWrapper />
|
|
170
171
|
<HandlesWrapper />
|
|
172
|
+
<OverlaysWrapper />
|
|
171
173
|
<LiveCollaborators />
|
|
172
174
|
</div>
|
|
173
175
|
</div>
|
|
@@ -372,14 +374,33 @@ function HandleWrapper({
|
|
|
372
374
|
)
|
|
373
375
|
}
|
|
374
376
|
|
|
377
|
+
function OverlaysWrapper() {
|
|
378
|
+
const { Overlays } = useEditorComponents()
|
|
379
|
+
if (!Overlays) return null
|
|
380
|
+
return (
|
|
381
|
+
<div className="tl-custom-overlays tl-overlays__item">
|
|
382
|
+
<Overlays />
|
|
383
|
+
</div>
|
|
384
|
+
)
|
|
385
|
+
}
|
|
386
|
+
|
|
375
387
|
function ShapesWithSVGs() {
|
|
376
388
|
const editor = useEditor()
|
|
377
389
|
|
|
378
390
|
const renderingShapes = useValue('rendering shapes', () => editor.getRenderingShapes(), [editor])
|
|
379
391
|
|
|
392
|
+
const dprMultiple = useValue(
|
|
393
|
+
'dpr multiple',
|
|
394
|
+
() =>
|
|
395
|
+
// dprMultiple is the smallest number we can multiply dpr by to get an integer
|
|
396
|
+
// it's usually 1, 2, or 4 (for e.g. dpr of 2, 2.5 and 2.25 respectively)
|
|
397
|
+
nearestMultiple(Math.floor(editor.getInstanceState().devicePixelRatio * 100) / 100),
|
|
398
|
+
[editor]
|
|
399
|
+
)
|
|
400
|
+
|
|
380
401
|
return renderingShapes.map((result) => (
|
|
381
402
|
<Fragment key={result.id + '_fragment'}>
|
|
382
|
-
<Shape {...result} />
|
|
403
|
+
<Shape {...result} dprMultiple={dprMultiple} />
|
|
383
404
|
<DebugSvgCopy id={result.id} mode="iframe" />
|
|
384
405
|
</Fragment>
|
|
385
406
|
))
|
|
@@ -414,10 +435,19 @@ function ShapesToDisplay() {
|
|
|
414
435
|
|
|
415
436
|
const renderingShapes = useValue('rendering shapes', () => editor.getRenderingShapes(), [editor])
|
|
416
437
|
|
|
438
|
+
const dprMultiple = useValue(
|
|
439
|
+
'dpr multiple',
|
|
440
|
+
() =>
|
|
441
|
+
// dprMultiple is the smallest number we can multiply dpr by to get an integer
|
|
442
|
+
// it's usually 1, 2, or 4 (for e.g. dpr of 2, 2.5 and 2.25 respectively)
|
|
443
|
+
nearestMultiple(Math.floor(editor.getInstanceState().devicePixelRatio * 100) / 100),
|
|
444
|
+
[editor]
|
|
445
|
+
)
|
|
446
|
+
|
|
417
447
|
return (
|
|
418
448
|
<>
|
|
419
449
|
{renderingShapes.map((result) => (
|
|
420
|
-
<Shape key={result.id + '_shape'} {...result} />
|
|
450
|
+
<Shape key={result.id + '_shape'} {...result} dprMultiple={dprMultiple} />
|
|
421
451
|
))}
|
|
422
452
|
{tlenv.isSafari && <ReflowIfNeeded />}
|
|
423
453
|
</>
|
|
@@ -168,16 +168,23 @@ My browser: ${navigator.userAgent}`
|
|
|
168
168
|
) : (
|
|
169
169
|
<>
|
|
170
170
|
<h2>Something went wrong</h2>
|
|
171
|
-
<p>Please refresh
|
|
171
|
+
<p>Please refresh your browser.</p>
|
|
172
172
|
<p>
|
|
173
|
-
If
|
|
174
|
-
|
|
175
|
-
<a href="https://discord.tldraw.com/?utm_source=sdk&utm_medium=organic&utm_campaign=error-screen">
|
|
176
|
-
Discord
|
|
177
|
-
</a>
|
|
178
|
-
. If you are still stuck, you can reset the tldraw data on your machine. This may
|
|
179
|
-
erase the project you were working on, so try to get help first.
|
|
173
|
+
If the issue continues after refreshing, you may need to reset the tldraw data stored
|
|
174
|
+
on your device.
|
|
180
175
|
</p>
|
|
176
|
+
<p>
|
|
177
|
+
<strong>Note:</strong> Resetting will erase your current project and any unsaved work.
|
|
178
|
+
</p>
|
|
179
|
+
{process.env.NODE_ENV !== 'production' && (
|
|
180
|
+
<p>
|
|
181
|
+
If you're developing with the SDK and need help, join us on{' '}
|
|
182
|
+
<a href="https://discord.tldraw.com/?utm_source=sdk&utm_medium=organic&utm_campaign=error-screen">
|
|
183
|
+
Discord
|
|
184
|
+
</a>
|
|
185
|
+
.
|
|
186
|
+
</p>
|
|
187
|
+
)}
|
|
181
188
|
{shouldShowError && (
|
|
182
189
|
<>
|
|
183
190
|
Message:
|
|
@@ -9,13 +9,21 @@ import { useEditorComponents } from '../../hooks/useEditorComponents'
|
|
|
9
9
|
import { OptionalErrorBoundary } from '../ErrorBoundary'
|
|
10
10
|
|
|
11
11
|
// need an extra layer of indirection here to allow hooks to be used inside the indicator render
|
|
12
|
-
const EvenInnererIndicator = memo(
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
12
|
+
const EvenInnererIndicator = memo(
|
|
13
|
+
({ shape, util }: { shape: TLShape; util: ShapeUtil<any> }) => {
|
|
14
|
+
return useStateTracking('Indicator: ' + shape.type, () =>
|
|
15
|
+
// always fetch the latest shape from the store even if the props/meta have not changed, to avoid
|
|
16
|
+
// calling the render method with stale data.
|
|
17
|
+
util.indicator(util.editor.store.unsafeGetWithoutCapture(shape.id) as TLShape)
|
|
18
|
+
)
|
|
19
|
+
},
|
|
20
|
+
(prevProps, nextProps) => {
|
|
21
|
+
return (
|
|
22
|
+
prevProps.shape.props === nextProps.shape.props &&
|
|
23
|
+
prevProps.shape.meta === nextProps.shape.meta
|
|
24
|
+
)
|
|
25
|
+
}
|
|
26
|
+
)
|
|
19
27
|
|
|
20
28
|
const InnerIndicator = memo(({ editor, id }: { editor: Editor; id: TLShapeId }) => {
|
|
21
29
|
const shape = useValue('shape for indicator', () => editor.store.get(id), [editor, id])
|
|
@@ -61,13 +69,14 @@ export const DefaultShapeIndicator = memo(function DefaultShapeIndicator({
|
|
|
61
69
|
useQuickReactor(
|
|
62
70
|
'indicator transform',
|
|
63
71
|
() => {
|
|
72
|
+
if (hidden) return
|
|
64
73
|
const elm = rIndicator.current
|
|
65
74
|
if (!elm) return
|
|
66
75
|
const pageTransform = editor.getShapePageTransform(shapeId)
|
|
67
76
|
if (!pageTransform) return
|
|
68
77
|
elm.style.setProperty('transform', pageTransform.toCssString())
|
|
69
78
|
},
|
|
70
|
-
[editor, shapeId]
|
|
79
|
+
[editor, shapeId, hidden]
|
|
71
80
|
)
|
|
72
81
|
|
|
73
82
|
useLayoutEffect(() => {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/** @public @react */
|
|
2
2
|
export function DefaultSpinner() {
|
|
3
3
|
return (
|
|
4
|
-
<svg width={16} height={16} viewBox="0 0 16 16">
|
|
4
|
+
<svg width={16} height={16} viewBox="0 0 16 16" aria-hidden="false">
|
|
5
5
|
<g strokeWidth={2} fill="none" fillRule="evenodd">
|
|
6
6
|
<circle strokeOpacity={0.25} cx={8} cy={8} r={7} stroke="currentColor" />
|
|
7
7
|
<path strokeLinecap="round" d="M15 8c0-4.5-4.5-7-7-7" stroke="currentColor">
|
|
@@ -52,7 +52,7 @@ beforeEach(() => {
|
|
|
52
52
|
shapeUtils: [CustomShape],
|
|
53
53
|
bindingUtils: [],
|
|
54
54
|
tools: [],
|
|
55
|
-
store: createTLStore({ shapeUtils: [CustomShape] }),
|
|
55
|
+
store: createTLStore({ shapeUtils: [CustomShape], bindingUtils: [] }),
|
|
56
56
|
getContainer: () => document.body,
|
|
57
57
|
})
|
|
58
58
|
editor.setCameraOptions({ isLocked: true })
|
package/src/lib/editor/Editor.ts
CHANGED
|
@@ -129,6 +129,7 @@ import { Group2d } from '../primitives/geometry/Group2d'
|
|
|
129
129
|
import { intersectPolygonPolygon } from '../primitives/intersect'
|
|
130
130
|
import { PI, approximately, areAnglesCompatible, clamp, pointInPolygon } from '../primitives/utils'
|
|
131
131
|
import { ReadonlySharedStyleMap, SharedStyle, SharedStyleMap } from '../utils/SharedStylesMap'
|
|
132
|
+
import { areShapesContentEqual } from '../utils/areShapesContentEqual'
|
|
132
133
|
import { dataUrlToFile } from '../utils/assets'
|
|
133
134
|
import { debugFlags } from '../utils/debug-flags'
|
|
134
135
|
import {
|
|
@@ -2275,13 +2276,21 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
2275
2276
|
setEditingShape(shape: TLShapeId | TLShape | null): this {
|
|
2276
2277
|
const id = typeof shape === 'string' ? shape : (shape?.id ?? null)
|
|
2277
2278
|
this.setRichTextEditor(null)
|
|
2278
|
-
|
|
2279
|
+
const prevEditingShapeId = this.getEditingShapeId()
|
|
2280
|
+
if (id !== prevEditingShapeId) {
|
|
2279
2281
|
if (id) {
|
|
2280
2282
|
const shape = this.getShape(id)
|
|
2281
2283
|
if (shape && this.getShapeUtil(shape).canEdit(shape)) {
|
|
2282
2284
|
this.run(
|
|
2283
2285
|
() => {
|
|
2284
2286
|
this._updateCurrentPageState({ editingShapeId: id })
|
|
2287
|
+
if (prevEditingShapeId) {
|
|
2288
|
+
const prevEditingShape = this.getShape(prevEditingShapeId)
|
|
2289
|
+
if (prevEditingShape) {
|
|
2290
|
+
this.getShapeUtil(prevEditingShape).onEditEnd?.(prevEditingShape)
|
|
2291
|
+
}
|
|
2292
|
+
}
|
|
2293
|
+
this.getShapeUtil(shape).onEditStart?.(shape)
|
|
2285
2294
|
},
|
|
2286
2295
|
{ history: 'ignore' }
|
|
2287
2296
|
)
|
|
@@ -2294,6 +2303,12 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
2294
2303
|
() => {
|
|
2295
2304
|
this._updateCurrentPageState({ editingShapeId: null })
|
|
2296
2305
|
this._currentRichTextEditor.set(null)
|
|
2306
|
+
if (prevEditingShapeId) {
|
|
2307
|
+
const prevEditingShape = this.getShape(prevEditingShapeId)
|
|
2308
|
+
if (prevEditingShape) {
|
|
2309
|
+
this.getShapeUtil(prevEditingShape).onEditEnd?.(prevEditingShape)
|
|
2310
|
+
}
|
|
2311
|
+
}
|
|
2297
2312
|
},
|
|
2298
2313
|
{ history: 'ignore' }
|
|
2299
2314
|
)
|
|
@@ -4574,7 +4589,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
4574
4589
|
this.fonts.trackFontsForShape(shape)
|
|
4575
4590
|
return this.getShapeUtil(shape).getGeometry(shape, opts)
|
|
4576
4591
|
},
|
|
4577
|
-
{ areRecordsEqual:
|
|
4592
|
+
{ areRecordsEqual: areShapesContentEqual }
|
|
4578
4593
|
)
|
|
4579
4594
|
}
|
|
4580
4595
|
return this._shapeGeometryCaches[context].get(
|
|
@@ -4622,9 +4637,15 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
4622
4637
|
|
|
4623
4638
|
/** @internal */
|
|
4624
4639
|
@computed private _getShapeHandlesCache(): ComputedCache<TLHandle[] | undefined, TLShape> {
|
|
4625
|
-
return this.store.createComputedCache(
|
|
4626
|
-
|
|
4627
|
-
|
|
4640
|
+
return this.store.createComputedCache(
|
|
4641
|
+
'handles',
|
|
4642
|
+
(shape) => {
|
|
4643
|
+
return this.getShapeUtil(shape).getHandles?.(shape)
|
|
4644
|
+
},
|
|
4645
|
+
{
|
|
4646
|
+
areRecordsEqual: areShapesContentEqual,
|
|
4647
|
+
}
|
|
4648
|
+
)
|
|
4628
4649
|
}
|
|
4629
4650
|
|
|
4630
4651
|
/**
|
|
@@ -5845,9 +5866,15 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
5845
5866
|
@computed
|
|
5846
5867
|
private _getBindingsIndexCache() {
|
|
5847
5868
|
const index = bindingsIndex(this)
|
|
5848
|
-
return this.store.createComputedCache<TLBinding[], TLShape>(
|
|
5849
|
-
|
|
5850
|
-
|
|
5869
|
+
return this.store.createComputedCache<TLBinding[], TLShape>(
|
|
5870
|
+
'bindingsIndex',
|
|
5871
|
+
(shape) => {
|
|
5872
|
+
return index.get().get(shape.id)
|
|
5873
|
+
},
|
|
5874
|
+
// we can ignore the shape equality check here because the index is
|
|
5875
|
+
// computed incrementally based on what bindings are in the store
|
|
5876
|
+
{ areRecordsEqual: () => true }
|
|
5877
|
+
)
|
|
5851
5878
|
}
|
|
5852
5879
|
|
|
5853
5880
|
/**
|
|
@@ -10214,7 +10241,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
10214
10241
|
|
|
10215
10242
|
// If the camera behavior is "zoom" and the ctrl key is pressed, then pan;
|
|
10216
10243
|
// If the camera behavior is "pan" and the ctrl key is not pressed, then zoom
|
|
10217
|
-
if (
|
|
10244
|
+
if (info.ctrlKey) behavior = wheelBehavior === 'pan' ? 'zoom' : 'pan'
|
|
10218
10245
|
|
|
10219
10246
|
switch (behavior) {
|
|
10220
10247
|
case 'zoom': {
|
|
@@ -10330,12 +10357,10 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
10330
10357
|
if (this.inputs.isPanning && this.inputs.isPointing) {
|
|
10331
10358
|
// Handle spacebar / middle mouse button panning
|
|
10332
10359
|
const { currentScreenPoint, previousScreenPoint } = this.inputs
|
|
10333
|
-
const { panSpeed } = cameraOptions
|
|
10334
10360
|
const offset = Vec.Sub(currentScreenPoint, previousScreenPoint)
|
|
10335
|
-
this.setCamera(
|
|
10336
|
-
|
|
10337
|
-
|
|
10338
|
-
)
|
|
10361
|
+
this.setCamera(new Vec(cx + offset.x / cz, cy + offset.y / cz, cz), {
|
|
10362
|
+
immediate: true,
|
|
10363
|
+
})
|
|
10339
10364
|
this.maybeTrackPerformance('Panning')
|
|
10340
10365
|
return
|
|
10341
10366
|
}
|
|
@@ -32,6 +32,7 @@ export interface TLMeasureTextSpanOpts {
|
|
|
32
32
|
fontStyle: string
|
|
33
33
|
lineHeight: number
|
|
34
34
|
textAlign: TLDefaultHorizontalAlignStyle
|
|
35
|
+
otherStyles?: Record<string, string>
|
|
35
36
|
}
|
|
36
37
|
|
|
37
38
|
const spaceCharacterRegex = /\s/
|
|
@@ -86,6 +87,7 @@ export class TextManager {
|
|
|
86
87
|
*/
|
|
87
88
|
maxWidth: null | number
|
|
88
89
|
minWidth?: null | number
|
|
90
|
+
otherStyles?: Record<string, string>
|
|
89
91
|
padding: string
|
|
90
92
|
disableOverflowWrapBreaking?: boolean
|
|
91
93
|
}
|
|
@@ -112,6 +114,11 @@ export class TextManager {
|
|
|
112
114
|
'overflow-wrap',
|
|
113
115
|
opts.disableOverflowWrapBreaking ? 'normal' : 'break-word'
|
|
114
116
|
)
|
|
117
|
+
if (opts.otherStyles) {
|
|
118
|
+
for (const [key, value] of Object.entries(opts.otherStyles)) {
|
|
119
|
+
wrapperElm.style.setProperty(key, value)
|
|
120
|
+
}
|
|
121
|
+
}
|
|
115
122
|
|
|
116
123
|
const scrollWidth = wrapperElm.scrollWidth
|
|
117
124
|
const rect = wrapperElm.getBoundingClientRect()
|
|
@@ -256,6 +263,11 @@ export class TextManager {
|
|
|
256
263
|
elm.style.setProperty('line-height', `${opts.lineHeight * opts.fontSize}px`)
|
|
257
264
|
elm.style.setProperty('text-align', textAlignmentsForLtr[opts.textAlign])
|
|
258
265
|
elm.style.setProperty('font-style', opts.fontStyle)
|
|
266
|
+
if (opts.otherStyles) {
|
|
267
|
+
for (const [key, value] of Object.entries(opts.otherStyles)) {
|
|
268
|
+
elm.style.setProperty(key, value)
|
|
269
|
+
}
|
|
270
|
+
}
|
|
259
271
|
|
|
260
272
|
const shouldTruncateToFirstLine =
|
|
261
273
|
opts.overflow === 'truncate-ellipsis' || opts.overflow === 'truncate-clip'
|
|
@@ -19,6 +19,7 @@ import { TLFontFace } from '../managers/FontManager'
|
|
|
19
19
|
import { BoundsSnapGeometry } from '../managers/SnapManager/BoundsSnaps'
|
|
20
20
|
import { HandleSnapGeometry } from '../managers/SnapManager/HandleSnaps'
|
|
21
21
|
import { SvgExportContext } from '../types/SvgExportContext'
|
|
22
|
+
import { TLClickEventInfo } from '../types/event-types'
|
|
22
23
|
import { TLResizeHandle } from '../types/selection-types'
|
|
23
24
|
|
|
24
25
|
/** @public */
|
|
@@ -671,10 +672,21 @@ export abstract class ShapeUtil<Shape extends TLUnknownShape = TLUnknownShape> {
|
|
|
671
672
|
* A callback called when a shape's edge is double clicked.
|
|
672
673
|
*
|
|
673
674
|
* @param shape - The shape.
|
|
675
|
+
* @param info - Info about the edge.
|
|
674
676
|
* @returns A change to apply to the shape, or void.
|
|
675
677
|
* @public
|
|
676
678
|
*/
|
|
677
|
-
onDoubleClickEdge?(shape: Shape): TLShapePartial<Shape> | void
|
|
679
|
+
onDoubleClickEdge?(shape: Shape, info: TLClickEventInfo): TLShapePartial<Shape> | void
|
|
680
|
+
|
|
681
|
+
/**
|
|
682
|
+
* A callback called when a shape's corner is double clicked.
|
|
683
|
+
*
|
|
684
|
+
* @param shape - The shape.
|
|
685
|
+
* @param info - Info about the corner.
|
|
686
|
+
* @returns A change to apply to the shape, or void.
|
|
687
|
+
* @public
|
|
688
|
+
*/
|
|
689
|
+
onDoubleClickCorner?(shape: Shape, info: TLClickEventInfo): TLShapePartial<Shape> | void
|
|
678
690
|
|
|
679
691
|
/**
|
|
680
692
|
* A callback called when a shape is double clicked.
|
|
@@ -695,7 +707,15 @@ export abstract class ShapeUtil<Shape extends TLUnknownShape = TLUnknownShape> {
|
|
|
695
707
|
onClick?(shape: Shape): TLShapePartial<Shape> | void
|
|
696
708
|
|
|
697
709
|
/**
|
|
698
|
-
* A callback called when a shape
|
|
710
|
+
* A callback called when a shape starts being edited.
|
|
711
|
+
*
|
|
712
|
+
* @param shape - The shape.
|
|
713
|
+
* @public
|
|
714
|
+
*/
|
|
715
|
+
onEditStart?(shape: Shape): void
|
|
716
|
+
|
|
717
|
+
/**
|
|
718
|
+
* A callback called when a shape finishes being edited.
|
|
699
719
|
*
|
|
700
720
|
* @param shape - The shape.
|
|
701
721
|
* @public
|
|
@@ -4,15 +4,15 @@ import { TLDefaultDashStyle } from '@tldraw/tlschema'
|
|
|
4
4
|
export function getPerfectDashProps(
|
|
5
5
|
totalLength: number,
|
|
6
6
|
strokeWidth: number,
|
|
7
|
-
opts
|
|
8
|
-
style
|
|
9
|
-
snap
|
|
10
|
-
end
|
|
11
|
-
start
|
|
12
|
-
lengthRatio
|
|
13
|
-
closed
|
|
14
|
-
forceSolid
|
|
15
|
-
}
|
|
7
|
+
opts: {
|
|
8
|
+
style?: TLDefaultDashStyle
|
|
9
|
+
snap?: number
|
|
10
|
+
end?: 'skip' | 'outset' | 'none'
|
|
11
|
+
start?: 'skip' | 'outset' | 'none'
|
|
12
|
+
lengthRatio?: number
|
|
13
|
+
closed?: boolean
|
|
14
|
+
forceSolid?: boolean
|
|
15
|
+
} = {}
|
|
16
16
|
): {
|
|
17
17
|
strokeDasharray: string
|
|
18
18
|
strokeDashoffset: string
|
|
@@ -365,6 +365,21 @@ function SvgExport({
|
|
|
365
365
|
onMount()
|
|
366
366
|
}, [onMount, shapeElements])
|
|
367
367
|
|
|
368
|
+
let backgroundColor = background ? theme.background : 'transparent'
|
|
369
|
+
|
|
370
|
+
if (singleFrameShapeId && background) {
|
|
371
|
+
const frameShapeUtil = editor.getShapeUtil('frame') as any as
|
|
372
|
+
| undefined
|
|
373
|
+
| { options: { showColors: boolean } }
|
|
374
|
+
if (frameShapeUtil?.options.showColors) {
|
|
375
|
+
const shape = editor.getShape(singleFrameShapeId)! as TLFrameShape
|
|
376
|
+
const color = theme[shape.props.color]
|
|
377
|
+
backgroundColor = color.frame.fill
|
|
378
|
+
} else {
|
|
379
|
+
backgroundColor = theme.solid
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
|
|
368
383
|
return (
|
|
369
384
|
<SvgExportContextProvider editor={editor} context={exportContext}>
|
|
370
385
|
<svg
|
|
@@ -375,13 +390,7 @@ function SvgExport({
|
|
|
375
390
|
viewBox={`${bbox.minX} ${bbox.minY} ${bbox.width} ${bbox.height}`}
|
|
376
391
|
strokeLinecap="round"
|
|
377
392
|
strokeLinejoin="round"
|
|
378
|
-
style={{
|
|
379
|
-
backgroundColor: background
|
|
380
|
-
? singleFrameShapeId
|
|
381
|
-
? theme.solid
|
|
382
|
-
: theme.background
|
|
383
|
-
: 'transparent',
|
|
384
|
-
}}
|
|
393
|
+
style={{ backgroundColor }}
|
|
385
394
|
data-color-mode={isDarkMode ? 'dark' : 'light'}
|
|
386
395
|
className={`tl-container tl-theme__force-sRGB ${isDarkMode ? 'tl-theme__dark' : 'tl-theme__light'}`}
|
|
387
396
|
>
|
|
@@ -11,6 +11,7 @@ export function useDocumentEvents() {
|
|
|
11
11
|
const editor = useEditor()
|
|
12
12
|
const container = useContainer()
|
|
13
13
|
|
|
14
|
+
const isEditing = useValue('isEditing', () => editor.getEditingShapeId(), [editor])
|
|
14
15
|
const isAppFocused = useValue('isFocused', () => editor.getIsFocused(), [editor])
|
|
15
16
|
|
|
16
17
|
// Prevent the browser's default drag and drop behavior on our container (UI, etc)
|
|
@@ -125,7 +126,11 @@ export function useDocumentEvents() {
|
|
|
125
126
|
if (areShortcutsDisabled(editor)) {
|
|
126
127
|
return
|
|
127
128
|
}
|
|
128
|
-
|
|
129
|
+
// isEditing here sounds like it's about text editing
|
|
130
|
+
// but more specifically, this is so you can tab into an
|
|
131
|
+
// embed that's being 'edited'. In our world,
|
|
132
|
+
// editing an embed, means it's interactive.
|
|
133
|
+
if (hasSelectedShapes && !isEditing) {
|
|
129
134
|
// This is used in tandem with shape navigation.
|
|
130
135
|
preventDefault(e)
|
|
131
136
|
}
|
|
@@ -289,7 +294,7 @@ export function useDocumentEvents() {
|
|
|
289
294
|
container.removeEventListener('keydown', handleKeyDown)
|
|
290
295
|
container.removeEventListener('keyup', handleKeyUp)
|
|
291
296
|
}
|
|
292
|
-
}, [editor, container, isAppFocused])
|
|
297
|
+
}, [editor, container, isAppFocused, isEditing])
|
|
293
298
|
}
|
|
294
299
|
|
|
295
300
|
function areShortcutsDisabled(editor: Editor) {
|
|
@@ -51,29 +51,30 @@ import { useShallowObjectIdentity } from './useIdentity'
|
|
|
51
51
|
/** @public */
|
|
52
52
|
export interface TLEditorComponents {
|
|
53
53
|
Background?: ComponentType | null
|
|
54
|
-
SvgDefs?: ComponentType | null
|
|
55
54
|
Brush?: ComponentType<TLBrushProps> | null
|
|
56
|
-
ZoomBrush?: ComponentType<TLBrushProps> | null
|
|
57
|
-
ShapeIndicators?: ComponentType | null
|
|
58
|
-
ShapeIndicator?: ComponentType<TLShapeIndicatorProps> | null
|
|
59
|
-
Cursor?: ComponentType<TLCursorProps> | null
|
|
60
55
|
Canvas?: ComponentType<TLCanvasComponentProps> | null
|
|
61
56
|
CollaboratorBrush?: ComponentType<TLBrushProps> | null
|
|
62
57
|
CollaboratorCursor?: ComponentType<TLCursorProps> | null
|
|
63
58
|
CollaboratorHint?: ComponentType<TLCollaboratorHintProps> | null
|
|
59
|
+
CollaboratorScribble?: ComponentType<TLScribbleProps> | null
|
|
64
60
|
CollaboratorShapeIndicator?: ComponentType<TLShapeIndicatorProps> | null
|
|
61
|
+
Cursor?: ComponentType<TLCursorProps> | null
|
|
65
62
|
Grid?: ComponentType<TLGridProps> | null
|
|
66
|
-
Scribble?: ComponentType<TLScribbleProps> | null
|
|
67
|
-
CollaboratorScribble?: ComponentType<TLScribbleProps> | null
|
|
68
|
-
SnapIndicator?: ComponentType<TLSnapIndicatorProps> | null
|
|
69
|
-
Handles?: ComponentType<TLHandlesProps> | null
|
|
70
63
|
Handle?: ComponentType<TLHandleProps> | null
|
|
71
|
-
|
|
72
|
-
SelectionForeground?: ComponentType<TLSelectionForegroundProps> | null
|
|
73
|
-
SelectionBackground?: ComponentType<TLSelectionBackgroundProps> | null
|
|
74
|
-
OnTheCanvas?: ComponentType | null
|
|
64
|
+
Handles?: ComponentType<TLHandlesProps> | null
|
|
75
65
|
InFrontOfTheCanvas?: ComponentType | null
|
|
76
66
|
LoadingScreen?: ComponentType | null
|
|
67
|
+
OnTheCanvas?: ComponentType | null
|
|
68
|
+
Overlays?: ComponentType | null
|
|
69
|
+
Scribble?: ComponentType<TLScribbleProps> | null
|
|
70
|
+
SelectionBackground?: ComponentType<TLSelectionBackgroundProps> | null
|
|
71
|
+
SelectionForeground?: ComponentType<TLSelectionForegroundProps> | null
|
|
72
|
+
ShapeIndicator?: ComponentType<TLShapeIndicatorProps> | null
|
|
73
|
+
ShapeIndicators?: ComponentType | null
|
|
74
|
+
SnapIndicator?: ComponentType<TLSnapIndicatorProps> | null
|
|
75
|
+
Spinner?: ComponentType | null
|
|
76
|
+
SvgDefs?: ComponentType | null
|
|
77
|
+
ZoomBrush?: ComponentType<TLBrushProps> | null
|
|
77
78
|
|
|
78
79
|
// These will always have defaults
|
|
79
80
|
ErrorFallback?: TLErrorFallbackComponent
|
|
@@ -96,32 +97,35 @@ export function EditorComponentsProvider({
|
|
|
96
97
|
const value = useMemo(
|
|
97
98
|
(): Required<TLEditorComponents> => ({
|
|
98
99
|
Background: DefaultBackground,
|
|
99
|
-
SvgDefs: DefaultSvgDefs,
|
|
100
100
|
Brush: DefaultBrush,
|
|
101
|
-
|
|
101
|
+
Canvas: DefaultCanvas,
|
|
102
102
|
CollaboratorBrush: DefaultBrush,
|
|
103
|
-
Cursor: DefaultCursor,
|
|
104
103
|
CollaboratorCursor: DefaultCursor,
|
|
105
104
|
CollaboratorHint: DefaultCollaboratorHint,
|
|
105
|
+
CollaboratorScribble: DefaultScribble,
|
|
106
106
|
CollaboratorShapeIndicator: DefaultShapeIndicator,
|
|
107
|
+
Cursor: DefaultCursor,
|
|
107
108
|
Grid: DefaultGrid,
|
|
109
|
+
Handle: DefaultHandle,
|
|
110
|
+
Handles: DefaultHandles,
|
|
111
|
+
InFrontOfTheCanvas: null,
|
|
112
|
+
LoadingScreen: DefaultLoadingScreen,
|
|
113
|
+
OnTheCanvas: null,
|
|
114
|
+
Overlays: null,
|
|
108
115
|
Scribble: DefaultScribble,
|
|
116
|
+
SelectionBackground: DefaultSelectionBackground,
|
|
117
|
+
SelectionForeground: DefaultSelectionForeground,
|
|
118
|
+
ShapeIndicator: DefaultShapeIndicator,
|
|
119
|
+
ShapeIndicators: DefaultShapeIndicators,
|
|
109
120
|
SnapIndicator: DefaultSnapIndicator,
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
121
|
+
Spinner: DefaultSpinner,
|
|
122
|
+
SvgDefs: DefaultSvgDefs,
|
|
123
|
+
ZoomBrush: DefaultBrush,
|
|
124
|
+
|
|
113
125
|
ErrorFallback: DefaultErrorFallback,
|
|
114
126
|
ShapeErrorFallback: DefaultShapeErrorFallback,
|
|
115
127
|
ShapeIndicatorErrorFallback: DefaultShapeIndicatorErrorFallback,
|
|
116
|
-
|
|
117
|
-
SelectionBackground: DefaultSelectionBackground,
|
|
118
|
-
SelectionForeground: DefaultSelectionForeground,
|
|
119
|
-
ShapeIndicators: DefaultShapeIndicators,
|
|
120
|
-
ShapeIndicator: DefaultShapeIndicator,
|
|
121
|
-
OnTheCanvas: null,
|
|
122
|
-
InFrontOfTheCanvas: null,
|
|
123
|
-
Canvas: DefaultCanvas,
|
|
124
|
-
LoadingScreen: DefaultLoadingScreen,
|
|
128
|
+
|
|
125
129
|
..._overrides,
|
|
126
130
|
}),
|
|
127
131
|
[_overrides]
|
package/src/lib/options.ts
CHANGED
|
@@ -80,6 +80,10 @@ export interface TldrawOptions {
|
|
|
80
80
|
* nonce to use in the editor's styles.
|
|
81
81
|
*/
|
|
82
82
|
readonly nonce: string | undefined
|
|
83
|
+
/**
|
|
84
|
+
* Branding name of the app, currently only used for adding aria-label for the application.
|
|
85
|
+
*/
|
|
86
|
+
readonly branding?: string
|
|
83
87
|
}
|
|
84
88
|
|
|
85
89
|
/** @public */
|
|
@@ -57,6 +57,11 @@ export class Box {
|
|
|
57
57
|
this.x = n
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
+
// eslint-disable-next-line no-restricted-syntax
|
|
61
|
+
get left() {
|
|
62
|
+
return this.x
|
|
63
|
+
}
|
|
64
|
+
|
|
60
65
|
// eslint-disable-next-line no-restricted-syntax
|
|
61
66
|
get midX() {
|
|
62
67
|
return this.x + this.w / 2
|
|
@@ -67,6 +72,11 @@ export class Box {
|
|
|
67
72
|
return this.x + this.w
|
|
68
73
|
}
|
|
69
74
|
|
|
75
|
+
// eslint-disable-next-line no-restricted-syntax
|
|
76
|
+
get right() {
|
|
77
|
+
return this.x + this.w
|
|
78
|
+
}
|
|
79
|
+
|
|
70
80
|
// eslint-disable-next-line no-restricted-syntax
|
|
71
81
|
get minY() {
|
|
72
82
|
return this.y
|
|
@@ -77,6 +87,11 @@ export class Box {
|
|
|
77
87
|
this.y = n
|
|
78
88
|
}
|
|
79
89
|
|
|
90
|
+
// eslint-disable-next-line no-restricted-syntax
|
|
91
|
+
get top() {
|
|
92
|
+
return this.y
|
|
93
|
+
}
|
|
94
|
+
|
|
80
95
|
// eslint-disable-next-line no-restricted-syntax
|
|
81
96
|
get midY() {
|
|
82
97
|
return this.y + this.h / 2
|
|
@@ -87,6 +102,11 @@ export class Box {
|
|
|
87
102
|
return this.y + this.h
|
|
88
103
|
}
|
|
89
104
|
|
|
105
|
+
// eslint-disable-next-line no-restricted-syntax
|
|
106
|
+
get bottom() {
|
|
107
|
+
return this.y + this.h
|
|
108
|
+
}
|
|
109
|
+
|
|
90
110
|
// eslint-disable-next-line no-restricted-syntax
|
|
91
111
|
get width() {
|
|
92
112
|
return this.w
|
|
@@ -157,12 +157,13 @@ export class Mat {
|
|
|
157
157
|
return Mat.Compose(Mat.Translate(cx, cy!), rotationMatrix, Mat.Translate(-cx, -cy!))
|
|
158
158
|
}
|
|
159
159
|
|
|
160
|
-
static Scale(x: number, y: number):
|
|
161
|
-
static Scale(x: number, y: number, cx: number, cy: number):
|
|
162
|
-
static Scale(x: number, y: number, cx?: number, cy?: number):
|
|
160
|
+
static Scale(x: number, y: number): Mat
|
|
161
|
+
static Scale(x: number, y: number, cx: number, cy: number): Mat
|
|
162
|
+
static Scale(x: number, y: number, cx?: number, cy?: number): Mat {
|
|
163
163
|
const scaleMatrix = new Mat(x, 0, 0, y, 0, 0)
|
|
164
164
|
if (cx === undefined) return scaleMatrix
|
|
165
|
-
|
|
165
|
+
|
|
166
|
+
return Mat.Translate(cx, cy!).multiply(scaleMatrix).translate(-cx, -cy!)
|
|
166
167
|
}
|
|
167
168
|
static Multiply(m1: MatModel, m2: MatModel): MatModel {
|
|
168
169
|
return {
|