pull/3282/head
Steve Ruiz 2024-04-18 17:38:32 +01:00
rodzic caf9ec4ee1
commit e929bdd133
7 zmienionych plików z 70 dodań i 76 usunięć

Wyświetl plik

@ -18,12 +18,12 @@ const CAMERA_OPTIONS: TLCameraOptions = {
zoomSpeed: 1,
zoomSteps: [0.1, 0.25, 0.5, 1, 2, 4, 8],
constraints: {
fit: 'max',
resetDimension: 'max',
bounds: {
x: 0,
y: 0,
w: 1200,
h: 800,
w: 1600,
h: 900,
},
fitX: 'contain',
fitY: 'contain',
@ -281,12 +281,12 @@ const CameraOptionsControlPanel = track(() => {
<label htmlFor="fit">Fit</label>
<select
name="fit"
value={constraints.fit}
value={constraints.resetDimension}
onChange={(e) => {
updateOptions({
constraints: {
...constraints,
fit: e.target.value as any,
resetDimension: e.target.value as any,
},
})
}}

Wyświetl plik

@ -133,7 +133,7 @@ export function ImageAnnotationEditor({
editor.setCameraOptions(
{
constraints: {
fit: 'max',
resetDimension: 'max',
bounds: { w: image.width, h: image.height, x: 0, y: 0 },
padding: { x: 32, y: 64 },
origin: { x: 0.5, y: 0.5 },
@ -145,7 +145,7 @@ export function ImageAnnotationEditor({
panSpeed: 1,
isLocked: false,
},
{ initial: isInitial }
{ reset: isInitial }
)
isInitial = false

Wyświetl plik

@ -895,11 +895,7 @@ export class Editor extends EventEmitter<TLEventMap> {
sendBackward(shapes: TLShape[] | TLShapeId[]): this;
sendToBack(shapes: TLShape[] | TLShapeId[]): this;
setCamera(point: VecLike, opts?: TLCameraMoveOptions): this;
setCameraOptions(options: Partial<TLCameraOptions>, opts?: {
force?: boolean;
immediate?: boolean;
initial?: boolean;
}): this;
setCameraOptions(options: Partial<TLCameraOptions>, opts?: TLCameraMoveOptions): this;
setCroppingShape(shape: null | TLShape | TLShapeId): this;
setCurrentPage(page: TLPage | TLPageId, historyOptions?: TLCommandHistoryOptions): this;
setCurrentTool(id: string, info?: {}): this;
@ -1997,8 +1993,8 @@ export type TLBrushProps = {
// @public (undocumented)
export type TLCameraMoveOptions = Partial<{
animation: Partial<{
duration: number;
easing: (t: number) => number;
duration: number;
}>;
force: boolean;
immediate: boolean;
@ -2013,7 +2009,7 @@ export type TLCameraOptions = {
bounds: BoxModel;
origin: VecLike;
padding: VecLike;
fit: 'max' | 'min' | 'none' | 'x' | 'y';
resetDimension: 'max' | 'min' | 'none' | 'x' | 'y';
};
panSpeed: number;
zoomSpeed: number;

Wyświetl plik

@ -17060,8 +17060,9 @@
"text": ", opts?: "
},
{
"kind": "Content",
"text": "{\n force?: boolean;\n immediate?: boolean;\n initial?: boolean;\n }"
"kind": "Reference",
"text": "TLCameraMoveOptions",
"canonicalReference": "@tldraw/editor!TLCameraMoveOptions:type"
},
{
"kind": "Content",
@ -36940,14 +36941,14 @@
},
{
"kind": "Content",
"text": "<{\n duration: number;\n easing: (t: number) => number;\n }>;\n force: boolean;\n immediate: boolean;\n reset: boolean;\n}>"
"text": "<{\n easing: (t: number) => number;\n duration: number;\n }>;\n force: boolean;\n immediate: boolean;\n reset: boolean;\n}>"
},
{
"kind": "Content",
"text": ";"
}
],
"fileUrlPath": "packages/editor/src/lib/editor/Editor.ts",
"fileUrlPath": "packages/editor/src/lib/editor/types/misc-types.ts",
"releaseTag": "Public",
"name": "TLCameraMoveOptions",
"typeTokenRange": {
@ -36993,7 +36994,7 @@
},
{
"kind": "Content",
"text": ";\n fit: 'max' | 'min' | 'none' | 'x' | 'y';\n };\n panSpeed: number;\n zoomSpeed: number;\n zoomSteps: number[];\n isLocked: boolean;\n wheelBehavior: 'none' | 'pan' | 'zoom';\n}"
"text": ";\n resetDimension: 'max' | 'min' | 'none' | 'x' | 'y';\n };\n panSpeed: number;\n zoomSpeed: number;\n zoomSteps: number[];\n isLocked: boolean;\n wheelBehavior: 'none' | 'pan' | 'zoom';\n}"
},
{
"kind": "Content",

Wyświetl plik

@ -122,12 +122,7 @@ export {
SIDES,
SVG_PADDING,
} from './lib/constants'
export {
Editor,
type TLCameraMoveOptions,
type TLEditorOptions,
type TLResizeShapeOptions,
} from './lib/editor/Editor'
export { Editor, type TLEditorOptions, type TLResizeShapeOptions } from './lib/editor/Editor'
export type {
SideEffectManager,
TLAfterChangeHandler,
@ -240,6 +235,7 @@ export {
} from './lib/editor/types/history-types'
export {
type RequiredKeys,
type TLCameraMoveOptions,
type TLCameraOptions,
type TLSvgOptions,
} from './lib/editor/types/misc-types'

Wyświetl plik

@ -134,20 +134,15 @@ import {
} from './types/event-types'
import { TLExternalAssetContent, TLExternalContent } from './types/external-content'
import { TLCommandHistoryOptions } from './types/history-types'
import { OptionalKeys, RequiredKeys, TLCameraOptions, TLSvgOptions } from './types/misc-types'
import {
OptionalKeys,
RequiredKeys,
TLCameraMoveOptions,
TLCameraOptions,
TLSvgOptions,
} from './types/misc-types'
import { TLResizeHandle } from './types/selection-types'
/** @public */
export type TLCameraMoveOptions = Partial<{
animation: Partial<{
duration: number
easing: (t: number) => number
}>
immediate: boolean
force: boolean
reset: boolean
}>
/** @public */
export type TLResizeShapeOptions = Partial<{
initialBounds: Box
@ -2079,7 +2074,7 @@ export class Editor extends EventEmitter<TLEventMap> {
* @public */
getCameraFitZoom() {
const cameraOptions = this.getCameraOptions()
if (!cameraOptions.constraints || cameraOptions.constraints.fit === 'none') {
if (!cameraOptions.constraints || cameraOptions.constraints.resetDimension === 'none') {
return 1
}
const { padding } = cameraOptions.constraints
@ -2090,7 +2085,7 @@ export class Editor extends EventEmitter<TLEventMap> {
const zx = (vsb.w - px * 2) / bounds.w
const zy = (vsb.h - py * 2) / bounds.h
switch (cameraOptions.constraints.fit) {
switch (cameraOptions.constraints.resetDimension) {
case 'min': {
return Math.max(zx, zy)
}
@ -2104,7 +2099,7 @@ export class Editor extends EventEmitter<TLEventMap> {
return zy
}
default: {
throw exhaustiveSwitchError(cameraOptions.constraints.fit)
throw exhaustiveSwitchError(cameraOptions.constraints.resetDimension)
}
}
}
@ -2137,10 +2132,7 @@ export class Editor extends EventEmitter<TLEventMap> {
* @param opts - The options for the change.
*
* @public */
setCameraOptions(
options: Partial<TLCameraOptions>,
opts?: { immediate?: boolean; force?: boolean; initial?: boolean }
) {
setCameraOptions(options: Partial<TLCameraOptions>, opts?: TLCameraMoveOptions) {
const next = { ...this._cameraOptions.__unsafe__getWithoutCapture(), ...options }
if (next.zoomSteps?.length < 1) next.zoomSteps = [1]
this._cameraOptions.set(next)
@ -2149,10 +2141,7 @@ export class Editor extends EventEmitter<TLEventMap> {
}
/** @internal */
private _setCamera(
point: VecLike,
opts?: { immediate?: boolean; force?: boolean; initial?: boolean }
): this {
private _setCamera(point: VecLike, opts?: TLCameraMoveOptions): this {
const currentCamera = this.getCamera()
let { x, y, z = currentCamera.z } = point
@ -2168,12 +2157,12 @@ export class Editor extends EventEmitter<TLEventMap> {
const zoomMin = cameraOptions.zoomSteps[0]
const zoomMax = last(cameraOptions.zoomSteps)!
const vsb = this.getViewportScreenBounds()
// If bounds are provided, then we'll keep those bounds on screen
if (cameraOptions.constraints) {
const { constraints } = cameraOptions
const vsb = this.getViewportScreenBounds()
// Get padding (it's either a number or an array of 2 numbers for t/b, l/r)
// Clamp padding to half the viewport size on either dimension
const py = Math.min(constraints.padding.y, vsb.w / 2)
@ -2193,7 +2182,7 @@ export class Editor extends EventEmitter<TLEventMap> {
let fitZoom = 1
switch (cameraOptions.constraints.fit) {
switch (cameraOptions.constraints.resetDimension) {
case 'min': {
fitZoom = Math.max(zx, zy)
break
@ -2215,7 +2204,7 @@ export class Editor extends EventEmitter<TLEventMap> {
const maxZ = zoomMax * fitZoom
const minZ = zoomMin * fitZoom
if (opts?.initial) {
if (opts?.reset) {
z = fitZoom
}
@ -2233,16 +2222,22 @@ export class Editor extends EventEmitter<TLEventMap> {
y = cy + cyB - cyA
}
// Calculate available space
const minX = px / z - bounds.x
const minY = py / z - bounds.y
const freeW = (vsb.w - px * 2) / z - bounds.w
const freeH = (vsb.h - py * 2) / z - bounds.h
const originX = minX + freeW * constraints.origin.x
const originY = minY + freeH * constraints.origin.y
// x axis
const minX = px / z - bounds.x
const freeW = (vsb.w - px * 2) / z - bounds.w
const originX = minX + freeW * constraints.origin.x
if (opts?.initial) {
// Center according to the origin
if (opts?.reset) {
// Reset the camera according to the origin
x = originX
y = originY
} else {
// Apply constraints to the camera
switch (constraints.fitX) {
case 'lock': {
// Center according to the origin
@ -2269,17 +2264,9 @@ export class Editor extends EventEmitter<TLEventMap> {
break
}
}
}
// y axis
// y axis
const minY = py / z - bounds.y
const freeH = (vsb.h - py * 2) / z - bounds.h
const originY = minY + freeH * constraints.origin.y
if (opts?.initial) {
y = originY
} else {
switch (constraints.fitY) {
case 'lock': {
y = originY
@ -2303,9 +2290,7 @@ export class Editor extends EventEmitter<TLEventMap> {
}
} else {
// constrain the zoom, preserving the center
if (z > zoomMax || z < zoomMin) {
const vsb = this.getViewportScreenBounds()
const { x: cx, y: cy, z: cz } = currentCamera
const cxA = -cx + vsb.w / cz / 2
const cyA = -cy + vsb.h / cz / 2
@ -2756,11 +2741,10 @@ export class Editor extends EventEmitter<TLEventMap> {
const { isLocked, panSpeed } = this.getCameraOptions()
if (isLocked) return this
const { x: cx, y: cy, z: cz } = this.getCamera()
this.setCamera(
new Vec(cx + (offset.x * panSpeed) / cz, cy + (offset.y * panSpeed) / cz, cz),
opts
)
this._flushEventsForTick(0)
this.setCamera(new Vec(cx + (offset.x * panSpeed) / cz, cy + (offset.y * panSpeed) / cz, cz), {
...opts,
immediate: true,
})
return this
}

Wyświetl plik

@ -17,6 +17,23 @@ export type TLSvgOptions = {
preserveAspectRatio: React.SVGAttributes<SVGSVGElement>['preserveAspectRatio']
}
/** @public */
export type TLCameraMoveOptions = Partial<{
/** Whether to move the camera immediately, rather than on the next tick. */
immediate: boolean
/** Whether to force the camera to move, even if the user's camera options have locked the camera. */
force: boolean
/** Whether to reset the camera to its default position and zoom. */
reset: boolean
/** An (optional) animation to use. */
animation: Partial<{
/** The time the animation should take to arrive at the specified camera coordinates. */
duration: number
/** An easing function to apply to the animation's progress from start to end. */
easing: (t: number) => number
}>
}>
/** @public */
export type TLCameraOptions = {
wheelBehavior: 'zoom' | 'pan' | 'none'
@ -30,8 +47,8 @@ export type TLCameraOptions = {
isLocked: boolean
/** The camera constraints */
constraints?: {
/** The type of constraint behavior. */
fit: 'min' | 'max' | 'x' | 'y' | 'none'
/** Which dimension to fit when the camera is reset. */
resetDimension: 'min' | 'max' | 'x' | 'y' | 'none'
/** The behavior for the constraints on the x axis. */
fitX: 'contain' | 'inside' | 'outside' | 'lock'
/** The behavior for the constraints on the y axis. */