[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:
parent
7e4fb59a48
commit
1014a71abb
3 changed files with 29 additions and 47 deletions
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in a new issue