Improve performance of culling (#3272)

This PR tweaks the logic of _when_ we update the viewport screen bounds.
Previously, we updated every one second in order to capture any changes
to the viewport's screen position. In this PR, we _check_ every one
second and update the screen bounds if the viewport's screen position
has actually changed. Since we also update the rendering shapes when
this happens, it would cause the rendering / culling shapes to update
while the camera was moving.

I've also removed the "maximum time before we start culling shapes", as
this wasn't very useful and could also cause frames to start dropping
without recovering.


https://github.com/tldraw/tldraw/assets/23072548/9f474481-30c9-49b4-a009-66775ca6a0c1

### Change Type

<!--  Please select a 'Scope' label ️ -->

- [x] `sdk` — Changes the tldraw SDK
- [ ] `dotcom` — Changes the tldraw.com web app
- [ ] `docs` — Changes to the documentation, examples, or templates.
- [ ] `vs code` — Changes to the vscode plugin
- [ ] `internal` — Does not affect user-facing stuff

<!--  Please select a 'Type' label ️ -->

- [ ] `bugfix` — Bug fix
- [ ] `feature` — New feature
- [x] `improvement` — Improving existing features
- [ ] `chore` — Updating dependencies, other boring stuff
- [ ] `galaxy brain` — Architectural changes
- [ ] `tests` — Changes to any test code
- [ ] `tools` — Changes to infrastructure, CI, internal scripts,
debugging tools, etc.
- [ ] `dunno` — I don't know


### Test Plan

1. Zoom and pan around
2. Culled shapes should only update when you stop moving the camera.

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

### Release Notes

- Improve performance of the canvas when many shapes are present.
This commit is contained in:
Steve Ruiz 2024-03-28 09:42:48 +00:00 committed by GitHub
parent 408a269114
commit d399c027fd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 11 additions and 15 deletions

View file

@ -87,9 +87,6 @@ export const INTERNAL_POINTER_IDS = {
/** @internal */
export const CAMERA_MOVING_TIMEOUT = 64
/** @internal */
export const CAMERA_MAX_RENDERING_INTERVAL = 620
/** @public */
export const HIT_TEST_MARGIN = 8

View file

@ -66,7 +66,6 @@ import { TLUser, createTLUser } from '../config/createTLUser'
import { checkShapesAndAddCore } from '../config/defaultShapes'
import {
ANIMATION_MEDIUM_MS,
CAMERA_MAX_RENDERING_INTERVAL,
CAMERA_MOVING_TIMEOUT,
CAMERA_SLIDE_FRICTION,
COARSE_DRAG_DISTANCE,
@ -3085,10 +3084,6 @@ export class Editor extends EventEmitter<TLEventMap> {
this._lastUpdateRenderingBoundsTimestamp = now // don't render right away
this._cameraState.set('moving')
this.on('tick', this._decayCameraStateTimeout)
} else {
if (now - this._lastUpdateRenderingBoundsTimestamp > CAMERA_MAX_RENDERING_INTERVAL) {
this.updateRenderingBounds()
}
}
}

View file

@ -7,20 +7,24 @@ export function useScreenBounds(ref: React.RefObject<HTMLElement>) {
const editor = useEditor()
useLayoutEffect(() => {
let prevBounds = new Box()
function updateScreenBounds() {
const container = ref.current
if (!container) return null
const rect = container.getBoundingClientRect()
editor.updateViewportScreenBounds(
new Box(
rect.left || rect.x,
rect.top || rect.y,
Math.max(rect.width, 1),
Math.max(rect.height, 1)
)
const next = new Box(
rect.left || rect.x,
rect.top || rect.y,
Math.max(rect.width, 1),
Math.max(rect.height, 1)
)
if (prevBounds.equals(next)) return
editor.updateViewportScreenBounds(next)
prevBounds = next
}
// Set the initial bounds