[fix] minimap, common page bounds (#1770)

This PR fixes a bug that was introduced (by me) in #1751, where:
- the `commonBoundsOfAllShapesOnCurrentPage` would mutate the first
bounding box
- the render reactor would fire too often

### Change Type

- [x] `patch` — Bug fix

### Test Plan

1. Use the minimap
This commit is contained in:
Steve Ruiz 2023-07-27 17:01:01 +01:00 committed by GitHub
parent 7e4fb59a48
commit 1014a71abb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 29 additions and 47 deletions

View file

@ -4227,7 +4227,7 @@ export class Editor extends EventEmitter<TLEventMap> {
const bounds = this.getMaskedPageBounds(shapeId)
if (!bounds) return
if (!commonBounds) {
commonBounds = bounds
commonBounds = bounds.clone()
} else {
commonBounds = commonBounds.expand(bounds)
}

View file

@ -8,9 +8,9 @@ import {
intersectPolygonPolygon,
normalizeWheel,
setPointerCapture,
track,
useContainer,
useComputed,
useEditor,
useIsDarkMode,
useQuickReactor,
} from '@tldraw/editor'
import * as React from 'react'
@ -22,30 +22,22 @@ export interface MinimapProps {
viewportFill: string
}
export const Minimap = track(function Minimap({
shapeFill,
selectFill,
viewportFill,
}: MinimapProps) {
export function Minimap({ shapeFill, selectFill, viewportFill }: MinimapProps) {
const editor = useEditor()
const rCanvas = React.useRef<HTMLCanvasElement>(null!)
const container = useContainer()
const rPointing = React.useRef(false)
const minimap = React.useMemo(
() => new MinimapManager(editor, editor.instanceState.devicePixelRatio),
[editor]
)
const isDarkMode = useIsDarkMode()
const devicePixelRatio = useComputed('dpr', () => editor.instanceState.devicePixelRatio, [editor])
const presences = React.useMemo(() => editor.store.query.records('instance_presence'), [editor])
const isDarkMode = editor.user.isDarkMode
const minimap = React.useMemo(() => new MinimapManager(editor), [editor])
React.useEffect(() => {
// Must check after render
const raf = requestAnimationFrame(() => {
const style = getComputedStyle(container)
const style = getComputedStyle(editor.getContainer())
minimap.colors = {
shapeFill: style.getPropertyValue(shapeFill).trim(),
@ -58,7 +50,7 @@ export const Minimap = track(function Minimap({
return () => {
cancelAnimationFrame(raf)
}
}, [container, selectFill, shapeFill, viewportFill, minimap, isDarkMode])
}, [editor, selectFill, shapeFill, viewportFill, minimap, isDarkMode])
const onDoubleClick = React.useCallback(
(e: React.MouseEvent<HTMLCanvasElement>) => {
@ -163,17 +155,15 @@ export const Minimap = track(function Minimap({
// Update the minimap's dpr when the dpr changes
useQuickReactor(
'update dpr',
'update when dpr changes',
() => {
const {
instanceState: { devicePixelRatio },
} = editor
minimap.setDpr(devicePixelRatio)
const dpr = devicePixelRatio.value
minimap.setDpr(dpr)
const canvas = rCanvas.current as HTMLCanvasElement
const rect = canvas.getBoundingClientRect()
const width = rect.width * devicePixelRatio
const height = rect.height * devicePixelRatio
const width = rect.width * dpr
const height = rect.height * dpr
// These must happen in order
canvas.width = width
@ -182,26 +172,19 @@ export const Minimap = track(function Minimap({
minimap.cvs = rCanvas.current
},
[editor, minimap]
[devicePixelRatio, minimap]
)
const presences = React.useMemo(() => {
return editor.store.query.records('instance_presence')
}, [editor])
useQuickReactor(
'minimap render when pagebounds or collaborators changes',
() => {
const {
instanceState: { devicePixelRatio },
viewportPageBounds,
commonBoundsOfAllShapesOnCurrentPage: allShapesCommonBounds,
} = editor
const { shapeIdsOnCurrentPage, viewportPageBounds, commonBoundsOfAllShapesOnCurrentPage } =
editor
devicePixelRatio // dereference dpr so that it renders then, too
const _dpr = devicePixelRatio.value
minimap.contentPageBounds = allShapesCommonBounds
? Box2d.Expand(allShapesCommonBounds, viewportPageBounds)
minimap.contentPageBounds = commonBoundsOfAllShapesOnCurrentPage
? Box2d.Expand(commonBoundsOfAllShapesOnCurrentPage, viewportPageBounds)
: viewportPageBounds
minimap.updateContentScreenBounds()
@ -210,8 +193,9 @@ export const Minimap = track(function Minimap({
const allShapeBounds = [] as (Box2d & { id: TLShapeId })[]
editor.shapeIdsOnCurrentPage.forEach((id) => {
let pageBounds = editor.getPageBounds(id)! as Box2d & { id: TLShapeId }
shapeIdsOnCurrentPage.forEach((id) => {
let pageBounds = editor.getPageBounds(id) as Box2d & { id: TLShapeId }
if (!pageBounds) return
const pageMask = editor.getPageMask(id)
@ -230,11 +214,7 @@ export const Minimap = track(function Minimap({
})
minimap.pageBounds = allShapeBounds
// Collaborators
minimap.collaborators = presences.value
minimap.render()
},
[editor, minimap]
@ -253,4 +233,4 @@ export const Minimap = track(function Minimap({
/>
</div>
)
})
}

View file

@ -10,7 +10,9 @@ import {
} from '@tldraw/editor'
export class MinimapManager {
constructor(public editor: Editor, private dpr: number) {}
constructor(public editor: Editor) {}
dpr = 1
colors = {
shapeFill: 'rgba(144, 144, 144, .1)',
@ -212,7 +214,6 @@ export class MinimapManager {
const by = ry / 4
// shapes
const shapesPath = new Path2D()
const selectedPath = new Path2D()
@ -234,6 +235,7 @@ export class MinimapManager {
clamp(ry, ay, pb.height / by)
)
}
// Fill the shapes paths
ctx.fillStyle = shapeFill
ctx.fill(shapesPath)