No impure getters pt6 (#2218)

follow up to #2189 

### Change Type

- [x] `patch` — Bug fix
This commit is contained in:
David Sheldrick 2023-11-14 11:57:43 +00:00 committed by GitHub
parent 25e7bf30c9
commit 6f872c796a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
61 changed files with 493 additions and 259 deletions

View file

@ -763,6 +763,11 @@ export class Editor extends EventEmitter<TLEventMap> {
darkMode?: boolean | undefined; darkMode?: boolean | undefined;
preserveAspectRatio: React.SVGAttributes<SVGSVGElement>['preserveAspectRatio']; preserveAspectRatio: React.SVGAttributes<SVGSVGElement>['preserveAspectRatio'];
}>): Promise<SVGSVGElement | undefined>; }>): Promise<SVGSVGElement | undefined>;
getViewportPageBounds(): Box2d;
getViewportPageCenter(): Vec2d;
getViewportScreenBounds(): Box2d;
getViewportScreenCenter(): Vec2d;
getZoomLevel(): number;
groupShapes(shapes: TLShape[] | TLShapeId[], groupId?: TLShapeId): this; groupShapes(shapes: TLShape[] | TLShapeId[], groupId?: TLShapeId): this;
hasAncestor(shape: TLShape | TLShapeId | undefined, ancestorId: TLShapeId): boolean; hasAncestor(shape: TLShape | TLShapeId | undefined, ancestorId: TLShapeId): boolean;
// @deprecated (undocumented) // @deprecated (undocumented)
@ -941,12 +946,17 @@ export class Editor extends EventEmitter<TLEventMap> {
updateShapes<T extends TLUnknownShape>(partials: (null | TLShapePartial<T> | undefined)[], historyOptions?: TLCommandHistoryOptions): this; updateShapes<T extends TLUnknownShape>(partials: (null | TLShapePartial<T> | undefined)[], historyOptions?: TLCommandHistoryOptions): this;
updateViewportScreenBounds(center?: boolean): this; updateViewportScreenBounds(center?: boolean): this;
readonly user: UserPreferencesManager; readonly user: UserPreferencesManager;
// @deprecated (undocumented)
get viewportPageBounds(): Box2d; get viewportPageBounds(): Box2d;
// @deprecated (undocumented)
get viewportPageCenter(): Vec2d; get viewportPageCenter(): Vec2d;
// @deprecated (undocumented)
get viewportScreenBounds(): Box2d; get viewportScreenBounds(): Box2d;
// @deprecated (undocumented)
get viewportScreenCenter(): Vec2d; get viewportScreenCenter(): Vec2d;
visitDescendants(parent: TLPage | TLParentId | TLShape, visitor: (id: TLShapeId) => false | void): this; visitDescendants(parent: TLPage | TLParentId | TLShape, visitor: (id: TLShapeId) => false | void): this;
zoomIn(point?: Vec2d, animation?: TLAnimationOptions): this; zoomIn(point?: Vec2d, animation?: TLAnimationOptions): this;
// @deprecated (undocumented)
get zoomLevel(): number; get zoomLevel(): number;
zoomOut(point?: Vec2d, animation?: TLAnimationOptions): this; zoomOut(point?: Vec2d, animation?: TLAnimationOptions): this;
zoomToBounds(bounds: Box2d, targetZoom?: number, animation?: TLAnimationOptions): this; zoomToBounds(bounds: Box2d, targetZoom?: number, animation?: TLAnimationOptions): this;

View file

@ -13275,6 +13275,165 @@
"isAbstract": false, "isAbstract": false,
"name": "getSvg" "name": "getSvg"
}, },
{
"kind": "Method",
"canonicalReference": "@tldraw/editor!Editor#getViewportPageBounds:member(1)",
"docComment": "/**\n * The current viewport in the current page space.\n *\n * @public\n */\n",
"excerptTokens": [
{
"kind": "Content",
"text": "getViewportPageBounds(): "
},
{
"kind": "Reference",
"text": "Box2d",
"canonicalReference": "@tldraw/editor!Box2d:class"
},
{
"kind": "Content",
"text": ";"
}
],
"isStatic": false,
"returnTypeTokenRange": {
"startIndex": 1,
"endIndex": 2
},
"releaseTag": "Public",
"isProtected": false,
"overloadIndex": 1,
"parameters": [],
"isOptional": false,
"isAbstract": false,
"name": "getViewportPageBounds"
},
{
"kind": "Method",
"canonicalReference": "@tldraw/editor!Editor#getViewportPageCenter:member(1)",
"docComment": "/**\n * The center of the viewport in the current page space.\n *\n * @public\n */\n",
"excerptTokens": [
{
"kind": "Content",
"text": "getViewportPageCenter(): "
},
{
"kind": "Reference",
"text": "Vec2d",
"canonicalReference": "@tldraw/editor!Vec2d:class"
},
{
"kind": "Content",
"text": ";"
}
],
"isStatic": false,
"returnTypeTokenRange": {
"startIndex": 1,
"endIndex": 2
},
"releaseTag": "Public",
"isProtected": false,
"overloadIndex": 1,
"parameters": [],
"isOptional": false,
"isAbstract": false,
"name": "getViewportPageCenter"
},
{
"kind": "Method",
"canonicalReference": "@tldraw/editor!Editor#getViewportScreenBounds:member(1)",
"docComment": "/**\n * The bounds of the editor's viewport in screen space.\n *\n * @public\n */\n",
"excerptTokens": [
{
"kind": "Content",
"text": "getViewportScreenBounds(): "
},
{
"kind": "Reference",
"text": "Box2d",
"canonicalReference": "@tldraw/editor!Box2d:class"
},
{
"kind": "Content",
"text": ";"
}
],
"isStatic": false,
"returnTypeTokenRange": {
"startIndex": 1,
"endIndex": 2
},
"releaseTag": "Public",
"isProtected": false,
"overloadIndex": 1,
"parameters": [],
"isOptional": false,
"isAbstract": false,
"name": "getViewportScreenBounds"
},
{
"kind": "Method",
"canonicalReference": "@tldraw/editor!Editor#getViewportScreenCenter:member(1)",
"docComment": "/**\n * The center of the editor's viewport in screen space.\n *\n * @public\n */\n",
"excerptTokens": [
{
"kind": "Content",
"text": "getViewportScreenCenter(): "
},
{
"kind": "Reference",
"text": "Vec2d",
"canonicalReference": "@tldraw/editor!Vec2d:class"
},
{
"kind": "Content",
"text": ";"
}
],
"isStatic": false,
"returnTypeTokenRange": {
"startIndex": 1,
"endIndex": 2
},
"releaseTag": "Public",
"isProtected": false,
"overloadIndex": 1,
"parameters": [],
"isOptional": false,
"isAbstract": false,
"name": "getViewportScreenCenter"
},
{
"kind": "Method",
"canonicalReference": "@tldraw/editor!Editor#getZoomLevel:member(1)",
"docComment": "/**\n * The current camera zoom level.\n *\n * @public\n */\n",
"excerptTokens": [
{
"kind": "Content",
"text": "getZoomLevel(): "
},
{
"kind": "Content",
"text": "number"
},
{
"kind": "Content",
"text": ";"
}
],
"isStatic": false,
"returnTypeTokenRange": {
"startIndex": 1,
"endIndex": 2
},
"releaseTag": "Public",
"isProtected": false,
"overloadIndex": 1,
"parameters": [],
"isOptional": false,
"isAbstract": false,
"name": "getZoomLevel"
},
{ {
"kind": "Method", "kind": "Method",
"canonicalReference": "@tldraw/editor!Editor#groupShapes:member(1)", "canonicalReference": "@tldraw/editor!Editor#groupShapes:member(1)",
@ -19125,7 +19284,7 @@
{ {
"kind": "Property", "kind": "Property",
"canonicalReference": "@tldraw/editor!Editor#viewportPageBounds:member", "canonicalReference": "@tldraw/editor!Editor#viewportPageBounds:member",
"docComment": "/**\n * The current viewport in the current page space.\n *\n * @public\n */\n", "docComment": "/**\n * @deprecated\n *\n * Use `getViewportPageBounds` instead.\n */\n",
"excerptTokens": [ "excerptTokens": [
{ {
"kind": "Content", "kind": "Content",
@ -19156,7 +19315,7 @@
{ {
"kind": "Property", "kind": "Property",
"canonicalReference": "@tldraw/editor!Editor#viewportPageCenter:member", "canonicalReference": "@tldraw/editor!Editor#viewportPageCenter:member",
"docComment": "/**\n * The center of the viewport in the current page space.\n *\n * @public\n */\n", "docComment": "/**\n * @deprecated\n *\n * Use `getViewportPageCenter` instead.\n */\n",
"excerptTokens": [ "excerptTokens": [
{ {
"kind": "Content", "kind": "Content",
@ -19187,7 +19346,7 @@
{ {
"kind": "Property", "kind": "Property",
"canonicalReference": "@tldraw/editor!Editor#viewportScreenBounds:member", "canonicalReference": "@tldraw/editor!Editor#viewportScreenBounds:member",
"docComment": "/**\n * The bounds of the editor's viewport in screen space.\n *\n * @public\n */\n", "docComment": "/**\n * @deprecated\n *\n * Use `getViewportScreenBounds` instead.\n */\n",
"excerptTokens": [ "excerptTokens": [
{ {
"kind": "Content", "kind": "Content",
@ -19218,7 +19377,7 @@
{ {
"kind": "Property", "kind": "Property",
"canonicalReference": "@tldraw/editor!Editor#viewportScreenCenter:member", "canonicalReference": "@tldraw/editor!Editor#viewportScreenCenter:member",
"docComment": "/**\n * The center of the editor's viewport in screen space.\n *\n * @public\n */\n", "docComment": "/**\n * @deprecated\n *\n * Use `getViewportScreenCenter` instead.\n */\n",
"excerptTokens": [ "excerptTokens": [
{ {
"kind": "Content", "kind": "Content",
@ -19407,7 +19566,7 @@
{ {
"kind": "Property", "kind": "Property",
"canonicalReference": "@tldraw/editor!Editor#zoomLevel:member", "canonicalReference": "@tldraw/editor!Editor#zoomLevel:member",
"docComment": "/**\n * The current camera zoom level.\n *\n * @public\n */\n", "docComment": "/**\n * @deprecated\n *\n * Use `getZoomLevel` instead.\n */\n",
"excerptTokens": [ "excerptTokens": [
{ {
"kind": "Content", "kind": "Content",

View file

@ -148,7 +148,7 @@ function GridWrapper() {
function ScribbleWrapper() { function ScribbleWrapper() {
const editor = useEditor() const editor = useEditor()
const scribbles = useValue('scribbles', () => editor.getInstanceState().scribbles, [editor]) const scribbles = useValue('scribbles', () => editor.getInstanceState().scribbles, [editor])
const zoomLevel = useValue('zoomLevel', () => editor.zoomLevel, [editor]) const zoomLevel = useValue('zoomLevel', () => editor.getZoomLevel(), [editor])
const { Scribble } = useEditorComponents() const { Scribble } = useEditorComponents()
if (!(Scribble && scribbles.length)) return null if (!(Scribble && scribbles.length)) return null
@ -190,7 +190,7 @@ function ZoomBrushWrapper() {
function SnapLinesWrapper() { function SnapLinesWrapper() {
const editor = useEditor() const editor = useEditor()
const lines = useValue('snapLines', () => editor.snaps.lines, [editor]) const lines = useValue('snapLines', () => editor.snaps.lines, [editor])
const zoomLevel = useValue('zoomLevel', () => editor.zoomLevel, [editor]) const zoomLevel = useValue('zoomLevel', () => editor.getZoomLevel(), [editor])
const { SnapLine } = useEditorComponents() const { SnapLine } = useEditorComponents()
if (!(SnapLine && lines.length > 0)) return null if (!(SnapLine && lines.length > 0)) return null
@ -210,7 +210,7 @@ function HandlesWrapper() {
const editor = useEditor() const editor = useEditor()
const { Handles } = useEditorComponents() const { Handles } = useEditorComponents()
const zoomLevel = useValue('zoomLevel', () => editor.zoomLevel, [editor]) const zoomLevel = useValue('zoomLevel', () => editor.getZoomLevel(), [editor])
const isCoarse = useValue('coarse pointer', () => editor.getInstanceState().isCoarsePointer, [ const isCoarse = useValue('coarse pointer', () => editor.getInstanceState().isCoarsePointer, [
editor, editor,
]) ])

View file

@ -29,8 +29,8 @@ export const GeometryDebuggingView = track(function GeometryDebuggingView({
useTick(showClosestPointOnOutline) useTick(showClosestPointOnOutline)
const zoomLevel = editor.getZoomLevel()
const { const {
zoomLevel,
renderingShapes, renderingShapes,
inputs: { currentPagePoint }, inputs: { currentPagePoint },
} = editor } = editor

View file

@ -80,7 +80,8 @@ const Collaborator = track(function Collaborator({
CollaboratorShapeIndicator, CollaboratorShapeIndicator,
} = useEditorComponents() } = useEditorComponents()
const { viewportPageBounds, zoomLevel } = editor const zoomLevel = editor.getZoomLevel()
const viewportPageBounds = editor.getViewportPageBounds()
const { userId, chatMessage, brush, scribbles, selectedShapeIds, userName, cursor, color } = const { userId, chatMessage, brush, scribbles, selectedShapeIds, userName, cursor, color } =
latestPresence latestPresence

View file

@ -2208,10 +2208,17 @@ export class Editor extends EventEmitter<TLEventMap> {
* *
* @public * @public
*/ */
@computed get zoomLevel() { @computed getZoomLevel() {
return this.getCamera().z return this.getCamera().z
} }
/**
* @deprecated Use `getZoomLevel` instead.
*/
get zoomLevel() {
return this.getZoomLevel()
}
/** @internal */ /** @internal */
private _setCamera(point: VecLike): this { private _setCamera(point: VecLike): this {
const currentCamera = this.getCamera() const currentCamera = this.getCamera()
@ -2264,7 +2271,7 @@ export class Editor extends EventEmitter<TLEventMap> {
setCamera(point: VecLike, animation?: TLAnimationOptions): this { setCamera(point: VecLike, animation?: TLAnimationOptions): this {
const x = Number.isFinite(point.x) ? point.x : 0 const x = Number.isFinite(point.x) ? point.x : 0
const y = Number.isFinite(point.y) ? point.y : 0 const y = Number.isFinite(point.y) ? point.y : 0
const z = Number.isFinite(point.z) ? point.z! : this.zoomLevel const z = Number.isFinite(point.z) ? point.z! : this.getZoomLevel()
// Stop any camera animations // Stop any camera animations
this.stopCameraAnimation() this.stopCameraAnimation()
@ -2275,7 +2282,7 @@ export class Editor extends EventEmitter<TLEventMap> {
} }
if (animation) { if (animation) {
const { width, height } = this.viewportScreenBounds const { width, height } = this.getViewportScreenBounds()
return this._animateToViewport(new Box2d(-x, -y, width / z, height / z), animation) return this._animateToViewport(new Box2d(-x, -y, width / z, height / z), animation)
} else { } else {
this._setCamera({ x, y, z }) this._setCamera({ x, y, z })
@ -2301,9 +2308,7 @@ export class Editor extends EventEmitter<TLEventMap> {
centerOnPoint(point: VecLike, animation?: TLAnimationOptions): this { centerOnPoint(point: VecLike, animation?: TLAnimationOptions): this {
if (!this.getInstanceState().canMoveCamera) return this if (!this.getInstanceState().canMoveCamera) return this
const { const { width: pw, height: ph } = this.getViewportPageBounds()
viewportPageBounds: { width: pw, height: ph },
} = this
this.setCamera( this.setCamera(
{ x: -(point.x - pw / 2), y: -(point.y - ph / 2), z: this.getCamera().z }, { x: -(point.x - pw / 2), y: -(point.y - ph / 2), z: this.getCamera().z },
@ -2329,7 +2334,7 @@ export class Editor extends EventEmitter<TLEventMap> {
const bounds = this.getSelectionPageBounds() ?? this.currentPageBounds const bounds = this.getSelectionPageBounds() ?? this.currentPageBounds
if (bounds) { if (bounds) {
this.zoomToBounds(bounds, Math.min(1, this.zoomLevel), { duration: 220 }) this.zoomToBounds(bounds, Math.min(1, this.getZoomLevel()), { duration: 220 })
} }
return this return this
@ -2374,7 +2379,7 @@ export class Editor extends EventEmitter<TLEventMap> {
* *
* @public * @public
*/ */
resetZoom(point = this.viewportScreenCenter, animation?: TLAnimationOptions): this { resetZoom(point = this.getViewportScreenCenter(), animation?: TLAnimationOptions): this {
if (!this.getInstanceState().canMoveCamera) return this if (!this.getInstanceState().canMoveCamera) return this
const { x: cx, y: cy, z: cz } = this.getCamera() const { x: cx, y: cy, z: cz } = this.getCamera()
@ -2401,7 +2406,7 @@ export class Editor extends EventEmitter<TLEventMap> {
* *
* @public * @public
*/ */
zoomIn(point = this.viewportScreenCenter, animation?: TLAnimationOptions): this { zoomIn(point = this.getViewportScreenCenter(), animation?: TLAnimationOptions): this {
if (!this.getInstanceState().canMoveCamera) return this if (!this.getInstanceState().canMoveCamera) return this
const { x: cx, y: cy, z: cz } = this.getCamera() const { x: cx, y: cy, z: cz } = this.getCamera()
@ -2439,7 +2444,7 @@ export class Editor extends EventEmitter<TLEventMap> {
* *
* @public * @public
*/ */
zoomOut(point = this.viewportScreenCenter, animation?: TLAnimationOptions): this { zoomOut(point = this.getViewportScreenCenter(), animation?: TLAnimationOptions): this {
if (!this.getInstanceState().canMoveCamera) return this if (!this.getInstanceState().canMoveCamera) return this
const { x: cx, y: cy, z: cz } = this.getCamera() const { x: cx, y: cy, z: cz } = this.getCamera()
@ -2486,7 +2491,7 @@ export class Editor extends EventEmitter<TLEventMap> {
const selectionPageBounds = this.getSelectionPageBounds() const selectionPageBounds = this.getSelectionPageBounds()
if (!selectionPageBounds) return this if (!selectionPageBounds) return this
this.zoomToBounds(selectionPageBounds, Math.max(1, this.zoomLevel), animation) this.zoomToBounds(selectionPageBounds, Math.max(1, this.getZoomLevel()), animation)
return this return this
} }
@ -2505,14 +2510,16 @@ export class Editor extends EventEmitter<TLEventMap> {
if (ids.length <= 0) return this if (ids.length <= 0) return this
const selectionBounds = Box2d.Common(compact(ids.map((id) => this.getShapePageBounds(id)))) const selectionBounds = Box2d.Common(compact(ids.map((id) => this.getShapePageBounds(id))))
const { viewportPageBounds } = this const viewportPageBounds = this.getViewportPageBounds()
if (viewportPageBounds.h < selectionBounds.h || viewportPageBounds.w < selectionBounds.w) { if (viewportPageBounds.h < selectionBounds.h || viewportPageBounds.w < selectionBounds.w) {
this.zoomToBounds(selectionBounds, this.getCamera().z, animation) this.zoomToBounds(selectionBounds, this.getCamera().z, animation)
return this return this
} else { } else {
const insetViewport = this.viewportPageBounds.clone().expandBy(-32 / this.zoomLevel) const insetViewport = this.getViewportPageBounds()
.clone()
.expandBy(-32 / this.getZoomLevel())
let offsetX = 0 let offsetX = 0
let offsetY = 0 let offsetY = 0
@ -2562,7 +2569,7 @@ export class Editor extends EventEmitter<TLEventMap> {
zoomToBounds(bounds: Box2d, targetZoom?: number, animation?: TLAnimationOptions): this { zoomToBounds(bounds: Box2d, targetZoom?: number, animation?: TLAnimationOptions): this {
if (!this.getInstanceState().canMoveCamera) return this if (!this.getInstanceState().canMoveCamera) return this
const { viewportScreenBounds } = this const viewportScreenBounds = this.getViewportScreenBounds()
const inset = Math.min(256, viewportScreenBounds.width * 0.28) const inset = Math.min(256, viewportScreenBounds.width * 0.28)
@ -2646,7 +2653,7 @@ export class Editor extends EventEmitter<TLEventMap> {
const { elapsed, easing, duration, start, end } = this._viewportAnimation const { elapsed, easing, duration, start, end } = this._viewportAnimation
if (elapsed > duration) { if (elapsed > duration) {
this._setCamera({ x: -end.x, y: -end.y, z: this.viewportScreenBounds.width / end.width }) this._setCamera({ x: -end.x, y: -end.y, z: this.getViewportScreenBounds().width / end.width })
cancel() cancel()
return return
} }
@ -2658,7 +2665,7 @@ export class Editor extends EventEmitter<TLEventMap> {
const top = start.minY + (end.minY - start.minY) * t const top = start.minY + (end.minY - start.minY) * t
const right = start.maxX + (end.maxX - start.maxX) * t const right = start.maxX + (end.maxX - start.maxX) * t
this._setCamera({ x: -left, y: -top, z: this.viewportScreenBounds.width / (right - left) }) this._setCamera({ x: -left, y: -top, z: this.getViewportScreenBounds().width / (right - left) })
} }
/** @internal */ /** @internal */
@ -2666,8 +2673,8 @@ export class Editor extends EventEmitter<TLEventMap> {
const { duration = 0, easing = EASINGS.easeInOutCubic } = opts const { duration = 0, easing = EASINGS.easeInOutCubic } = opts
const { const {
user: { animationSpeed }, user: { animationSpeed },
viewportPageBounds,
} = this } = this
const viewportPageBounds = this.getViewportPageBounds()
// If we have an existing animation, then stop it; also stop following any user // If we have an existing animation, then stop it; also stop following any user
this.stopCameraAnimation() this.stopCameraAnimation()
@ -2680,7 +2687,7 @@ export class Editor extends EventEmitter<TLEventMap> {
return this._setCamera({ return this._setCamera({
x: -targetViewportPage.x, x: -targetViewportPage.x,
y: -targetViewportPage.y, y: -targetViewportPage.y,
z: this.viewportScreenBounds.width / targetViewportPage.width, z: this.getViewportScreenBounds().width / targetViewportPage.width,
}) })
} }
@ -2811,7 +2818,7 @@ export class Editor extends EventEmitter<TLEventMap> {
animateToShape(shapeId: TLShapeId, opts: TLAnimationOptions = DEFAULT_ANIMATION_OPTIONS): this { animateToShape(shapeId: TLShapeId, opts: TLAnimationOptions = DEFAULT_ANIMATION_OPTIONS): this {
if (!this.getInstanceState().canMoveCamera) return this if (!this.getInstanceState().canMoveCamera) return this
const activeArea = this.viewportScreenBounds.clone().expandBy(-32) const activeArea = this.getViewportScreenBounds().clone().expandBy(-32)
const viewportAspectRatio = activeArea.width / activeArea.height const viewportAspectRatio = activeArea.width / activeArea.height
const shapePageBounds = this.getShapePageBounds(shapeId) const shapePageBounds = this.getShapePageBounds(shapeId)
@ -2869,7 +2876,7 @@ export class Editor extends EventEmitter<TLEventMap> {
Math.max(rect.width, 1), Math.max(rect.width, 1),
Math.max(rect.height, 1) Math.max(rect.height, 1)
) )
const boundsAreEqual = screenBounds.equals(this.viewportScreenBounds) const boundsAreEqual = screenBounds.equals(this.getViewportScreenBounds())
const { _willSetInitialBounds } = this const { _willSetInitialBounds } = this
@ -2886,7 +2893,7 @@ export class Editor extends EventEmitter<TLEventMap> {
} else { } else {
if (center && !this.getInstanceState().followingUserId) { if (center && !this.getInstanceState().followingUserId) {
// Get the page center before the change, make the change, and restore it // Get the page center before the change, make the change, and restore it
const before = this.viewportPageCenter const before = this.getViewportPageCenter()
this.updateInstanceState( this.updateInstanceState(
{ screenBounds: screenBounds.toJson() }, { screenBounds: screenBounds.toJson() },
{ squashing: true, ephemeral: true } { squashing: true, ephemeral: true }
@ -2913,18 +2920,32 @@ export class Editor extends EventEmitter<TLEventMap> {
* *
* @public * @public
*/ */
@computed get viewportScreenBounds() { @computed getViewportScreenBounds() {
const { x, y, w, h } = this.getInstanceState().screenBounds const { x, y, w, h } = this.getInstanceState().screenBounds
return new Box2d(x, y, w, h) return new Box2d(x, y, w, h)
} }
/**
* @deprecated Use `getViewportScreenBounds` instead.
*/
get viewportScreenBounds() {
return this.getViewportScreenBounds()
}
/** /**
* The center of the editor's viewport in screen space. * The center of the editor's viewport in screen space.
* *
* @public * @public
*/ */
@computed get viewportScreenCenter() { @computed getViewportScreenCenter() {
return this.viewportScreenBounds.center return this.getViewportScreenBounds().center
}
/**
* @deprecated Use `getViewportScreenCenter` instead.
*/
get viewportScreenCenter() {
return this.getViewportScreenCenter()
} }
/** /**
@ -2932,19 +2953,33 @@ export class Editor extends EventEmitter<TLEventMap> {
* *
* @public * @public
*/ */
@computed get viewportPageBounds() { @computed getViewportPageBounds() {
const { w, h } = this.viewportScreenBounds const { w, h } = this.getViewportScreenBounds()
const { x: cx, y: cy, z: cz } = this.getCamera() const { x: cx, y: cy, z: cz } = this.getCamera()
return new Box2d(-cx, -cy, w / cz, h / cz) return new Box2d(-cx, -cy, w / cz, h / cz)
} }
/**
* @deprecated Use `getViewportPageBounds` instead.
*/
get viewportPageBounds() {
return this.getViewportPageBounds()
}
/** /**
* The center of the viewport in the current page space. * The center of the viewport in the current page space.
* *
* @public * @public
*/ */
@computed get viewportPageCenter() { @computed getViewportPageCenter() {
return this.viewportPageBounds.center return this.getViewportPageBounds().center
}
/**
* @deprecated Use `getViewportPageCenter` instead.
*/
get viewportPageCenter() {
return this.getViewportPageCenter()
} }
/** /**
@ -3053,7 +3088,7 @@ export class Editor extends EventEmitter<TLEventMap> {
} }
// Get the bounds of the follower (me) and the leader (them) // Get the bounds of the follower (me) and the leader (them)
const { center, width, height } = this.viewportPageBounds const { center, width, height } = this.getViewportPageBounds()
const leaderScreen = Box2d.From(leaderPresence.screenBounds) const leaderScreen = Box2d.From(leaderPresence.screenBounds)
const leaderWidth = leaderScreen.width / leaderPresence.camera.z const leaderWidth = leaderScreen.width / leaderPresence.camera.z
const leaderHeight = leaderScreen.height / leaderPresence.camera.z const leaderHeight = leaderScreen.height / leaderPresence.camera.z
@ -3075,8 +3110,8 @@ export class Editor extends EventEmitter<TLEventMap> {
: height / desiredHeight : height / desiredHeight
const targetZoom = clamp(this.getCamera().z * ratio, MIN_ZOOM, MAX_ZOOM) const targetZoom = clamp(this.getCamera().z * ratio, MIN_ZOOM, MAX_ZOOM)
const targetWidth = this.viewportScreenBounds.w / targetZoom const targetWidth = this.getViewportScreenBounds().w / targetZoom
const targetHeight = this.viewportScreenBounds.h / targetZoom const targetHeight = this.getViewportScreenBounds().h / targetZoom
// Figure out where to move the camera // Figure out where to move the camera
const displacement = leaderCenter.sub(center) const displacement = leaderCenter.sub(center)
@ -3349,13 +3384,13 @@ export class Editor extends EventEmitter<TLEventMap> {
* @internal * @internal
*/ */
updateRenderingBounds(): this { updateRenderingBounds(): this {
const { viewportPageBounds } = this const viewportPageBounds = this.getViewportPageBounds()
if (viewportPageBounds.equals(this._renderingBounds.__unsafe__getWithoutCapture())) return this if (viewportPageBounds.equals(this._renderingBounds.__unsafe__getWithoutCapture())) return this
this._renderingBounds.set(viewportPageBounds.clone()) this._renderingBounds.set(viewportPageBounds.clone())
if (Number.isFinite(this.renderingBoundsMargin)) { if (Number.isFinite(this.renderingBoundsMargin)) {
this._renderingBoundsExpanded.set( this._renderingBoundsExpanded.set(
viewportPageBounds.clone().expandBy(this.renderingBoundsMargin / this.zoomLevel) viewportPageBounds.clone().expandBy(this.renderingBoundsMargin / this.getZoomLevel())
) )
} else { } else {
this._renderingBoundsExpanded.set(viewportPageBounds) this._renderingBoundsExpanded.set(viewportPageBounds)
@ -4425,7 +4460,8 @@ export class Editor extends EventEmitter<TLEventMap> {
filter?: (shape: TLShape) => boolean filter?: (shape: TLShape) => boolean
} }
): TLShape | undefined { ): TLShape | undefined {
const { viewportPageBounds, zoomLevel } = this const zoomLevel = this.getZoomLevel()
const viewportPageBounds = this.getViewportPageBounds()
const { const {
filter, filter,
margin = 0, margin = 0,
@ -5479,7 +5515,7 @@ export class Editor extends EventEmitter<TLEventMap> {
// contained in the current viewport. If not, then animate the camera to be centered on the // contained in the current viewport. If not, then animate the camera to be centered on the
// new shapes. // new shapes.
const selectionPageBounds = this.getSelectionPageBounds() const selectionPageBounds = this.getSelectionPageBounds()
const { viewportPageBounds } = this const viewportPageBounds = this.getViewportPageBounds()
if (selectionPageBounds && !viewportPageBounds.contains(selectionPageBounds)) { if (selectionPageBounds && !viewportPageBounds.contains(selectionPageBounds)) {
this.centerOnPoint(selectionPageBounds.center, { this.centerOnPoint(selectionPageBounds.center, {
duration: ANIMATION_MEDIUM_MS, duration: ANIMATION_MEDIUM_MS,
@ -7988,7 +8024,7 @@ export class Editor extends EventEmitter<TLEventMap> {
if (!isPageId(pasteParentId)) { if (!isPageId(pasteParentId)) {
const parent = this.getShape(pasteParentId) const parent = this.getShape(pasteParentId)
if (parent) { if (parent) {
if (!this.viewportPageBounds.includes(this.getShapePageBounds(parent)!)) { if (!this.getViewportPageBounds().includes(this.getShapePageBounds(parent)!)) {
pasteParentId = currentPageId pasteParentId = currentPageId
} else { } else {
if (rootShapeIds.length === 1) { if (rootShapeIds.length === 1) {
@ -8189,7 +8225,7 @@ export class Editor extends EventEmitter<TLEventMap> {
this.getShapeGeometry(shape).bounds.center this.getShapeGeometry(shape).bounds.center
) )
} else { } else {
const { viewportPageBounds } = this const viewportPageBounds = this.getViewportPageBounds()
if (preservePosition || viewportPageBounds.includes(Box2d.From(bounds))) { if (preservePosition || viewportPageBounds.includes(Box2d.From(bounds))) {
// Otherwise, put shapes where they used to be // Otherwise, put shapes where they used to be
point = bounds.center point = bounds.center
@ -8872,7 +8908,7 @@ export class Editor extends EventEmitter<TLEventMap> {
inputs.isPointing && inputs.isPointing &&
originPagePoint.dist(currentPagePoint) > originPagePoint.dist(currentPagePoint) >
(this.getInstanceState().isCoarsePointer ? COARSE_DRAG_DISTANCE : DRAG_DISTANCE) / (this.getInstanceState().isCoarsePointer ? COARSE_DRAG_DISTANCE : DRAG_DISTANCE) /
this.zoomLevel this.getZoomLevel()
) { ) {
inputs.isDragging = true inputs.isDragging = true
} }
@ -8960,7 +8996,7 @@ export class Editor extends EventEmitter<TLEventMap> {
inputs.isPointing && inputs.isPointing &&
originPagePoint.dist(currentPagePoint) > originPagePoint.dist(currentPagePoint) >
(this.getInstanceState().isCoarsePointer ? COARSE_DRAG_DISTANCE : DRAG_DISTANCE) / (this.getInstanceState().isCoarsePointer ? COARSE_DRAG_DISTANCE : DRAG_DISTANCE) /
this.zoomLevel this.getZoomLevel()
) { ) {
inputs.isDragging = true inputs.isDragging = true
} }

View file

@ -242,7 +242,7 @@ export class SnapManager {
} }
@computed get snapThreshold() { @computed get snapThreshold() {
return 8 / this.editor.zoomLevel return 8 / this.editor.getZoomLevel()
} }
// TODO: make this an incremental derivation // TODO: make this an incremental derivation

View file

@ -6,7 +6,7 @@ import { getPerfectDashProps } from '../shared/getPerfectDashProps'
export function DashedOutlineBox({ bounds, className }: { bounds: Box2d; className: string }) { export function DashedOutlineBox({ bounds, className }: { bounds: Box2d; className: string }) {
const editor = useEditor() const editor = useEditor()
const zoomLevel = useValue('zoom level', () => editor.zoomLevel, [editor]) const zoomLevel = useValue('zoom level', () => editor.getZoomLevel(), [editor])
return ( return (
<g className={className} pointerEvents="none" strokeLinecap="round" strokeLinejoin="round"> <g className={className} pointerEvents="none" strokeLinecap="round" strokeLinejoin="round">

View file

@ -225,7 +225,7 @@ export function useDocumentEvents() {
// touchstart event in that case. // touchstart event in that case.
if ( if (
touchXPosition - touchXRadius < 10 || touchXPosition - touchXRadius < 10 ||
touchXPosition + touchXRadius > editor.viewportScreenBounds.width - 10 touchXPosition + touchXRadius > editor.getViewportScreenBounds().width - 10
) { ) {
if ((e.target as HTMLElement)?.tagName === 'BUTTON') { if ((e.target as HTMLElement)?.tagName === 'BUTTON') {
// Force a click before bailing // Force a click before bailing

View file

@ -155,12 +155,12 @@ export function useGestureEvents(ref: React.RefObject<HTMLDivElement>) {
initPointBetweenFingers.x = origin[0] initPointBetweenFingers.x = origin[0]
initPointBetweenFingers.y = origin[1] initPointBetweenFingers.y = origin[1]
initDistanceBetweenFingers = da[0] initDistanceBetweenFingers = da[0]
initZoom = editor.zoomLevel initZoom = editor.getZoomLevel()
editor.dispatch({ editor.dispatch({
type: 'pinch', type: 'pinch',
name: 'pinch_start', name: 'pinch_start',
point: { x: origin[0], y: origin[1], z: editor.zoomLevel }, point: { x: origin[0], y: origin[1], z: editor.getZoomLevel() },
delta: { x: 0, y: 0 }, delta: { x: 0, y: 0 },
shiftKey: event.shiftKey, shiftKey: event.shiftKey,
altKey: event.altKey, altKey: event.altKey,
@ -302,9 +302,9 @@ export function useGestureEvents(ref: React.RefObject<HTMLDivElement>) {
target: ref, target: ref,
eventOptions: { passive: false }, eventOptions: { passive: false },
pinch: { pinch: {
from: () => [editor.zoomLevel, 0], // Return the camera z to use when pinch starts from: () => [editor.getZoomLevel(), 0], // Return the camera z to use when pinch starts
scaleBounds: () => { scaleBounds: () => {
return { from: editor.zoomLevel, max: 8, min: 0.05 } return { from: editor.getZoomLevel(), max: 8, min: 0.05 }
}, },
}, },
}) })

View file

@ -15,9 +15,9 @@ export function useZoomCss() {
const scheduler = new EffectScheduler('useZoomCss', () => { const scheduler = new EffectScheduler('useZoomCss', () => {
const numShapes = editor.currentPageShapeIds.size const numShapes = editor.currentPageShapeIds.size
if (numShapes < 300) { if (numShapes < 300) {
setScale(editor.zoomLevel) setScale(editor.getZoomLevel())
} else { } else {
setScaleDebounced(editor.zoomLevel) setScaleDebounced(editor.getZoomLevel())
} }
}) })

View file

@ -54,7 +54,7 @@ export const TldrawSelectionForeground: TLSelectionForegroundComponent = track(
if (!bounds) return null if (!bounds) return null
bounds = bounds.clone().expandBy(expandOutlineBy).zeroFix() bounds = bounds.clone().expandBy(expandOutlineBy).zeroFix()
const zoom = editor.zoomLevel const zoom = editor.getZoomLevel()
const isChangingStyle = editor.getInstanceState().isChangingStyle const isChangingStyle = editor.getInstanceState().isChangingStyle
const width = bounds.width const width = bounds.width
@ -501,7 +501,7 @@ export const MobileRotateHandle = function RotateHandle({
const events = useSelectionEvents('mobile_rotate') const events = useSelectionEvents('mobile_rotate')
const editor = useEditor() const editor = useEditor()
const zoom = useValue('zoom level', () => editor.zoomLevel, [editor]) const zoom = useValue('zoom level', () => editor.getZoomLevel(), [editor])
const bgRadius = Math.max(14 * (1 / zoom), 20 / Math.max(1, zoom)) const bgRadius = Math.max(14 * (1 / zoom), 20 / Math.max(1, zoom))
return ( return (

View file

@ -165,7 +165,8 @@ export function registerDefaultExternalContentHandlers(
// svg text // svg text
editor.registerExternalContentHandler('svg-text', async ({ point, text }) => { editor.registerExternalContentHandler('svg-text', async ({ point, text }) => {
const position = const position =
point ?? (editor.inputs.shiftKey ? editor.inputs.currentPagePoint : editor.viewportPageCenter) point ??
(editor.inputs.shiftKey ? editor.inputs.currentPagePoint : editor.getViewportPageCenter())
const svg = new DOMParser().parseFromString(text, 'image/svg+xml').querySelector('svg') const svg = new DOMParser().parseFromString(text, 'image/svg+xml').querySelector('svg')
if (!svg) { if (!svg) {
@ -197,7 +198,8 @@ export function registerDefaultExternalContentHandlers(
// embeds // embeds
editor.registerExternalContentHandler('embed', ({ point, url, embed }) => { editor.registerExternalContentHandler('embed', ({ point, url, embed }) => {
const position = const position =
point ?? (editor.inputs.shiftKey ? editor.inputs.currentPagePoint : editor.viewportPageCenter) point ??
(editor.inputs.shiftKey ? editor.inputs.currentPagePoint : editor.getViewportPageCenter())
const { width, height } = embed const { width, height } = embed
@ -221,7 +223,8 @@ export function registerDefaultExternalContentHandlers(
// files // files
editor.registerExternalContentHandler('files', async ({ point, files }) => { editor.registerExternalContentHandler('files', async ({ point, files }) => {
const position = const position =
point ?? (editor.inputs.shiftKey ? editor.inputs.currentPagePoint : editor.viewportPageCenter) point ??
(editor.inputs.shiftKey ? editor.inputs.currentPagePoint : editor.getViewportPageCenter())
const pagePoint = new Vec2d(position.x, position.y) const pagePoint = new Vec2d(position.x, position.y)
@ -272,7 +275,8 @@ export function registerDefaultExternalContentHandlers(
// text // text
editor.registerExternalContentHandler('text', async ({ point, text }) => { editor.registerExternalContentHandler('text', async ({ point, text }) => {
const p = const p =
point ?? (editor.inputs.shiftKey ? editor.inputs.currentPagePoint : editor.viewportPageCenter) point ??
(editor.inputs.shiftKey ? editor.inputs.currentPagePoint : editor.getViewportPageCenter())
const defaultProps = editor.getShapeUtil<TLTextShape>('text').getDefaultProps() const defaultProps = editor.getShapeUtil<TLTextShape>('text').getDefaultProps()
@ -301,8 +305,8 @@ export function registerDefaultExternalContentHandlers(
}) })
const minWidth = Math.min( const minWidth = Math.min(
isMultiLine ? editor.viewportPageBounds.width * 0.9 : 920, isMultiLine ? editor.getViewportPageBounds().width * 0.9 : 920,
Math.max(200, editor.viewportPageBounds.width * 0.9) Math.max(200, editor.getViewportPageBounds().width * 0.9)
) )
if (rawSize.w > minWidth) { if (rawSize.w > minWidth) {
@ -323,8 +327,8 @@ export function registerDefaultExternalContentHandlers(
autoSize = true autoSize = true
} }
if (p.y - h / 2 < editor.viewportPageBounds.minY + 40) { if (p.y - h / 2 < editor.getViewportPageBounds().minY + 40) {
p.y = editor.viewportPageBounds.minY + 40 + h / 2 p.y = editor.getViewportPageBounds().minY + 40 + h / 2
} }
editor.createShapes<TLTextShape>([ editor.createShapes<TLTextShape>([
@ -359,7 +363,8 @@ export function registerDefaultExternalContentHandlers(
} }
const position = const position =
point ?? (editor.inputs.shiftKey ? editor.inputs.currentPagePoint : editor.viewportPageCenter) point ??
(editor.inputs.shiftKey ? editor.inputs.currentPagePoint : editor.getViewportPageCenter())
const assetId: TLAssetId = AssetRecordType.createId(getHashForString(url)) const assetId: TLAssetId = AssetRecordType.createId(getHashForString(url))
const shape = createEmptyBookmarkShape(editor, url, position) const shape = createEmptyBookmarkShape(editor, url, position)
@ -475,7 +480,7 @@ export async function createShapesForAssets(
function centerSelectionAroundPoint(editor: Editor, position: VecLike) { function centerSelectionAroundPoint(editor: Editor, position: VecLike) {
// Re-position shapes so that the center of the group is at the provided point // Re-position shapes so that the center of the group is at the provided point
const { viewportPageBounds } = editor const viewportPageBounds = editor.getViewportPageBounds()
let selectionPageBounds = editor.getSelectionPageBounds() let selectionPageBounds = editor.getSelectionPageBounds()
if (selectionPageBounds) { if (selectionPageBounds) {

View file

@ -288,7 +288,7 @@ export class ArrowShapeUtil extends ShapeUtil<TLArrowShape> {
precise = precise =
Vec2d.Dist(pointInTargetSpace, targetBounds.center) > Vec2d.Dist(pointInTargetSpace, targetBounds.center) >
Math.max(4, Math.min(Math.min(targetBounds.width, targetBounds.height) * 0.15, 16)) / Math.max(4, Math.min(Math.min(targetBounds.width, targetBounds.height) * 0.15, 16)) /
this.editor.zoomLevel this.editor.getZoomLevel()
} }
if (!isPrecise) { if (!isPrecise) {

View file

@ -67,7 +67,7 @@ export class BookmarkShapeUtil extends BaseBoxShapeUtil<TLBookmarkShape> {
) : ( ) : (
<div className="tl-bookmark__placeholder" /> <div className="tl-bookmark__placeholder" />
)} )}
<HyperlinkButton url={shape.props.url} zoomLevel={this.editor.zoomLevel} /> <HyperlinkButton url={shape.props.url} zoomLevel={this.editor.getZoomLevel()} />
</div> </div>
<div className="tl-bookmark__copy_container"> <div className="tl-bookmark__copy_container">
{asset?.props.title && ( {asset?.props.title && (

View file

@ -87,7 +87,7 @@ export class Drawing extends StateNode {
if (inputs.isPen) { if (inputs.isPen) {
if ( if (
Vec2d.Dist(inputs.currentPagePoint, this.lastRecordedPoint) >= Vec2d.Dist(inputs.currentPagePoint, this.lastRecordedPoint) >=
1 / this.editor.zoomLevel 1 / this.editor.getZoomLevel()
) { ) {
this.lastRecordedPoint = inputs.currentPagePoint.clone() this.lastRecordedPoint = inputs.currentPagePoint.clone()
this.mergeNextPoint = false this.mergeNextPoint = false
@ -474,7 +474,7 @@ export class Drawing extends StateNode {
if (shouldSnap) { if (shouldSnap) {
if (newSegments.length > 2) { if (newSegments.length > 2) {
let nearestPoint: Vec2dModel | undefined = undefined let nearestPoint: Vec2dModel | undefined = undefined
let minDistance = 8 / this.editor.zoomLevel let minDistance = 8 / this.editor.getZoomLevel()
// Don't try to snap to the last two segments // Don't try to snap to the last two segments
for (let i = 0, n = segments.length - 2; i < n; i++) { for (let i = 0, n = segments.length - 2; i < n; i++) {

View file

@ -540,7 +540,7 @@ export class GeoShapeUtil extends BaseBoxShapeUtil<TLGeoShape> {
bounds={props.geo === 'cloud' ? this.getGeometry(shape).bounds : undefined} bounds={props.geo === 'cloud' ? this.getGeometry(shape).bounds : undefined}
/> />
{shape.props.url && ( {shape.props.url && (
<HyperlinkButton url={shape.props.url} zoomLevel={this.editor.zoomLevel} /> <HyperlinkButton url={shape.props.url} zoomLevel={this.editor.getZoomLevel()} />
)} )}
</HTMLContainer> </HTMLContainer>
</> </>

View file

@ -155,7 +155,7 @@ export class ImageShapeUtil extends BaseBoxShapeUtil<TLImageShape> {
)} )}
</div> </div>
{'url' in shape.props && shape.props.url && ( {'url' in shape.props && shape.props.url && (
<HyperlinkButton url={shape.props.url} zoomLevel={this.editor.zoomLevel} /> <HyperlinkButton url={shape.props.url} zoomLevel={this.editor.getZoomLevel()} />
)} )}
</HTMLContainer> </HTMLContainer>
</> </>

View file

@ -94,7 +94,7 @@ export class NoteShapeUtil extends ShapeUtil<TLNoteShape> {
</div> </div>
</div> </div>
{'url' in shape.props && shape.props.url && ( {'url' in shape.props && shape.props.url && (
<HyperlinkButton url={shape.props.url} zoomLevel={this.editor.zoomLevel} /> <HyperlinkButton url={shape.props.url} zoomLevel={this.editor.getZoomLevel()} />
)} )}
</> </>
) )

View file

@ -40,10 +40,10 @@ export const ShapeFill = React.memo(function ShapeFill({ theme, d, color, fill }
const PatternFill = function PatternFill({ d, color, theme }: ShapeFillProps) { const PatternFill = function PatternFill({ d, color, theme }: ShapeFillProps) {
const editor = useEditor() const editor = useEditor()
const zoomLevel = useValue('zoomLevel', () => editor.zoomLevel, [editor]) const zoomLevel = useValue('zoomLevel', () => editor.getZoomLevel(), [editor])
const intZoom = Math.ceil(zoomLevel) const intZoom = Math.ceil(zoomLevel)
const teenyTiny = editor.zoomLevel <= 0.18 const teenyTiny = editor.getZoomLevel() <= 0.18
return ( return (
<> <>

View file

@ -2,5 +2,5 @@ import { useEditor, useValue } from '@tldraw/editor'
export function useForceSolid() { export function useForceSolid() {
const editor = useEditor() const editor = useEditor()
return useValue('zoom', () => editor.zoomLevel < 0.35, [editor]) return useValue('zoom', () => editor.getZoomLevel() < 0.35, [editor])
} }

View file

@ -71,7 +71,7 @@ const TLVideoUtilComponent = track(function TLVideoUtilComponent(props: {
}) { }) {
const { shape, videoUtil } = props const { shape, videoUtil } = props
const showControls = const showControls =
videoUtil.editor.getShapeGeometry(shape).bounds.w * videoUtil.editor.zoomLevel >= 110 videoUtil.editor.getShapeGeometry(shape).bounds.w * videoUtil.editor.getZoomLevel() >= 110
const asset = shape.props.assetId ? videoUtil.editor.getAsset(shape.props.assetId) : null const asset = shape.props.assetId ? videoUtil.editor.getAsset(shape.props.assetId) : null
const { time, playing } = shape.props const { time, playing } = shape.props
const isEditing = useIsEditing(shape.id) const isEditing = useIsEditing(shape.id)
@ -208,7 +208,7 @@ const TLVideoUtilComponent = track(function TLVideoUtilComponent(props: {
</div> </div>
</HTMLContainer> </HTMLContainer>
{'url' in shape.props && shape.props.url && ( {'url' in shape.props && shape.props.url && (
<HyperlinkButton url={shape.props.url} zoomLevel={videoUtil.editor.zoomLevel} /> <HyperlinkButton url={shape.props.url} zoomLevel={videoUtil.editor.getZoomLevel()} />
)} )}
</> </>
) )

View file

@ -79,8 +79,8 @@ export class Erasing extends StateNode {
update() { update() {
const erasingShapeIds = this.editor.getErasingShapeIds() const erasingShapeIds = this.editor.getErasingShapeIds()
const zoomLevel = this.editor.getZoomLevel()
const { const {
zoomLevel,
currentPageShapes: currentPageShapes, currentPageShapes: currentPageShapes,
inputs: { currentPagePoint, previousPagePoint }, inputs: { currentPagePoint, previousPagePoint },
} = this.editor } = this.editor

View file

@ -11,10 +11,10 @@ export class Pointing extends StateNode {
static override id = 'pointing' static override id = 'pointing'
override onEnter = () => { override onEnter = () => {
const zoomLevel = this.editor.getZoomLevel()
const { const {
inputs: { currentPagePoint }, inputs: { currentPagePoint },
currentPageShapesSorted: sortedShapesOnCurrentPage, currentPageShapesSorted: sortedShapesOnCurrentPage,
zoomLevel,
} = this.editor } = this.editor
const erasing = new Set<TLShapeId>() const erasing = new Set<TLShapeId>()

View file

@ -25,8 +25,8 @@ export class HandTool extends StateNode {
override onQuadrupleClick: TLClickEvent = (info) => { override onQuadrupleClick: TLClickEvent = (info) => {
if (info.phase === 'settle') { if (info.phase === 'settle') {
const zoomLevel = this.editor.getZoomLevel()
const { const {
zoomLevel,
inputs: { currentScreenPoint }, inputs: { currentScreenPoint },
} = this.editor } = this.editor

View file

@ -93,8 +93,8 @@ export class Brushing extends StateNode {
} }
private hitTestShapes() { private hitTestShapes() {
const zoomLevel = this.editor.getZoomLevel()
const { const {
zoomLevel,
currentPageId, currentPageId,
currentPageShapes: currentPageShapes, currentPageShapes: currentPageShapes,
inputs: { originPagePoint, currentPagePoint, shiftKey, ctrlKey }, inputs: { originPagePoint, currentPagePoint, shiftKey, ctrlKey },

View file

@ -176,7 +176,7 @@ export class Idle extends StateNode {
? hoveredShape ? hoveredShape
: this.editor.getSelectedShapeAtPoint(this.editor.inputs.currentPagePoint) ?? : this.editor.getSelectedShapeAtPoint(this.editor.inputs.currentPagePoint) ??
this.editor.getShapeAtPoint(this.editor.inputs.currentPagePoint, { this.editor.getShapeAtPoint(this.editor.inputs.currentPagePoint, {
margin: HIT_TEST_MARGIN / this.editor.zoomLevel, margin: HIT_TEST_MARGIN / this.editor.getZoomLevel(),
hitInside: false, hitInside: false,
}) })
@ -329,7 +329,7 @@ export class Idle extends StateNode {
hoveredShape && !this.editor.isShapeOfType<TLGroupShape>(hoveredShape, 'group') hoveredShape && !this.editor.isShapeOfType<TLGroupShape>(hoveredShape, 'group')
? hoveredShape ? hoveredShape
: this.editor.getShapeAtPoint(this.editor.inputs.currentPagePoint, { : this.editor.getShapeAtPoint(this.editor.inputs.currentPagePoint, {
margin: HIT_TEST_MARGIN / this.editor.zoomLevel, margin: HIT_TEST_MARGIN / this.editor.getZoomLevel(),
hitInside: false, hitInside: false,
hitLabels: true, hitLabels: true,
hitFrameInside: false, hitFrameInside: false,

View file

@ -62,8 +62,8 @@ export class PointingShape extends StateNode {
override onPointerUp: TLEventHandlers['onPointerUp'] = (info) => { override onPointerUp: TLEventHandlers['onPointerUp'] = (info) => {
const selectedShapeIds = this.editor.getSelectedShapeIds() const selectedShapeIds = this.editor.getSelectedShapeIds()
const focusedGroupId = this.editor.getFocusedGroupId() const focusedGroupId = this.editor.getFocusedGroupId()
const zoomLevel = this.editor.getZoomLevel()
const { const {
zoomLevel,
inputs: { currentPagePoint, shiftKey }, inputs: { currentPagePoint, shiftKey },
} = this.editor } = this.editor

View file

@ -85,8 +85,8 @@ export class ScribbleBrushing extends StateNode {
} }
private updateScribbleSelection(addPoint: boolean) { private updateScribbleSelection(addPoint: boolean) {
const zoomLevel = this.editor.getZoomLevel()
const { const {
zoomLevel,
currentPageShapes: currentPageShapes, currentPageShapes: currentPageShapes,
inputs: { shiftKey, originPagePoint, previousPagePoint, currentPagePoint }, inputs: { shiftKey, originPagePoint, previousPagePoint, currentPagePoint },
} = this.editor } = this.editor

View file

@ -43,7 +43,7 @@ export class ZoomBrushing extends StateNode {
private complete() { private complete() {
const { zoomBrush } = this const { zoomBrush } = this
const threshold = 8 / this.editor.zoomLevel const threshold = 8 / this.editor.getZoomLevel()
// If the selected area is small then treat it as a click // If the selected area is small then treat it as a click
if (zoomBrush.width < threshold && zoomBrush.height < threshold) { if (zoomBrush.width < threshold && zoomBrush.height < threshold) {
const point = this.editor.inputs.currentScreenPoint const point = this.editor.inputs.currentScreenPoint
@ -53,7 +53,7 @@ export class ZoomBrushing extends StateNode {
this.editor.zoomIn(point, { duration: 220 }) this.editor.zoomIn(point, { duration: 220 })
} }
} else { } else {
const zoomLevel = this.editor.inputs.altKey ? this.editor.zoomLevel / 2 : undefined const zoomLevel = this.editor.inputs.altKey ? this.editor.getZoomLevel() / 2 : undefined
this.editor.zoomToBounds(zoomBrush, zoomLevel, { duration: 220 }) this.editor.zoomToBounds(zoomBrush, zoomLevel, { duration: 220 })
} }

View file

@ -1,8 +1,8 @@
import { Editor, HIT_TEST_MARGIN, TLShape } from '@tldraw/editor' import { Editor, HIT_TEST_MARGIN, TLShape } from '@tldraw/editor'
export function getHitShapeOnCanvasPointerDown(editor: Editor): TLShape | undefined { export function getHitShapeOnCanvasPointerDown(editor: Editor): TLShape | undefined {
const zoomLevel = editor.getZoomLevel()
const { const {
zoomLevel,
inputs: { currentPagePoint }, inputs: { currentPagePoint },
} = editor } = editor

View file

@ -6,7 +6,7 @@ export function selectOnCanvasPointerUp(editor: Editor) {
const hitShape = editor.getShapeAtPoint(currentPagePoint, { const hitShape = editor.getShapeAtPoint(currentPagePoint, {
hitInside: false, hitInside: false,
margin: HIT_TEST_MARGIN / editor.zoomLevel, margin: HIT_TEST_MARGIN / editor.getZoomLevel(),
hitLabels: true, hitLabels: true,
renderingOnly: true, renderingOnly: true,
filter: (shape) => !shape.isLocked, filter: (shape) => !shape.isLocked,

View file

@ -5,7 +5,7 @@ export function updateHoveredId(editor: Editor) {
const hitShape = editor.getShapeAtPoint(editor.inputs.currentPagePoint, { const hitShape = editor.getShapeAtPoint(editor.inputs.currentPagePoint, {
hitInside: false, hitInside: false,
hitLabels: false, hitLabels: false,
margin: HIT_TEST_MARGIN / editor.zoomLevel, margin: HIT_TEST_MARGIN / editor.getZoomLevel(),
renderingOnly: true, renderingOnly: true,
}) })

View file

@ -108,7 +108,7 @@ export const EmbedDialog = track(function EmbedDialog({ onClose }: TLUiDialogPro
editor.putExternalContent({ editor.putExternalContent({
type: 'embed', type: 'embed',
url, url,
point: editor.viewportPageCenter, point: editor.getViewportPageCenter(),
embed: embedInfoForUrl.definition, embed: embedInfoForUrl.definition,
}) })

View file

@ -37,8 +37,8 @@ export const HTMLCanvas = track(function HTMLCanvas() {
return ( return (
<canvas <canvas
ref={rCanvas} ref={rCanvas}
width={editor.viewportScreenBounds.width} width={editor.getViewportScreenBounds().width}
height={editor.viewportScreenBounds.height} height={editor.getViewportScreenBounds().height}
style={{ width: '100%', height: '100%' }} style={{ width: '100%', height: '100%' }}
/> />
) )

View file

@ -64,7 +64,7 @@ export function Minimap({ shapeFill, selectFill, viewportFill }: MinimapProps) {
const clampedPoint = minimap.minimapScreenPointToPagePoint(e.clientX, e.clientY, false, true) const clampedPoint = minimap.minimapScreenPointToPagePoint(e.clientX, e.clientY, false, true)
minimap.originPagePoint.setTo(clampedPoint) minimap.originPagePoint.setTo(clampedPoint)
minimap.originPageCenter.setTo(editor.viewportPageBounds.center) minimap.originPageCenter.setTo(editor.getViewportPageBounds().center)
editor.centerOnPoint(point, { duration: ANIMATION_MEDIUM_MS }) editor.centerOnPoint(point, { duration: ANIMATION_MEDIUM_MS })
}, },
@ -85,7 +85,7 @@ export function Minimap({ shapeFill, selectFill, viewportFill }: MinimapProps) {
const clampedPoint = minimap.minimapScreenPointToPagePoint(e.clientX, e.clientY, false, true) const clampedPoint = minimap.minimapScreenPointToPagePoint(e.clientX, e.clientY, false, true)
const _vpPageBounds = editor.viewportPageBounds const _vpPageBounds = editor.getViewportPageBounds()
minimap.isInViewport = _vpPageBounds.containsPoint(clampedPoint) minimap.isInViewport = _vpPageBounds.containsPoint(clampedPoint)
@ -189,9 +189,9 @@ export function Minimap({ shapeFill, selectFill, viewportFill }: MinimapProps) {
() => { () => {
const { const {
currentPageShapeIds: shapeIdsOnCurrentPage, currentPageShapeIds: shapeIdsOnCurrentPage,
viewportPageBounds,
currentPageBounds: commonBoundsOfAllShapesOnCurrentPage, currentPageBounds: commonBoundsOfAllShapesOnCurrentPage,
} = editor } = editor
const viewportPageBounds = editor.getViewportPageBounds()
const _dpr = devicePixelRatio.get() // dereference const _dpr = devicePixelRatio.get() // dereference

View file

@ -118,7 +118,7 @@ export class MinimapManager {
clampToBounds = false clampToBounds = false
) => { ) => {
const { editor } = this const { editor } = this
const { viewportPageBounds } = editor const viewportPageBounds = editor.getViewportPageBounds()
let { x: px, y: py } = this.getPagePoint(x, y) let { x: px, y: py } = this.getPagePoint(x, y)
@ -179,9 +179,8 @@ export class MinimapManager {
this this
const { width: cw, height: ch } = canvasScreenBounds const { width: cw, height: ch } = canvasScreenBounds
const selectedShapeIds = this.editor.getSelectedShapeIds() const selectedShapeIds = editor.getSelectedShapeIds()
const viewportPageBounds = editor.getViewportPageBounds()
const { viewportPageBounds } = editor
if (!cvs || !pageBounds) { if (!cvs || !pageBounds) {
return return

View file

@ -11,13 +11,13 @@ export const ZoomMenu = track(function ZoomMenu() {
const msg = useTranslation() const msg = useTranslation()
const breakpoint = useBreakpoint() const breakpoint = useBreakpoint()
const zoom = editor.zoomLevel const zoom = editor.getZoomLevel()
const hasShapes = editor.currentPageShapeIds.size > 0 const hasShapes = editor.currentPageShapeIds.size > 0
const hasSelected = editor.getSelectedShapeIds().length > 0 const hasSelected = editor.getSelectedShapeIds().length > 0
const isZoomedTo100 = editor.zoomLevel === 1 const isZoomedTo100 = editor.getZoomLevel() === 1
const handleDoubleClick = React.useCallback(() => { const handleDoubleClick = React.useCallback(() => {
editor.resetZoom(editor.viewportScreenCenter, { duration: ANIMATION_MEDIUM_MS }) editor.resetZoom(editor.getViewportScreenCenter(), { duration: ANIMATION_MEDIUM_MS })
}, [editor]) }, [editor])
return ( return (

View file

@ -345,7 +345,7 @@ export async function pasteExcalidrawContent(editor: Editor, clipboard: any, poi
const rootShapes = compact(rootShapeIds.map((id) => editor.getShape(id))) const rootShapes = compact(rootShapeIds.map((id) => editor.getShape(id)))
const bounds = Box2d.Common(rootShapes.map((s) => editor.getShapePageBounds(s)!)) const bounds = Box2d.Common(rootShapes.map((s) => editor.getShapePageBounds(s)!))
const viewPortCenter = editor.viewportPageBounds.center const viewPortCenter = editor.getViewportPageBounds().center
editor.updateShapes( editor.updateShapes(
rootShapes.map((s) => { rootShapes.map((s) => {
const delta = { const delta = {

View file

@ -409,8 +409,8 @@ export function ActionsProvider({ overrides, children }: ActionsProviderProps) {
y: 0, y: 0,
} }
: { : {
x: 16 / editor.zoomLevel, x: 16 / editor.getZoomLevel(),
y: 16 / editor.zoomLevel, y: 16 / editor.getZoomLevel(),
} }
editor.mark('duplicate shapes') editor.mark('duplicate shapes')
editor.duplicateShapes(ids, offset) editor.duplicateShapes(ids, offset)
@ -869,7 +869,7 @@ export function ActionsProvider({ overrides, children }: ActionsProviderProps) {
readonlyOk: true, readonlyOk: true,
onSelect(source) { onSelect(source) {
trackEvent('zoom-in', { source }) trackEvent('zoom-in', { source })
editor.zoomIn(editor.viewportScreenCenter, { duration: ANIMATION_MEDIUM_MS }) editor.zoomIn(editor.getViewportScreenCenter(), { duration: ANIMATION_MEDIUM_MS })
}, },
}, },
{ {
@ -879,7 +879,7 @@ export function ActionsProvider({ overrides, children }: ActionsProviderProps) {
readonlyOk: true, readonlyOk: true,
onSelect(source) { onSelect(source) {
trackEvent('zoom-out', { source }) trackEvent('zoom-out', { source })
editor.zoomOut(editor.viewportScreenCenter, { duration: ANIMATION_MEDIUM_MS }) editor.zoomOut(editor.getViewportScreenCenter(), { duration: ANIMATION_MEDIUM_MS })
}, },
}, },
{ {
@ -890,7 +890,7 @@ export function ActionsProvider({ overrides, children }: ActionsProviderProps) {
readonlyOk: true, readonlyOk: true,
onSelect(source) { onSelect(source) {
trackEvent('reset-zoom', { source }) trackEvent('reset-zoom', { source })
editor.resetZoom(editor.viewportScreenCenter, { duration: ANIMATION_MEDIUM_MS }) editor.resetZoom(editor.getViewportScreenCenter(), { duration: ANIMATION_MEDIUM_MS })
}, },
}, },
{ {

View file

@ -52,7 +52,7 @@ export const ActionsMenuSchemaProvider = ({
const allowUngroup = useAllowUngroup() const allowUngroup = useAllowUngroup()
const showEditLink = useHasLinkShapeSelected() const showEditLink = useHasLinkShapeSelected()
const breakpoint = useBreakpoint() const breakpoint = useBreakpoint()
const isZoomedTo100 = useValue('zoom is 1', () => editor.zoomLevel === 1, [editor]) const isZoomedTo100 = useValue('zoom is 1', () => editor.getZoomLevel() === 1, [editor])
const actionTLUiMenuSchema = useMemo<TLUiMenuSchema>(() => { const actionTLUiMenuSchema = useMemo<TLUiMenuSchema>(() => {
const results = [ const results = [

View file

@ -18,7 +18,7 @@ export function BreakPointProvider({
'breakpoint', 'breakpoint',
() => { () => {
// This will recompute the viewport screen bounds changes... // This will recompute the viewport screen bounds changes...
const { width } = editor.viewportScreenBounds const { width } = editor.getViewportScreenBounds()
const maxBreakpoint = forceMobile ? 3 : PORTRAIT_BREAKPOINTS.length - 1 const maxBreakpoint = forceMobile ? 3 : PORTRAIT_BREAKPOINTS.length - 1

View file

@ -17,7 +17,7 @@ export function useInsertMedia() {
await editor.putExternalContent({ await editor.putExternalContent({
type: 'files', type: 'files',
files: Array.from(fileList), files: Array.from(fileList),
point: editor.viewportPageBounds.center, point: editor.getViewportPageBounds().center,
ignoreParent: false, ignoreParent: false,
}) })
input.value = '' input.value = ''

View file

@ -79,7 +79,7 @@ export function TLUiMenuSchemaProvider({ overrides, children }: TLUiMenuSchemaPr
const allowUngroup = useAllowUngroup() const allowUngroup = useAllowUngroup()
const canUndo = useCanUndo() const canUndo = useCanUndo()
const canRedo = useCanRedo() const canRedo = useCanRedo()
const isZoomedTo100 = useValue('isZoomedTo100', () => editor.zoomLevel === 1, [editor]) const isZoomedTo100 = useValue('isZoomedTo100', () => editor.getZoomLevel() === 1, [editor])
const oneEmbedSelected = useValue( const oneEmbedSelected = useValue(
'oneEmbedSelected', 'oneEmbedSelected',

View file

@ -19,55 +19,55 @@ jest.useFakeTimers()
describe(HandTool, () => { describe(HandTool, () => {
it('Double taps to zoom in', () => { it('Double taps to zoom in', () => {
editor.setCurrentTool('hand') editor.setCurrentTool('hand')
expect(editor.zoomLevel).toBe(1) expect(editor.getZoomLevel()).toBe(1)
editor.click() editor.click()
editor.click() // double click! editor.click() // double click!
jest.advanceTimersByTime(300) jest.advanceTimersByTime(300)
expect(editor.zoomLevel).not.toBe(1) // animating expect(editor.getZoomLevel()).not.toBe(1) // animating
jest.advanceTimersByTime(300) jest.advanceTimersByTime(300)
expect(editor.zoomLevel).toBe(2) // all done expect(editor.getZoomLevel()).toBe(2) // all done
}) })
it('Triple taps to zoom out', () => { it('Triple taps to zoom out', () => {
editor.setCurrentTool('hand') editor.setCurrentTool('hand')
expect(editor.zoomLevel).toBe(1) expect(editor.getZoomLevel()).toBe(1)
editor.click() editor.click()
editor.click() editor.click()
editor.click() // triple click! editor.click() // triple click!
jest.advanceTimersByTime(300) jest.advanceTimersByTime(300)
expect(editor.zoomLevel).not.toBe(1) // animating expect(editor.getZoomLevel()).not.toBe(1) // animating
jest.advanceTimersByTime(300) jest.advanceTimersByTime(300)
expect(editor.zoomLevel).toBe(0.5) // all done expect(editor.getZoomLevel()).toBe(0.5) // all done
}) })
it('Quadruple taps to reset zoom', () => { it('Quadruple taps to reset zoom', () => {
editor.setCurrentTool('hand') editor.setCurrentTool('hand')
editor.zoomIn() // zoom to 2 editor.zoomIn() // zoom to 2
expect(editor.zoomLevel).toBe(2) expect(editor.getZoomLevel()).toBe(2)
editor.click() editor.click()
editor.click() editor.click()
editor.click() editor.click()
editor.click() // quad click! editor.click() // quad click!
jest.advanceTimersByTime(300) jest.advanceTimersByTime(300)
expect(editor.zoomLevel).not.toBe(2) // animating expect(editor.getZoomLevel()).not.toBe(2) // animating
jest.advanceTimersByTime(300) jest.advanceTimersByTime(300)
expect(editor.zoomLevel).toBe(1) // all done expect(editor.getZoomLevel()).toBe(1) // all done
}) })
it('Quadruple taps from zoom=1 to zoom to fit', () => { it('Quadruple taps from zoom=1 to zoom to fit', () => {
editor.setCurrentTool('hand') editor.setCurrentTool('hand')
expect(editor.zoomLevel).toBe(1) expect(editor.getZoomLevel()).toBe(1)
editor.createShapes(createDefaultShapes()) // makes some shapes editor.createShapes(createDefaultShapes()) // makes some shapes
editor.click() editor.click()
editor.click() editor.click()
editor.click() editor.click()
editor.click() // quad click! editor.click() // quad click!
jest.advanceTimersByTime(300) jest.advanceTimersByTime(300)
expect(editor.zoomLevel).not.toBe(1) // animating expect(editor.getZoomLevel()).not.toBe(1) // animating
jest.advanceTimersByTime(300) jest.advanceTimersByTime(300)
const z = editor.zoomLevel const z = editor.getZoomLevel()
editor.zoomToFit() // call zoom to fit manually to compare editor.zoomToFit() // call zoom to fit manually to compare
expect(editor.zoomLevel).toBe(z) // zoom should not have changed expect(editor.getZoomLevel()).toBe(z) // zoom should not have changed
}) })
}) })

View file

@ -39,24 +39,24 @@ describe('TLSelectTool.Zooming', () => {
it('Correctly zooms in when clicking', () => { it('Correctly zooms in when clicking', () => {
editor.keyDown('z') editor.keyDown('z')
expect(editor.zoomLevel).toBe(1) expect(editor.getZoomLevel()).toBe(1)
expect(editor.viewportPageBounds).toMatchObject({ x: -0, y: -0, w: 1080, h: 720 }) expect(editor.getViewportPageBounds()).toMatchObject({ x: -0, y: -0, w: 1080, h: 720 })
expect(editor.viewportPageCenter).toMatchObject({ x: 540, y: 360 }) expect(editor.getViewportPageCenter()).toMatchObject({ x: 540, y: 360 })
editor.click() editor.click()
editor.expectToBeIn('zoom.idle') editor.expectToBeIn('zoom.idle')
jest.advanceTimersByTime(300) jest.advanceTimersByTime(300)
expect(editor.zoomLevel).toBe(2) expect(editor.getZoomLevel()).toBe(2)
}) })
it('Correctly zooms out when clicking while pressing Alt', () => { it('Correctly zooms out when clicking while pressing Alt', () => {
editor.keyDown('z') editor.keyDown('z')
editor.keyDown('Alt') editor.keyDown('Alt')
expect(editor.zoomLevel).toBe(1) expect(editor.getZoomLevel()).toBe(1)
expect(editor.viewportPageBounds).toMatchObject({ x: -0, y: -0, w: 1080, h: 720 }) expect(editor.getViewportPageBounds()).toMatchObject({ x: -0, y: -0, w: 1080, h: 720 })
expect(editor.viewportPageCenter).toMatchObject({ x: 540, y: 360 }) expect(editor.getViewportPageCenter()).toMatchObject({ x: 540, y: 360 })
editor.click() editor.click()
jest.advanceTimersByTime(300) jest.advanceTimersByTime(300)
expect(editor.zoomLevel).toBe(0.5) expect(editor.getZoomLevel()).toBe(0.5)
}) })
it('Cancels while pointing', () => { it('Cancels while pointing', () => {
@ -67,7 +67,7 @@ describe('TLSelectTool.Zooming', () => {
editor.cancel() editor.cancel()
editor.expectToBeIn('zoom.idle') editor.expectToBeIn('zoom.idle')
editor.pointerUp() editor.pointerUp()
expect(editor.zoomLevel).toBe(1) expect(editor.getZoomLevel()).toBe(1)
}) })
it('Cancels while brushing', () => { it('Cancels while brushing', () => {
@ -80,7 +80,7 @@ describe('TLSelectTool.Zooming', () => {
editor.cancel() editor.cancel()
editor.expectToBeIn('zoom.idle') editor.expectToBeIn('zoom.idle')
editor.pointerUp() editor.pointerUp()
expect(editor.zoomLevel).toBe(1) expect(editor.getZoomLevel()).toBe(1)
}) })
it('Interrupts while pointing', () => { it('Interrupts while pointing', () => {
@ -91,7 +91,7 @@ describe('TLSelectTool.Zooming', () => {
editor.interrupt() editor.interrupt()
editor.expectToBeIn('select.idle') editor.expectToBeIn('select.idle')
editor.pointerUp() editor.pointerUp()
expect(editor.zoomLevel).toBe(1) expect(editor.getZoomLevel()).toBe(1)
}) })
it('Interrupts while brushing', () => { it('Interrupts while brushing', () => {
@ -104,16 +104,16 @@ describe('TLSelectTool.Zooming', () => {
editor.interrupt() editor.interrupt()
editor.expectToBeIn('select.idle') editor.expectToBeIn('select.idle')
editor.pointerUp() editor.pointerUp()
expect(editor.zoomLevel).toBe(1) expect(editor.getZoomLevel()).toBe(1)
}) })
it('When the dragged area is small it zooms in instead of zooming to the area', () => { it('When the dragged area is small it zooms in instead of zooming to the area', () => {
const originalCenter = { x: 540, y: 360 } const originalCenter = { x: 540, y: 360 }
const originalPageBounds = { x: -0, y: -0, w: 1080, h: 720 } const originalPageBounds = { x: -0, y: -0, w: 1080, h: 720 }
const change = 6 const change = 6
expect(editor.zoomLevel).toBe(1) expect(editor.getZoomLevel()).toBe(1)
expect(editor.viewportPageBounds).toMatchObject(originalPageBounds) expect(editor.getViewportPageBounds()).toMatchObject(originalPageBounds)
expect(editor.viewportPageCenter).toMatchObject(originalCenter) expect(editor.getViewportPageCenter()).toMatchObject(originalCenter)
editor.keyDown('z') editor.keyDown('z')
editor.expectToBeIn('zoom.idle') editor.expectToBeIn('zoom.idle')
editor.pointerDown(0, 0) editor.pointerDown(0, 0)
@ -123,14 +123,14 @@ describe('TLSelectTool.Zooming', () => {
editor.pointerUp(change, change) editor.pointerUp(change, change)
editor.expectToBeIn('zoom.idle') editor.expectToBeIn('zoom.idle')
jest.advanceTimersByTime(300) jest.advanceTimersByTime(300)
expect(editor.zoomLevel).toBe(2) expect(editor.getZoomLevel()).toBe(2)
expect(editor.viewportPageBounds).toMatchObject({ expect(editor.getViewportPageBounds()).toMatchObject({
x: change / 2, x: change / 2,
y: change / 2, y: change / 2,
w: originalPageBounds.w / 2, w: originalPageBounds.w / 2,
h: originalPageBounds.h / 2, h: originalPageBounds.h / 2,
}) })
expect(editor.viewportPageCenter).toMatchObject({ expect(editor.getViewportPageCenter()).toMatchObject({
x: (originalCenter.x + change) / 2, x: (originalCenter.x + change) / 2,
y: (originalCenter.y + change) / 2, y: (originalCenter.y + change) / 2,
}) })
@ -142,9 +142,9 @@ describe('TLSelectTool.Zooming', () => {
const newBoundsX = 100 const newBoundsX = 100
const newBoundsY = 200 const newBoundsY = 200
editor.expectToBeIn('select.idle') editor.expectToBeIn('select.idle')
expect(editor.zoomLevel).toBe(1) expect(editor.getZoomLevel()).toBe(1)
expect(editor.viewportPageBounds).toMatchObject({ x: -0, y: -0, w: 1080, h: 720 }) expect(editor.getViewportPageBounds()).toMatchObject({ x: -0, y: -0, w: 1080, h: 720 })
expect(editor.viewportPageCenter).toMatchObject({ x: 540, y: 360 }) expect(editor.getViewportPageCenter()).toMatchObject({ x: 540, y: 360 })
editor.keyDown('z') editor.keyDown('z')
editor.expectToBeIn('zoom.idle') editor.expectToBeIn('zoom.idle')
editor.pointerDown(newBoundsX, newBoundsY) editor.pointerDown(newBoundsX, newBoundsY)
@ -157,14 +157,14 @@ describe('TLSelectTool.Zooming', () => {
}) })
editor.pointerUp(newBoundsX + newBoundsWidth, newBoundsY + newBoundsHeight) editor.pointerUp(newBoundsX + newBoundsWidth, newBoundsY + newBoundsHeight)
jest.advanceTimersByTime(300) jest.advanceTimersByTime(300)
expect(editor.zoomLevel).toBeCloseTo(1.2888) expect(editor.getZoomLevel()).toBeCloseTo(1.2888)
expect(editor.viewportPageBounds).toMatchObject({ expect(editor.getViewportPageBounds()).toMatchObject({
x: -48.9655172413793, x: -48.9655172413793,
y: 100.68965517241382, y: 100.68965517241382,
w: 837.9310344827586, w: 837.9310344827586,
h: 558.6206896551723, h: 558.6206896551723,
}) })
expect(editor.viewportPageCenter).toMatchObject({ expect(editor.getViewportPageCenter()).toMatchObject({
x: newBoundsX + newBoundsWidth / 2, x: newBoundsX + newBoundsWidth / 2,
y: newBoundsY + newBoundsHeight / 2, y: newBoundsY + newBoundsHeight / 2,
}) })
@ -178,9 +178,9 @@ describe('TLSelectTool.Zooming', () => {
const newBoundsY = 200 const newBoundsY = 200
editor.expectToBeIn('select.idle') editor.expectToBeIn('select.idle')
const originalZoomLevel = 1 const originalZoomLevel = 1
expect(editor.zoomLevel).toBe(originalZoomLevel) expect(editor.getZoomLevel()).toBe(originalZoomLevel)
expect(editor.viewportPageBounds).toMatchObject({ x: -0, y: -0, w: 1080, h: 720 }) expect(editor.getViewportPageBounds()).toMatchObject({ x: -0, y: -0, w: 1080, h: 720 })
expect(editor.viewportPageCenter).toMatchObject({ x: 540, y: 360 }) expect(editor.getViewportPageCenter()).toMatchObject({ x: 540, y: 360 })
editor.keyDown('z') editor.keyDown('z')
editor.expectToBeIn('zoom.idle') editor.expectToBeIn('zoom.idle')
editor.keyDown('Alt') editor.keyDown('Alt')
@ -194,14 +194,14 @@ describe('TLSelectTool.Zooming', () => {
}) })
editor.pointerUp() editor.pointerUp()
jest.advanceTimersByTime(500) jest.advanceTimersByTime(500)
expect(editor.zoomLevel).toBeCloseTo(originalZoomLevel / 2) expect(editor.getZoomLevel()).toBeCloseTo(originalZoomLevel / 2)
expect(editor.viewportPageBounds).toMatchObject({ expect(editor.getViewportPageBounds()).toMatchObject({
x: -440, x: -440,
y: -160, y: -160,
w: 2160, w: 2160,
h: 1440, h: 1440,
}) })
expect(editor.viewportPageCenter).toMatchObject({ expect(editor.getViewportPageCenter()).toMatchObject({
x: newBoundsX + newBoundsWidth / 2, x: newBoundsX + newBoundsWidth / 2,
y: newBoundsY + newBoundsHeight / 2, y: newBoundsY + newBoundsHeight / 2,
}) })

View file

@ -9,30 +9,30 @@ beforeEach(() => {
jest.useFakeTimers() jest.useFakeTimers()
it('zooms in gradually when duration is present and animtion speed is default', () => { it('zooms in gradually when duration is present and animtion speed is default', () => {
expect(editor.zoomLevel).toBe(1) expect(editor.getZoomLevel()).toBe(1)
editor.user.updateUserPreferences({ animationSpeed: 1 }) // default editor.user.updateUserPreferences({ animationSpeed: 1 }) // default
editor.zoomIn(undefined, { duration: 100 }) editor.zoomIn(undefined, { duration: 100 })
editor.emit('tick', 25) // <-- quarter way editor.emit('tick', 25) // <-- quarter way
expect(editor.zoomLevel).not.toBe(2) expect(editor.getZoomLevel()).not.toBe(2)
editor.emit('tick', 25) // 50 <-- half way editor.emit('tick', 25) // 50 <-- half way
expect(editor.zoomLevel).not.toBe(2) expect(editor.getZoomLevel()).not.toBe(2)
editor.emit('tick', 50) // 50 <-- done! editor.emit('tick', 50) // 50 <-- done!
expect(editor.zoomLevel).toBe(2) expect(editor.getZoomLevel()).toBe(2)
}) })
it('zooms in gradually when duration is present and animtion speed is off', () => { it('zooms in gradually when duration is present and animtion speed is off', () => {
expect(editor.zoomLevel).toBe(1) expect(editor.getZoomLevel()).toBe(1)
editor.user.updateUserPreferences({ animationSpeed: 0 }) // none editor.user.updateUserPreferences({ animationSpeed: 0 }) // none
editor.zoomIn(undefined, { duration: 100 }) editor.zoomIn(undefined, { duration: 100 })
expect(editor.zoomLevel).toBe(2) // <-- Should skip! expect(editor.getZoomLevel()).toBe(2) // <-- Should skip!
}) })
it('zooms in gradually when duration is present and animtion speed is double', () => { it('zooms in gradually when duration is present and animtion speed is double', () => {
expect(editor.zoomLevel).toBe(1) expect(editor.getZoomLevel()).toBe(1)
editor.user.updateUserPreferences({ animationSpeed: 2 }) // default editor.user.updateUserPreferences({ animationSpeed: 2 }) // default
editor.zoomIn(undefined, { duration: 100 }) editor.zoomIn(undefined, { duration: 100 })
editor.emit('tick', 25) // <-- half way editor.emit('tick', 25) // <-- half way
expect(editor.zoomLevel).not.toBe(2) expect(editor.getZoomLevel()).not.toBe(2)
editor.emit('tick', 25) // 50 <-- should finish editor.emit('tick', 25) // 50 <-- should finish
expect(editor.zoomLevel).toBe(2) expect(editor.getZoomLevel()).toBe(2)
}) })

View file

@ -8,14 +8,14 @@ beforeEach(() => {
it('centers on the point', () => { it('centers on the point', () => {
editor.centerOnPoint({ x: 400, y: 400 }) editor.centerOnPoint({ x: 400, y: 400 })
expect(editor.viewportPageCenter).toMatchObject({ x: 400, y: 400 }) expect(editor.getViewportPageCenter()).toMatchObject({ x: 400, y: 400 })
}) })
it('centers on the point with animation', () => { it('centers on the point with animation', () => {
editor.centerOnPoint({ x: 400, y: 400 }, { duration: 200 }) editor.centerOnPoint({ x: 400, y: 400 }, { duration: 200 })
expect(editor.viewportPageCenter).not.toMatchObject({ x: 400, y: 400 }) expect(editor.getViewportPageCenter()).not.toMatchObject({ x: 400, y: 400 })
jest.advanceTimersByTime(100) jest.advanceTimersByTime(100)
expect(editor.viewportPageCenter).not.toMatchObject({ x: 400, y: 400 }) expect(editor.getViewportPageCenter()).not.toMatchObject({ x: 400, y: 400 })
jest.advanceTimersByTime(200) jest.advanceTimersByTime(200)
expect(editor.viewportPageCenter).toMatchObject({ x: 400, y: 400 }) expect(editor.getViewportPageCenter()).toMatchObject({ x: 400, y: 400 })
}) })

View file

@ -78,7 +78,7 @@ describe('When copying and pasting', () => {
editor.setCamera({ editor.setCamera({
x: editor.getCamera().x - testOffsetX, x: editor.getCamera().x - testOffsetX,
y: editor.getCamera().y - testOffsetY, y: editor.getCamera().y - testOffsetY,
z: editor.zoomLevel, z: editor.getZoomLevel(),
}) })
editor.paste() editor.paste()
@ -123,7 +123,7 @@ describe('When copying and pasting', () => {
editor.setCamera({ editor.setCamera({
x: editor.getCamera().x - testOffsetX, x: editor.getCamera().x - testOffsetX,
y: editor.getCamera().y - testOffsetY, y: editor.getCamera().y - testOffsetY,
z: editor.zoomLevel, z: editor.getZoomLevel(),
}) })
editor.paste() editor.paste()
@ -161,11 +161,11 @@ describe('When copying and pasting', () => {
const testOffsetX = 2000 const testOffsetX = 2000
const testOffsetY = 3000 const testOffsetY = 3000
const { w: screenWidth, h: screenHeight } = editor.viewportScreenBounds const { w: screenWidth, h: screenHeight } = editor.getViewportScreenBounds()
editor.setCamera({ editor.setCamera({
x: editor.getCamera().x - testOffsetX, x: editor.getCamera().x - testOffsetX,
y: editor.getCamera().y - testOffsetY, y: editor.getCamera().y - testOffsetY,
z: editor.zoomLevel, z: editor.getZoomLevel(),
}) })
editor.paste() editor.paste()
@ -295,7 +295,7 @@ describe('When copying and pasting', () => {
editor.setCamera({ editor.setCamera({
x: editor.getCamera().x - testOffsetX, x: editor.getCamera().x - testOffsetX,
y: editor.getCamera().y - testOffsetY, y: editor.getCamera().y - testOffsetY,
z: editor.zoomLevel, z: editor.getZoomLevel(),
}) })
editor.paste() editor.paste()
@ -325,7 +325,7 @@ describe('When copying and pasting', () => {
editor.setCamera({ editor.setCamera({
x: editor.getCamera().x - testOffsetX, x: editor.getCamera().x - testOffsetX,
y: editor.getCamera().y - testOffsetY, y: editor.getCamera().y - testOffsetY,
z: editor.zoomLevel, z: editor.getZoomLevel(),
}) })
editor.paste() editor.paste()
@ -354,11 +354,11 @@ describe('When copying and pasting', () => {
const testOffsetX = 2000 const testOffsetX = 2000
const testOffsetY = 3000 const testOffsetY = 3000
const { w: screenWidth, h: screenHeight } = editor.viewportScreenBounds const { w: screenWidth, h: screenHeight } = editor.getViewportScreenBounds()
editor.setCamera({ editor.setCamera({
x: editor.getCamera().x - testOffsetX, x: editor.getCamera().x - testOffsetX,
y: editor.getCamera().y - testOffsetY, y: editor.getCamera().y - testOffsetY,
z: editor.zoomLevel, z: editor.getZoomLevel(),
}) })
editor.paste() editor.paste()

View file

@ -36,7 +36,7 @@ it('Duplicates a page', () => {
// Also duplicates the camera // Also duplicates the camera
expect(editor.getCamera().x).toBe(camera.x) expect(editor.getCamera().x).toBe(camera.x)
expect(editor.getCamera().y).toBe(camera.y) expect(editor.getCamera().y).toBe(camera.y)
expect(editor.zoomLevel).toBe(camera.z) expect(editor.getZoomLevel()).toBe(camera.z)
editor.undo() editor.undo()
expect(editor.pages.length).toBe(n) expect(editor.pages.length).toBe(n)

View file

@ -241,6 +241,6 @@ describe('arrows', () => {
editor.moveShapesToPage([ids.box1, ids.box2], ids.page2) editor.moveShapesToPage([ids.box1, ids.box2], ids.page2)
const selectionPageBounds = editor.getSelectionPageBounds() const selectionPageBounds = editor.getSelectionPageBounds()
expect(editor.viewportPageCenter).toMatchObject(selectionPageBounds!.center) expect(editor.getViewportPageCenter()).toMatchObject(selectionPageBounds!.center)
}) })
}) })

View file

@ -15,17 +15,17 @@ describe('When panning', () => {
}) })
it('Updates the pageBounds', () => { it('Updates the pageBounds', () => {
const screenBounds = editor.viewportScreenBounds const screenBounds = editor.getViewportScreenBounds()
const beforeScreenBounds = new Box2d( const beforeScreenBounds = new Box2d(
screenBounds.x, screenBounds.x,
screenBounds.y, screenBounds.y,
screenBounds.w, screenBounds.w,
screenBounds.h screenBounds.h
) )
const beforePageBounds = editor.viewportPageBounds.clone() const beforePageBounds = editor.getViewportPageBounds().clone()
editor.pan({ x: 200, y: 200 }) editor.pan({ x: 200, y: 200 })
expect(editor.viewportScreenBounds).toMatchObject(beforeScreenBounds.toJson()) expect(editor.getViewportScreenBounds()).toMatchObject(beforeScreenBounds.toJson())
expect(editor.viewportPageBounds.toJson()).toMatchObject( expect(editor.getViewportPageBounds().toJson()).toMatchObject(
beforePageBounds.translate(new Vec2d(-200, -200)).toJson() beforePageBounds.translate(new Vec2d(-200, -200)).toJson()
) )
}) })

View file

@ -8,23 +8,23 @@ beforeEach(() => {
describe('When resetting zoom', () => { describe('When resetting zoom', () => {
it('Resets the zoom when zoomed out', () => { it('Resets the zoom when zoomed out', () => {
const center = editor.viewportScreenBounds.center.clone() const center = editor.getViewportScreenBounds().center.clone()
editor.zoomOut() editor.zoomOut()
editor.resetZoom() editor.resetZoom()
expect(editor.zoomLevel).toBe(1) expect(editor.getZoomLevel()).toBe(1)
editor.zoomIn() editor.zoomIn()
editor.resetZoom() editor.resetZoom()
expect(editor.zoomLevel).toBe(1) expect(editor.getZoomLevel()).toBe(1)
expect(editor.viewportScreenBounds.center.clone()).toMatchObject(center) expect(editor.getViewportScreenBounds().center.clone()).toMatchObject(center)
}) })
it('Resets the zoom when zoomed in', () => { it('Resets the zoom when zoomed in', () => {
const center = editor.viewportScreenBounds.center.clone() const center = editor.getViewportScreenBounds().center.clone()
editor.zoomOut() editor.zoomOut()
editor.resetZoom() editor.resetZoom()
expect(editor.viewportScreenBounds.center.clone()).toMatchObject(center) expect(editor.getViewportScreenBounds().center.clone()).toMatchObject(center)
editor.zoomIn() editor.zoomIn()
editor.resetZoom() editor.resetZoom()
expect(editor.viewportScreenBounds.center.clone()).toMatchObject(center) expect(editor.getViewportScreenBounds().center.clone()).toMatchObject(center)
}) })
}) })

View file

@ -47,7 +47,9 @@ describe('viewport.screenToPage', () => {
}) })
it('converts correctly when offset', () => { it('converts correctly when offset', () => {
editor.updateInstanceState({ screenBounds: { ...editor.viewportScreenBounds, x: 100, y: 100 } }) editor.updateInstanceState({
screenBounds: { ...editor.getViewportScreenBounds(), x: 100, y: 100 },
})
checkScreenPage({ x: 0, y: 0 }, { x: -100, y: -100 }) checkScreenPage({ x: 0, y: 0 }, { x: -100, y: -100 })
checkScreenPage({ x: -100, y: -100 }, { x: -200, y: -200 }) checkScreenPage({ x: -100, y: -100 }, { x: -200, y: -200 })
@ -57,7 +59,9 @@ describe('viewport.screenToPage', () => {
it('converts correctly when zoomed out', () => { it('converts correctly when zoomed out', () => {
// camera at zero, screenbounds at zero, but zoom at .5 // camera at zero, screenbounds at zero, but zoom at .5
editor.setCamera({ x: 0, y: 0, z: 0.5 }) editor.setCamera({ x: 0, y: 0, z: 0.5 })
editor.updateInstanceState({ screenBounds: { ...editor.viewportScreenBounds, x: 0, y: 0 } }) editor.updateInstanceState({
screenBounds: { ...editor.getViewportScreenBounds(), x: 0, y: 0 },
})
checkScreenPage({ x: 0, y: 0 }, { x: 0, y: 0 }) checkScreenPage({ x: 0, y: 0 }, { x: 0, y: 0 })
checkScreenPage({ x: -100, y: -100 }, { x: -200, y: -200 }) checkScreenPage({ x: -100, y: -100 }, { x: -200, y: -200 })
@ -66,7 +70,9 @@ describe('viewport.screenToPage', () => {
it('converts correctly when zoomed in', () => { it('converts correctly when zoomed in', () => {
editor.setCamera({ x: 0, y: 0, z: 2 }) editor.setCamera({ x: 0, y: 0, z: 2 })
editor.updateInstanceState({ screenBounds: { ...editor.viewportScreenBounds, x: 0, y: 0 } }) editor.updateInstanceState({
screenBounds: { ...editor.getViewportScreenBounds(), x: 0, y: 0 },
})
checkScreenPage({ x: 0, y: 0 }, { x: 0, y: 0 }) checkScreenPage({ x: 0, y: 0 }, { x: 0, y: 0 })
checkScreenPage({ x: -100, y: -100 }, { x: -50, y: -50 }) checkScreenPage({ x: -100, y: -100 }, { x: -50, y: -50 })
@ -75,7 +81,9 @@ describe('viewport.screenToPage', () => {
it('converts correctly when zoomed', () => { it('converts correctly when zoomed', () => {
// camera at zero, screenbounds at zero, but zoom at .5 // camera at zero, screenbounds at zero, but zoom at .5
editor.updateInstanceState({ screenBounds: { ...editor.viewportScreenBounds, x: 0, y: 0 } }) editor.updateInstanceState({
screenBounds: { ...editor.getViewportScreenBounds(), x: 0, y: 0 },
})
editor.setCamera({ x: 0, y: 0, z: 0.5 }) editor.setCamera({ x: 0, y: 0, z: 0.5 })
checkScreenPage({ x: 0, y: 0 }, { x: 0, y: 0 }) checkScreenPage({ x: 0, y: 0 }, { x: 0, y: 0 })
@ -85,7 +93,9 @@ describe('viewport.screenToPage', () => {
it('converts correctly when offset and zoomed', () => { it('converts correctly when offset and zoomed', () => {
editor.setCamera({ x: 0, y: 0, z: 0.5 }) editor.setCamera({ x: 0, y: 0, z: 0.5 })
editor.updateInstanceState({ screenBounds: { ...editor.viewportScreenBounds, x: 100, y: 100 } }) editor.updateInstanceState({
screenBounds: { ...editor.getViewportScreenBounds(), x: 100, y: 100 },
})
checkScreenPage({ x: 0, y: 0 }, { x: -200, y: -200 }) checkScreenPage({ x: 0, y: 0 }, { x: -200, y: -200 })
checkScreenPage({ x: -100, y: -100 }, { x: -400, y: -400 }) checkScreenPage({ x: -100, y: -100 }, { x: -400, y: -400 })
@ -93,7 +103,9 @@ describe('viewport.screenToPage', () => {
}) })
it('converts correctly when zoomed and panned', () => { it('converts correctly when zoomed and panned', () => {
editor.updateInstanceState({ screenBounds: { ...editor.viewportScreenBounds, x: 0, y: 0 } }) editor.updateInstanceState({
screenBounds: { ...editor.getViewportScreenBounds(), x: 0, y: 0 },
})
editor.setCamera({ x: 100, y: 100, z: 0.5 }) editor.setCamera({ x: 100, y: 100, z: 0.5 })
checkScreenPage({ x: 0, y: 0 }, { x: -100, y: -100 }) checkScreenPage({ x: 0, y: 0 }, { x: -100, y: -100 })
@ -102,7 +114,9 @@ describe('viewport.screenToPage', () => {
}) })
it('converts correctly when offset', () => { it('converts correctly when offset', () => {
editor.updateInstanceState({ screenBounds: { ...editor.viewportScreenBounds, x: 100, y: 100 } }) editor.updateInstanceState({
screenBounds: { ...editor.getViewportScreenBounds(), x: 100, y: 100 },
})
editor.setCamera({ x: 0, y: 0, z: 0.5 }) editor.setCamera({ x: 0, y: 0, z: 0.5 })
checkScreenPage({ x: 0, y: 0 }, { x: -200, y: -200 }) checkScreenPage({ x: 0, y: 0 }, { x: -200, y: -200 })
@ -111,7 +125,9 @@ describe('viewport.screenToPage', () => {
}) })
it('converts correctly when panned', () => { it('converts correctly when panned', () => {
editor.updateInstanceState({ screenBounds: { ...editor.viewportScreenBounds, x: 0, y: 0 } }) editor.updateInstanceState({
screenBounds: { ...editor.getViewportScreenBounds(), x: 0, y: 0 },
})
editor.setCamera({ x: 100, y: 100, z: 1 }) editor.setCamera({ x: 100, y: 100, z: 1 })
checkScreenPage({ x: 0, y: 0 }, { x: -100, y: -100 }) checkScreenPage({ x: 0, y: 0 }, { x: -100, y: -100 })
@ -120,7 +136,9 @@ describe('viewport.screenToPage', () => {
}) })
it('converts correctly when panned and zoomed', () => { it('converts correctly when panned and zoomed', () => {
editor.updateInstanceState({ screenBounds: { ...editor.viewportScreenBounds, x: 0, y: 0 } }) editor.updateInstanceState({
screenBounds: { ...editor.getViewportScreenBounds(), x: 0, y: 0 },
})
editor.setCamera({ x: 100, y: 100, z: 0.5 }) editor.setCamera({ x: 100, y: 100, z: 0.5 })
checkScreenPage({ x: 0, y: 0 }, { x: -100, y: -100 }) checkScreenPage({ x: 0, y: 0 }, { x: -100, y: -100 })
@ -129,7 +147,9 @@ describe('viewport.screenToPage', () => {
}) })
it('converts correctly when panned and zoomed and offset', () => { it('converts correctly when panned and zoomed and offset', () => {
editor.updateInstanceState({ screenBounds: { ...editor.viewportScreenBounds, x: 100, y: 100 } }) editor.updateInstanceState({
screenBounds: { ...editor.getViewportScreenBounds(), x: 100, y: 100 },
})
editor.setCamera({ x: 100, y: 100, z: 0.5 }) editor.setCamera({ x: 100, y: 100, z: 0.5 })
checkScreenPage({ x: 0, y: 0 }, { x: -300, y: -300 }) checkScreenPage({ x: 0, y: 0 }, { x: -300, y: -300 })
@ -141,11 +161,11 @@ describe('viewport.screenToPage', () => {
describe('viewportPageBounds', () => { describe('viewportPageBounds', () => {
it('sets the page bounds', () => { it('sets the page bounds', () => {
editor.updateInstanceState({ editor.updateInstanceState({
screenBounds: { ...editor.viewportScreenBounds, x: 0, y: 0, w: 1000, h: 1000 }, screenBounds: { ...editor.getViewportScreenBounds(), x: 0, y: 0, w: 1000, h: 1000 },
}) })
editor.setCamera({ x: 0, y: 0, z: 1 }) editor.setCamera({ x: 0, y: 0, z: 1 })
expect(editor.viewportPageBounds).toMatchObject({ expect(editor.getViewportPageBounds()).toMatchObject({
x: -0, x: -0,
y: -0, y: -0,
w: 1000, w: 1000,
@ -155,11 +175,11 @@ describe('viewportPageBounds', () => {
it('sets the page bounds when camera is zoomed', () => { it('sets the page bounds when camera is zoomed', () => {
editor.updateInstanceState({ editor.updateInstanceState({
screenBounds: { ...editor.viewportScreenBounds, x: 0, y: 0, w: 1000, h: 1000 }, screenBounds: { ...editor.getViewportScreenBounds(), x: 0, y: 0, w: 1000, h: 1000 },
}) })
editor.setCamera({ x: 0, y: 0, z: 2 }) editor.setCamera({ x: 0, y: 0, z: 2 })
expect(editor.viewportPageBounds).toMatchObject({ expect(editor.getViewportPageBounds()).toMatchObject({
x: -0, x: -0,
y: -0, y: -0,
w: 500, w: 500,
@ -167,7 +187,7 @@ describe('viewportPageBounds', () => {
}) })
editor.setCamera({ x: 0, y: 0, z: 0.5 }) editor.setCamera({ x: 0, y: 0, z: 0.5 })
expect(editor.viewportPageBounds).toMatchObject({ expect(editor.getViewportPageBounds()).toMatchObject({
x: -0, x: -0,
y: -0, y: -0,
w: 2000, w: 2000,
@ -177,11 +197,11 @@ describe('viewportPageBounds', () => {
it('sets the page bounds when camera is panned', () => { it('sets the page bounds when camera is panned', () => {
editor.updateInstanceState({ editor.updateInstanceState({
screenBounds: { ...editor.viewportScreenBounds, x: 0, y: 0, w: 1000, h: 1000 }, screenBounds: { ...editor.getViewportScreenBounds(), x: 0, y: 0, w: 1000, h: 1000 },
}) })
editor.setCamera({ x: 100, y: 100, z: 1 }) editor.setCamera({ x: 100, y: 100, z: 1 })
expect(editor.viewportPageBounds).toMatchObject({ expect(editor.getViewportPageBounds()).toMatchObject({
x: -100, x: -100,
y: -100, y: -100,
w: 1000, w: 1000,
@ -193,11 +213,11 @@ describe('viewportPageBounds', () => {
it('sets the page bounds when camera is panned and zoomed', () => { it('sets the page bounds when camera is panned and zoomed', () => {
editor.updateInstanceState({ editor.updateInstanceState({
screenBounds: { ...editor.viewportScreenBounds, x: 0, y: 0, w: 1000, h: 1000 }, screenBounds: { ...editor.getViewportScreenBounds(), x: 0, y: 0, w: 1000, h: 1000 },
}) })
editor.setCamera({ x: 100, y: 100, z: 2 }) editor.setCamera({ x: 100, y: 100, z: 2 })
expect(editor.viewportPageBounds).toMatchObject({ expect(editor.getViewportPageBounds()).toMatchObject({
x: -100, x: -100,
y: -100, y: -100,
w: 500, w: 500,
@ -209,12 +229,12 @@ describe('viewportPageBounds', () => {
it('sets the page bounds when viewport is offset', () => { it('sets the page bounds when viewport is offset', () => {
editor.updateInstanceState({ editor.updateInstanceState({
screenBounds: { ...editor.viewportScreenBounds, x: 100, y: 100, w: 1000, h: 1000 }, screenBounds: { ...editor.getViewportScreenBounds(), x: 100, y: 100, w: 1000, h: 1000 },
}) })
editor.setCamera({ x: 0, y: 0, z: 2 }) editor.setCamera({ x: 0, y: 0, z: 2 })
// changing the screen bounds should not affect the page bounds // changing the screen bounds should not affect the page bounds
expect(editor.viewportPageBounds).toMatchObject({ expect(editor.getViewportPageBounds()).toMatchObject({
x: -0, x: -0,
y: -0, y: -0,
w: 500, w: 500,

View file

@ -17,7 +17,7 @@ beforeEach(() => {
describe('When resizing', () => { describe('When resizing', () => {
it('sets the viewport bounds with Editor.resize', () => { it('sets the viewport bounds with Editor.resize', () => {
editor.setScreenBounds({ x: 100, y: 200, w: 700, h: 600 }) editor.setScreenBounds({ x: 100, y: 200, w: 700, h: 600 })
expect(editor.viewportScreenBounds).toMatchObject({ expect(editor.getViewportScreenBounds()).toMatchObject({
x: 100, x: 100,
y: 200, y: 200,
w: 700, w: 700,
@ -30,7 +30,7 @@ describe('When resizing', () => {
editor.undo() // this should have no effect editor.undo() // this should have no effect
expect(editor.viewportScreenBounds).toMatchObject({ expect(editor.getViewportScreenBounds()).toMatchObject({
x: 100, x: 100,
y: 200, y: 200,
w: 700, w: 700,
@ -40,7 +40,7 @@ describe('When resizing', () => {
it('clamps bounds to minimim 0,0,1,1', () => { it('clamps bounds to minimim 0,0,1,1', () => {
editor.setScreenBounds({ x: -100, y: -200, w: -700, h: 0 }) editor.setScreenBounds({ x: -100, y: -200, w: -700, h: 0 })
expect(editor.viewportScreenBounds).toMatchObject({ expect(editor.getViewportScreenBounds()).toMatchObject({
x: -100, x: -100,
y: -200, y: -200,
w: 1, w: 1,
@ -54,7 +54,7 @@ describe('When center is false', () => {
const a = editor.screenToPage({ x: 0, y: 0 }) const a = editor.screenToPage({ x: 0, y: 0 })
expect(a).toMatchObject({ x: 0, y: 0 }) expect(a).toMatchObject({ x: 0, y: 0 })
editor.setScreenBounds({ x: 100, y: 200, w: 500, h: 600 }, false) editor.setScreenBounds({ x: 100, y: 200, w: 500, h: 600 }, false)
expect(editor.viewportScreenBounds).toMatchObject({ expect(editor.getViewportScreenBounds()).toMatchObject({
x: 100, x: 100,
y: 200, y: 200,
w: 500, w: 500,
@ -70,7 +70,7 @@ describe('When center is false', () => {
expect(a).toMatchObject({ x: 100, y: 100 }) expect(a).toMatchObject({ x: 100, y: 100 })
editor.setScreenBounds({ x: 100, y: 200, w: 500, h: 600 }, false) editor.setScreenBounds({ x: 100, y: 200, w: 500, h: 600 }, false)
expect(editor.viewportScreenBounds).toMatchObject({ expect(editor.getViewportScreenBounds()).toMatchObject({
x: 100, x: 100,
y: 200, y: 200,
w: 500, w: 500,
@ -87,7 +87,7 @@ describe('When center is false', () => {
expect(editor.screenToPage({ x: 0, y: 0 })).toMatchObject({ x: 100, y: 100 }) expect(editor.screenToPage({ x: 0, y: 0 })).toMatchObject({ x: 100, y: 100 })
editor.setScreenBounds({ x: 100, y: 100, w: 500, h: 600 }, false) editor.setScreenBounds({ x: 100, y: 100, w: 500, h: 600 }, false)
expect(editor.viewportScreenBounds).toMatchObject({ expect(editor.getViewportScreenBounds()).toMatchObject({
x: 100, x: 100,
y: 100, y: 100,
w: 500, w: 500,
@ -99,17 +99,17 @@ describe('When center is false', () => {
describe('When center is true', () => { describe('When center is true', () => {
it('keep the same page center when resized', () => { it('keep the same page center when resized', () => {
const a = editor.viewportPageCenter.toJson() const a = editor.getViewportPageCenter().toJson()
editor.setScreenBounds({ x: 100, y: 200, w: 500, h: 600 }, true) editor.setScreenBounds({ x: 100, y: 200, w: 500, h: 600 }, true)
const b = editor.viewportPageCenter.toJson() const b = editor.getViewportPageCenter().toJson()
expect(a).toMatchObject(b) expect(a).toMatchObject(b)
}) })
it('keep the same page center when resized while panned / zoomed', () => { it('keep the same page center when resized while panned / zoomed', () => {
editor.setCamera({ x: -100, y: -100, z: 1.2 }) editor.setCamera({ x: -100, y: -100, z: 1.2 })
const a = editor.viewportPageCenter.toJson() const a = editor.getViewportPageCenter().toJson()
editor.setScreenBounds({ x: 100, y: 200, w: 500, h: 600 }, true) editor.setScreenBounds({ x: 100, y: 200, w: 500, h: 600 }, true)
const b = editor.viewportPageCenter.toJson() const b = editor.getViewportPageCenter().toJson()
expect(a).toMatchObject(b) expect(a).toMatchObject(b)
}) })
}) })

View file

@ -9,29 +9,29 @@ beforeEach(() => {
it('zooms by increments', () => { it('zooms by increments', () => {
// Starts at 1 // Starts at 1
expect(editor.zoomLevel).toBe(1) expect(editor.getZoomLevel()).toBe(1)
expect(editor.zoomLevel).toBe(ZOOMS[3]) expect(editor.getZoomLevel()).toBe(ZOOMS[3])
// zooms in // zooms in
expect(editor.zoomLevel).toBe(ZOOMS[3]) expect(editor.getZoomLevel()).toBe(ZOOMS[3])
editor.zoomIn() editor.zoomIn()
expect(editor.zoomLevel).toBe(ZOOMS[4]) expect(editor.getZoomLevel()).toBe(ZOOMS[4])
editor.zoomIn() editor.zoomIn()
expect(editor.zoomLevel).toBe(ZOOMS[5]) expect(editor.getZoomLevel()).toBe(ZOOMS[5])
editor.zoomIn() editor.zoomIn()
expect(editor.zoomLevel).toBe(ZOOMS[6]) expect(editor.getZoomLevel()).toBe(ZOOMS[6])
// does not zoom in past max // does not zoom in past max
editor.zoomIn() editor.zoomIn()
expect(editor.zoomLevel).toBe(ZOOMS[6]) expect(editor.getZoomLevel()).toBe(ZOOMS[6])
}) })
it('zooms to from B to D when B >= (C - A)/2, else zooms from B to C', () => { it('zooms to from B to D when B >= (C - A)/2, else zooms from B to C', () => {
editor.setCamera({ x: 0, y: 0, z: (ZOOMS[2] + ZOOMS[3]) / 2 }) editor.setCamera({ x: 0, y: 0, z: (ZOOMS[2] + ZOOMS[3]) / 2 })
editor.zoomIn() editor.zoomIn()
expect(editor.zoomLevel).toBe(ZOOMS[4]) expect(editor.getZoomLevel()).toBe(ZOOMS[4])
editor.setCamera({ x: 0, y: 0, z: (ZOOMS[2] + ZOOMS[3]) / 2 - 0.1 }) editor.setCamera({ x: 0, y: 0, z: (ZOOMS[2] + ZOOMS[3]) / 2 - 0.1 })
editor.zoomIn() editor.zoomIn()
expect(editor.zoomLevel).toBe(ZOOMS[3]) expect(editor.getZoomLevel()).toBe(ZOOMS[3])
}) })
it('does not zoom when camera is frozen', () => { it('does not zoom when camera is frozen', () => {

View file

@ -9,17 +9,17 @@ beforeEach(() => {
it('zooms by increments', () => { it('zooms by increments', () => {
// Starts at 1 // Starts at 1
expect(editor.zoomLevel).toBe(1) expect(editor.getZoomLevel()).toBe(1)
expect(editor.zoomLevel).toBe(ZOOMS[3]) expect(editor.getZoomLevel()).toBe(ZOOMS[3])
editor.zoomOut() editor.zoomOut()
expect(editor.zoomLevel).toBe(ZOOMS[2]) expect(editor.getZoomLevel()).toBe(ZOOMS[2])
editor.zoomOut() editor.zoomOut()
expect(editor.zoomLevel).toBe(ZOOMS[1]) expect(editor.getZoomLevel()).toBe(ZOOMS[1])
editor.zoomOut() editor.zoomOut()
expect(editor.zoomLevel).toBe(ZOOMS[0]) expect(editor.getZoomLevel()).toBe(ZOOMS[0])
// does not zoom out past min // does not zoom out past min
editor.zoomOut() editor.zoomOut()
expect(editor.zoomLevel).toBe(ZOOMS[0]) expect(editor.getZoomLevel()).toBe(ZOOMS[0])
}) })
it('does not zoom out when camera is frozen', () => { it('does not zoom out when camera is frozen', () => {

View file

@ -9,15 +9,15 @@ beforeEach(() => {
describe('When zooming to bounds', () => { describe('When zooming to bounds', () => {
it('centers the camera on the new bounds', () => { it('centers the camera on the new bounds', () => {
expect(editor.viewportPageCenter).toMatchObject({ x: 540, y: 360 }) expect(editor.getViewportPageCenter()).toMatchObject({ x: 540, y: 360 })
editor.setScreenBounds({ x: 0, y: 0, w: 1000, h: 1000 }) editor.setScreenBounds({ x: 0, y: 0, w: 1000, h: 1000 })
expect(editor.viewportPageCenter).toMatchObject({ x: 500, y: 500 }) expect(editor.getViewportPageCenter()).toMatchObject({ x: 500, y: 500 })
editor.setCamera({ x: 0, y: 0, z: 1 }) editor.setCamera({ x: 0, y: 0, z: 1 })
expect(editor.viewportPageBounds).toCloselyMatchObject({ expect(editor.getViewportPageBounds()).toCloselyMatchObject({
x: -0, x: -0,
y: -0, y: -0,
w: 1000, w: 1000,
@ -26,25 +26,25 @@ describe('When zooming to bounds', () => {
editor.zoomToBounds(new Box2d(200, 300, 300, 300)) editor.zoomToBounds(new Box2d(200, 300, 300, 300))
expect(editor.getCamera().z).toCloselyMatchObject((1000 - 256) / 300) expect(editor.getCamera().z).toCloselyMatchObject((1000 - 256) / 300)
expect(editor.viewportPageBounds.width).toCloselyMatchObject(1000 / ((1000 - 256) / 300)) expect(editor.getViewportPageBounds().width).toCloselyMatchObject(1000 / ((1000 - 256) / 300))
expect(editor.viewportPageBounds.height).toCloselyMatchObject(1000 / ((1000 - 256) / 300)) expect(editor.getViewportPageBounds().height).toCloselyMatchObject(1000 / ((1000 - 256) / 300))
}) })
}) })
it('does not zoom past max', () => { it('does not zoom past max', () => {
editor.zoomToBounds(new Box2d(0, 0, 1, 1)) editor.zoomToBounds(new Box2d(0, 0, 1, 1))
expect(editor.zoomLevel).toBe(8) expect(editor.getZoomLevel()).toBe(8)
}) })
it('does not zoom past min', () => { it('does not zoom past min', () => {
editor.zoomToBounds(new Box2d(0, 0, 1000000, 100000)) editor.zoomToBounds(new Box2d(0, 0, 1000000, 100000))
expect(editor.zoomLevel).toBe(0.1) expect(editor.getZoomLevel()).toBe(0.1)
}) })
it('does not zoom to bounds when camera is frozen', () => { it('does not zoom to bounds when camera is frozen', () => {
editor.setScreenBounds({ x: 0, y: 0, w: 1000, h: 1000 }) editor.setScreenBounds({ x: 0, y: 0, w: 1000, h: 1000 })
expect(editor.viewportPageCenter.toJson()).toCloselyMatchObject({ x: 500, y: 500 }) expect(editor.getViewportPageCenter().toJson()).toCloselyMatchObject({ x: 500, y: 500 })
editor.updateInstanceState({ canMoveCamera: false }) editor.updateInstanceState({ canMoveCamera: false })
editor.zoomToBounds(new Box2d(200, 300, 300, 300)) editor.zoomToBounds(new Box2d(200, 300, 300, 300))
expect(editor.viewportPageCenter.toJson()).toCloselyMatchObject({ x: 500, y: 500 }) expect(editor.getViewportPageCenter().toJson()).toCloselyMatchObject({ x: 500, y: 500 })
}) })

View file

@ -23,14 +23,14 @@ it('does not zoom past max', () => {
editor.updateShapes([{ id: ids.box1, type: 'geo', props: { w: 1, h: 1 } }]) editor.updateShapes([{ id: ids.box1, type: 'geo', props: { w: 1, h: 1 } }])
editor.select(ids.box1) editor.select(ids.box1)
editor.zoomToSelection() editor.zoomToSelection()
expect(editor.zoomLevel).toBe(1) // double check again when we're zooming in hard expect(editor.getZoomLevel()).toBe(1) // double check again when we're zooming in hard
}) })
it('does not zoom past min', () => { it('does not zoom past min', () => {
editor.updateShapes([{ id: ids.box1, type: 'geo', props: { w: 100000, h: 100000 } }]) editor.updateShapes([{ id: ids.box1, type: 'geo', props: { w: 100000, h: 100000 } }])
editor.select(ids.box1) editor.select(ids.box1)
editor.zoomToSelection() editor.zoomToSelection()
expect(editor.zoomLevel).toBe(0.1) expect(editor.getZoomLevel()).toBe(0.1)
}) })
it('does not zoom to selection when camera is frozen', () => { it('does not zoom to selection when camera is frozen', () => {

View file

@ -460,11 +460,11 @@ describe('When pasting into frames...', () => {
{ {
id: ids.frame1, id: ids.frame1,
type: 'frame', type: 'frame',
x: editor.viewportScreenBounds.w, x: editor.getViewportScreenBounds().w,
y: editor.viewportScreenBounds.h, y: editor.getViewportScreenBounds().h,
props: { props: {
w: editor.viewportScreenBounds.w, w: editor.getViewportScreenBounds().w,
h: editor.viewportScreenBounds.h, h: editor.getViewportScreenBounds().h,
}, },
}, },
]) ])
@ -472,7 +472,11 @@ describe('When pasting into frames...', () => {
// rotate the frame for hard mode // rotate the frame for hard mode
editor.rotateSelection(45) editor.rotateSelection(45)
// center on the center of the frame // center on the center of the frame
editor.setCamera({ x: -editor.viewportScreenBounds.w, y: -editor.viewportScreenBounds.h, z: 1 }) editor.setCamera({
x: -editor.getViewportScreenBounds().w,
y: -editor.getViewportScreenBounds().h,
z: 1,
})
// paste the box // paste the box
editor.paste() editor.paste()
const boxId = editor.getOnlySelectedShape()!.id const boxId = editor.getOnlySelectedShape()!.id

View file

@ -562,7 +562,7 @@ describe('snapping with single shapes', () => {
editor.pointerDown(25, 5, ids.box2).pointerMove(36, 5, { ctrlKey: true }) editor.pointerDown(25, 5, ids.box2).pointerMove(36, 5, { ctrlKey: true })
expect(editor.snaps.lines!.length).toBe(0) expect(editor.snaps.lines!.length).toBe(0)
editor.updateShapes([{ id: ids.box1, type: 'geo', x: editor.viewportScreenBounds.w + 10 }]) editor.updateShapes([{ id: ids.box1, type: 'geo', x: editor.getViewportScreenBounds().w + 10 }])
editor.pointerMove(33, 5, { ctrlKey: true }) editor.pointerMove(33, 5, { ctrlKey: true })
expect(editor.snaps.lines!.length).toBe(0) expect(editor.snaps.lines!.length).toBe(0)
@ -572,7 +572,7 @@ describe('snapping with single shapes', () => {
expect(editor.snaps.lines!.length).toBe(0) expect(editor.snaps.lines!.length).toBe(0)
editor.updateShapes([ editor.updateShapes([
{ id: ids.box1, type: 'geo', x: 0, y: editor.viewportScreenBounds.h + 10 }, { id: ids.box1, type: 'geo', x: 0, y: editor.getViewportScreenBounds().h + 10 },
]) ])
editor.pointerMove(5, 5, { ctrlKey: true }) editor.pointerMove(5, 5, { ctrlKey: true })