annotate onthecanvas example (#2459)

I've changed this example a little bit to add some hints to the user,
similar to the only-editor example. I also removed snaplines: null from
the components object because it seemed a bit unnecessary.

### Change Type

- [ ] `patch` — Bug fix
- [ ] `minor` — New feature
- [ ] `major` — Breaking change
- [ ] `dependencies` — Changes to package dependencies[^1]
- [x] `documentation` — Changes to the documentation only[^2]
- [ ] `tests` — Changes to any test code only[^2]
- [ ] `internal` — Any other changes that don't affect the published
package[^2]
- [ ] I don't know

[^1]: publishes a `patch` release, for devDependencies use `internal`
[^2]: will not publish a new version

### Test Plan

1. Add a step-by-step description of how to test your PR here.
2.

- [ ] Unit Tests
- [ ] End to end tests

### Release Notes

- annotate onthecanvas example
This commit is contained in:
Taha 2024-01-12 15:56:37 +00:00 committed by GitHub
parent 6fdd0987b0
commit 1cf6b4ff51
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -9,7 +9,9 @@ import {
import '@tldraw/tldraw/tldraw.css' import '@tldraw/tldraw/tldraw.css'
import { useState } from 'react' import { useState } from 'react'
// The "OnTheCanvas" component is rendered on top of the canvas, but behind the UI. // There's a guide at the bottom of this file!
// [1]
function MyComponent() { function MyComponent() {
const [state, setState] = useState(0) const [state, setState] = useState(0)
@ -20,46 +22,49 @@ function MyComponent() {
position: 'absolute', position: 'absolute',
top: 50, top: 50,
left: 50, left: 50,
width: 'fit-content', width: 200,
padding: 12, padding: 12,
borderRadius: 8, borderRadius: 8,
backgroundColor: 'goldenrod', backgroundColor: 'goldenrod',
zIndex: 0, zIndex: 0,
pointerEvents: 'all',
userSelect: 'unset', userSelect: 'unset',
boxShadow: '0 0 0 1px rgba(0,0,0,0.1), 0 4px 8px rgba(0,0,0,0.1)',
}} }}
onPointerDown={stopEventPropagation} onPointerDown={stopEventPropagation}
onPointerMove={stopEventPropagation} onPointerMove={stopEventPropagation}
> >
The count is {state}! <button onClick={() => setState((s) => s - 1)}>-1</button> <p>The count is {state}! </p>
<button onClick={() => setState((s) => s - 1)}>-1</button>
<p>These components are on the canvas. They will scale with camera zoom like shapes.</p>
</div> </div>
<div <div
style={{ style={{
position: 'absolute', position: 'absolute',
top: 150, top: 210,
left: 150, left: 150,
width: 128, width: 200,
padding: 12, padding: 12,
borderRadius: 8, borderRadius: 8,
backgroundColor: 'pink', backgroundColor: 'pink',
zIndex: 99999999, zIndex: 99999999,
pointerEvents: 'all',
userSelect: 'unset', userSelect: 'unset',
boxShadow: '0 0 0 1px rgba(0,0,0,0.1), 0 4px 8px rgba(0,0,0,0.1)',
}} }}
onPointerDown={stopEventPropagation} onPointerDown={stopEventPropagation}
onPointerMove={stopEventPropagation} onPointerMove={stopEventPropagation}
> >
The count is {state}! <button onClick={() => setState((s) => s + 1)}>+1</button> <p>The count is {state}! </p>
<button onClick={() => setState((s) => s + 1)}>+1</button>
<p>Create and select a shape to see the in front of the canvas component</p>
</div> </div>
</> </>
) )
} }
// The "InFrontOfTheCanvas" component is rendered on top of the canvas, but behind the UI. //[2]
const MyComponentInFront = track(() => { const MyComponentInFront = track(() => {
const editor = useEditor() const editor = useEditor()
const selectionRotatedPageBounds = editor.getSelectionRotatedPageBounds() const selectionRotatedPageBounds = editor.getSelectionRotatedPageBounds()
if (!selectionRotatedPageBounds) return null if (!selectionRotatedPageBounds) return null
const pageCoordinates = Vec.Sub( const pageCoordinates = Vec.Sub(
@ -73,21 +78,25 @@ const MyComponentInFront = track(() => {
position: 'absolute', position: 'absolute',
top: Math.max(64, pageCoordinates.y - 64), top: Math.max(64, pageCoordinates.y - 64),
left: Math.max(64, pageCoordinates.x), left: Math.max(64, pageCoordinates.x),
padding: 12, borderRadius: 8,
paddingLeft: 10,
paddingRight: 10,
background: '#efefef', background: '#efefef',
boxShadow: '0 0 0 1px rgba(0,0,0,0.1), 0 4px 8px rgba(0,0,0,0.1)',
}} }}
> >
This does not scale with the zoom <p>This won't scale with zoom.</p>
</div> </div>
) )
}) })
// [3]
const components: TLEditorComponents = { const components: TLEditorComponents = {
OnTheCanvas: MyComponent, OnTheCanvas: MyComponent,
InFrontOfTheCanvas: MyComponentInFront, InFrontOfTheCanvas: MyComponentInFront,
SnapLine: null,
} }
// [4]
export default function OnTheCanvasExample() { export default function OnTheCanvasExample() {
return ( return (
<div className="tldraw__editor"> <div className="tldraw__editor">
@ -95,3 +104,39 @@ export default function OnTheCanvasExample() {
</div> </div>
) )
} }
/*
This example shows how you can use the onTheCanvas and inFrontOfTheCanvas components.
onTheCanvas components will behave similarly to shapes, they will scale with the zoom
and move when the page is panned. inFrontOfTheCanvas components don't scale with the
zoom, but still move when the page is panned.
For another example that shows how to customize components, check out the custom
components example.
To have a component that ignores the camera entirely, you should check out the custom
UI example.
[1]
This is our onTheCanvas component. We also stop event propagation on the pointer events
so that we don't accidentally select shapes when interacting with the component.
[2]
This is our inFrontOfTheCanvas component. We want to render this next to a selected shape,
so we need to make sure it's reactive to changes in the editor. We use the track function
to make sure the component is re-rendered whenever the selection changes. Check out the
Signia docs for more info: https://signia.tldraw.dev/docs/API/signia_react/functions/track
Using the editor instance we can get the bounds of the selection box and convert them to
screen coordinates. We then render the component at those coordinates.
[3]
This is where we define the object that will be passed to the Tldraw component prop.
[4]
This is where we render the Tldraw component. Let's pass the components object to the
components prop.
*/