File size: 1,960 Bytes
6f91ce5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
import { BindingUtil, type BindingOnShapeChangeOptions } from 'tldraw'
import { NOTE_PIN_TYPE, notePinMigrations, notePinProps, type NotePinBinding } from '../../shared/bindings'

type Options = BindingOnShapeChangeOptions<NotePinBinding>

const near = (a: number, b: number) => Math.abs(a - b) < 0.5

/**
 * A built-in note pinned to a paper card, after tldraw's sticker-bindings example: the note keeps
 * its offset as the paper moves, and stays (unpinned) when the paper is deleted, because the
 * editor removes the binding along with the paper.
 */
export class NotePinBindingUtil extends BindingUtil<NotePinBinding> {
	static override type = NOTE_PIN_TYPE
	static override props = notePinProps
	static override migrations = notePinMigrations

	override getDefaultProps() {
		return { dx: 0, dy: 0 }
	}

	// the paper moved: bring the note along
	override onAfterChangeToShape({ binding, shapeAfter }: Options) {
		const note = this.editor.getShape(binding.fromId)
		if (!note) return
		const paper = this.editor.getShapePageTransform(shapeAfter).point()
		const target = { x: paper.x + binding.props.dx, y: paper.y + binding.props.dy }
		const current = this.editor.getShapePageTransform(note).point()
		if (near(current.x, target.x) && near(current.y, target.y)) return
		const { x, y } = this.editor.getPointInParentSpace(note, target)
		this.editor.updateShape({ id: note.id, type: note.type, x, y })
	}

	// the note itself was moved: keep its new place next to the paper
	override onAfterChangeFromShape({ binding, shapeAfter }: Options) {
		const paper = this.editor.getShape(binding.toId)
		if (!paper) return
		const p = this.editor.getShapePageTransform(paper).point()
		const n = this.editor.getShapePageTransform(shapeAfter).point()
		const dx = n.x - p.x
		const dy = n.y - p.y
		if (near(dx, binding.props.dx) && near(dy, binding.props.dy)) return
		this.editor.updateBinding({ id: binding.id, type: binding.type, props: { dx, dy } })
	}
}