From 0260f5da5da410847450147c23e3b3578076dd79 Mon Sep 17 00:00:00 2001 From: Peng Xiao Date: Thu, 17 Nov 2022 16:50:45 +0800 Subject: [PATCH] refactor(whiteboard): using canvas to render the whiteboard grid dots --- .../src/components/Devtools/Devtools.tsx | 10 ++ .../src/components/StatusBar/StatusBar.tsx | 24 +---- tldraw/packages/core/src/lib/TLSettings.ts | 2 +- tldraw/packages/react/package.json | 1 + .../react/src/components/ui/Grid/Grid.tsx | 98 ++++++++++++++----- .../packages/react/src/hooks/useStylesheet.ts | 7 ++ tldraw/yarn.lock | 2 +- 7 files changed, 94 insertions(+), 50 deletions(-) diff --git a/tldraw/apps/tldraw-logseq/src/components/Devtools/Devtools.tsx b/tldraw/apps/tldraw-logseq/src/components/Devtools/Devtools.tsx index 5a7fcc70c..1545b8f4b 100644 --- a/tldraw/apps/tldraw-logseq/src/components/Devtools/Devtools.tsx +++ b/tldraw/apps/tldraw-logseq/src/components/Devtools/Devtools.tsx @@ -84,6 +84,15 @@ export const DevTools = observer(() => { .map(p => p.join('')) .join('|') + const originPoint = canvasAnchorRef.current + ? ReactDOM.createPortal( + + + , + canvasAnchorRef.current + ) + : null + const rendererStatus = statusbarAnchorRef.current ? ReactDOM.createPortal(
{ return ( <> + {originPoint} {rendererStatus} diff --git a/tldraw/apps/tldraw-logseq/src/components/StatusBar/StatusBar.tsx b/tldraw/apps/tldraw-logseq/src/components/StatusBar/StatusBar.tsx index 45cda5553..68a635557 100644 --- a/tldraw/apps/tldraw-logseq/src/components/StatusBar/StatusBar.tsx +++ b/tldraw/apps/tldraw-logseq/src/components/StatusBar/StatusBar.tsx @@ -1,33 +1,11 @@ /* eslint-disable @typescript-eslint/no-non-null-assertion */ /* eslint-disable @typescript-eslint/no-explicit-any */ -import * as React from 'react' -import { observer } from 'mobx-react-lite' import { useApp } from '@tldraw/react' +import { observer } from 'mobx-react-lite' import type { Shape } from '../../lib' export const StatusBar = observer(function StatusBar() { const app = useApp() - React.useEffect(() => { - const canvas = document.querySelector('.logseq-tldraw-wrapper .tl-canvas') - const actionBar = document.querySelector('.logseq-tldraw-wrapper .tl-action-bar') - if (canvas) { - canvas.style.height = 'calc(100% - 32px)' - } - - if (actionBar) { - actionBar.style.marginBottom = '32px' - } - - return () => { - if (canvas) { - canvas.style.height = '100%' - } - - if (actionBar) { - actionBar.style.marginBottom = '0px' - } - } - }) return (
{app.selectedTool.id} | {app.selectedTool.currentState.id} diff --git a/tldraw/packages/core/src/lib/TLSettings.ts b/tldraw/packages/core/src/lib/TLSettings.ts index 1e1baa16e..9852c453e 100644 --- a/tldraw/packages/core/src/lib/TLSettings.ts +++ b/tldraw/packages/core/src/lib/TLSettings.ts @@ -13,7 +13,7 @@ export class TLSettings implements TLSettingsProps { } @observable mode: 'dark' | 'light' = 'light' - @observable showGrid = !isSafari() + @observable showGrid = true @action update(props: Partial): void { Object.assign(this, props) diff --git a/tldraw/packages/react/package.json b/tldraw/packages/react/package.json index ae3713fc2..77aa8dec2 100644 --- a/tldraw/packages/react/package.json +++ b/tldraw/packages/react/package.json @@ -41,6 +41,7 @@ "mobx": "^6.6.2", "mobx-react-lite": "^3.4.0", "mousetrap": "^1.6.5", + "polished": "^4.2.2", "rbush": "^3.0.1", "uuid": "^8.0.0" }, diff --git a/tldraw/packages/react/src/components/ui/Grid/Grid.tsx b/tldraw/packages/react/src/components/ui/Grid/Grid.tsx index ce6ab2ee3..fae6c62a9 100644 --- a/tldraw/packages/react/src/components/ui/Grid/Grid.tsx +++ b/tldraw/packages/react/src/components/ui/Grid/Grid.tsx @@ -1,5 +1,7 @@ import { modulate } from '@tldraw/core' import { observer } from 'mobx-react-lite' +import { transparentize } from 'polished' +import React from 'react' import { useRendererContext } from '../../../hooks' import type { TLGridProps } from '../../../types' @@ -15,35 +17,81 @@ export const Grid = observer(function Grid({ size }: TLGridProps) { const { viewport: { camera: { point, zoom }, + bounds, }, } = useRendererContext() - return ( - - - {STEPS.map(([min, mid, _size], i) => { - const s = _size * size * zoom + + const ref = React.useRef(null) + + // Use useEffect will cause the render flickering + React.useLayoutEffect(() => { + if (ref.current) { + const canvas = ref.current + if (canvas?.getContext) { + const fillColor = getComputedStyle(canvas) + .getPropertyValue('--ls-quaternary-background-color') + .trim() + const ctx = canvas.getContext('2d') + if (ctx && fillColor) { + const { width, height } = canvas + // fill the canvas with dots + ctx.clearRect(0, 0, width, height) + const xo = point[0] * zoom const yo = point[1] * zoom - const gxo = xo > 0 ? xo % s : s + (xo % s) - const gyo = yo > 0 ? yo % s : s + (yo % s) - const opacity = zoom < mid ? modulate(zoom, [min, mid], [0, 1]) : 1 - return ( - - - - ) - })} - - {STEPS.map((_, i) => ( - - ))} - + STEPS.forEach(([min, mid, _size]) => { + const s = _size * size * zoom + const gxo = xo > 0 ? xo % s : s + (xo % s) + const gyo = yo > 0 ? yo % s : s + (yo % s) + const opacity = zoom < mid ? modulate(zoom, [min, mid], [0, 1], true) : 1 + ctx.fillStyle = transparentize(1 - opacity, fillColor) + + if (opacity < 0.5 || s < 32) return + for (let i = gyo; i < height; i += s) { + for (let j = gxo; j < width; j += s) { + ctx.beginPath() + ctx.arc(j, i, 1.5, 0, 2 * Math.PI) + ctx.closePath() + ctx.fill() + } + } + // Pattern should have better performance, but I cannot make the offset correctly ... + // for (let i = 0; i < height; i += _size) { + // const y = i * _size + // for (let j = 0; j < width; j += _size) { + // const x = j * _size + // ctx.fillRect(x, y, _size, _size) + // } + // } + // const pattern = document.createElement('canvas').getContext('2d') + // if (pattern) { + // const s = _size * size * zoom + // if (s < 1) { + // return + // } + // const xo = point[0] * zoom + // const yo = point[1] * zoom + // const gxo = xo > 0 ? xo % s : s + (xo % s) + // const gyo = yo > 0 ? yo % s : s + (yo % s) + // const opacity = zoom < mid ? modulate(zoom, [min, mid], [0, 1]) : 1 + // pattern.canvas.width = s + // pattern.canvas.height = s + // pattern.beginPath() + // pattern.arc(gxo, gyo, 1.5, 0, 2 * Math.PI) + // pattern.fillStyle = transparentize(1 - opacity, fillColor) + // pattern.fill() + // pattern.closePath() + // ctx.fillStyle = ctx.createPattern(pattern.canvas, 'repeat')! + // ctx.fillRect(0, 0, width, height) + // } + }) + } + } + } + }, [point[0], point[1], zoom, bounds.width, bounds.height]) + + return ( + ) }) diff --git a/tldraw/packages/react/src/hooks/useStylesheet.ts b/tldraw/packages/react/src/hooks/useStylesheet.ts index 06b8b292e..110c1ef3e 100644 --- a/tldraw/packages/react/src/hooks/useStylesheet.ts +++ b/tldraw/packages/react/src/hooks/useStylesheet.ts @@ -421,6 +421,13 @@ const tlcss = css` color: var(--tl-background); } + .tl-grid-canvas { + position: absolute; + touch-action: none; + pointer-events: none; + user-select: none; + } + .tl-grid { position: absolute; width: 100%; diff --git a/tldraw/yarn.lock b/tldraw/yarn.lock index 9f6e47244..9c8b4635f 100644 --- a/tldraw/yarn.lock +++ b/tldraw/yarn.lock @@ -3669,7 +3669,7 @@ pirates@^4.0.1: resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.5.tgz#feec352ea5c3268fb23a37c702ab1699f35a5f3b" integrity sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ== -polished@^4.0.0: +polished@^4.0.0, polished@^4.2.2: version "4.2.2" resolved "https://registry.yarnpkg.com/polished/-/polished-4.2.2.tgz#2529bb7c3198945373c52e34618c8fe7b1aa84d1" integrity sha512-Sz2Lkdxz6F2Pgnpi9U5Ng/WdWAUZxmHrNPoVlm3aAemxoy2Qy7LGjQg4uf8qKelDAUW94F4np3iH2YPf2qefcQ==