From 4f00e326ff4bc369295b79e12cc79e74543708b1 Mon Sep 17 00:00:00 2001 From: Konstantinos Kaloutas Date: Wed, 14 Jun 2023 16:43:02 +0300 Subject: [PATCH] feat: snap to grip --- src/resources/dicts/en.edn | 2 ++ .../src/components/ActionBar/ActionBar.tsx | 31 +++++++++++++++++++ .../LogseqPortalTool/states/CreatingState.tsx | 10 ++++-- tldraw/packages/core/src/lib/TLApi/TLApi.ts | 6 ++++ tldraw/packages/core/src/lib/TLApp/TLApp.ts | 1 - tldraw/packages/core/src/lib/TLSettings.ts | 2 ++ tldraw/packages/core/src/lib/TLViewport.ts | 2 +- .../tools/TLBoxTool/states/CreatingState.tsx | 7 ++++- .../TLSelectTool/states/ResizingState.ts | 6 ++++ .../TLSelectTool/states/TranslatingState.ts | 15 ++++++--- 10 files changed, 73 insertions(+), 9 deletions(-) diff --git a/src/resources/dicts/en.edn b/src/resources/dicts/en.edn index 886eb535a0e..e729ef4dc80 100644 --- a/src/resources/dicts/en.edn +++ b/src/resources/dicts/en.edn @@ -354,6 +354,8 @@ :whiteboard/search-only-pages "Search only pages" :whiteboard/cache-outdated "Cache is outdated. Please click the 'Re-index' button in the graph's dropdown menu." :whiteboard/shape-quick-links "Shape Quick Links" + :whiteboard/toggle-grid "Toggle grid" + :whiteboard/snap-to-grid "Snap to grid" :page-search "Search in the current page" :graph-search "Search graph" :home "Home" diff --git a/tldraw/apps/tldraw-logseq/src/components/ActionBar/ActionBar.tsx b/tldraw/apps/tldraw-logseq/src/components/ActionBar/ActionBar.tsx index 51f4df3df02..1435eec0e31 100644 --- a/tldraw/apps/tldraw-logseq/src/components/ActionBar/ActionBar.tsx +++ b/tldraw/apps/tldraw-logseq/src/components/ActionBar/ActionBar.tsx @@ -6,6 +6,7 @@ import * as React from 'react' import type { Shape } from '../../lib' import { TablerIcon } from '../icons' import { Button } from '../Button' +import { ToggleInput } from '../inputs/ToggleInput' import { ZoomMenu } from '../ZoomMenu' import * as Separator from '@radix-ui/react-separator' import { LogseqContext } from '../../lib/logseq-context' @@ -32,6 +33,14 @@ export const ActionBar = observer(function ActionBar(): JSX.Element { app.api.zoomOut() }, [app]) + const toggleGrid = React.useCallback(() => { + app.api.toggleGrid() + }, [app]) + + const toggleSnapToGrid = React.useCallback(() => { + app.api.toggleSnapToGrid() + }, [app]) + return (
{!app.readOnly && ( @@ -55,6 +64,28 @@ export const ActionBar = observer(function ActionBar(): JSX.Element {
+ +
+ + + + + + + +
) }) diff --git a/tldraw/apps/tldraw-logseq/src/lib/tools/LogseqPortalTool/states/CreatingState.tsx b/tldraw/apps/tldraw-logseq/src/lib/tools/LogseqPortalTool/states/CreatingState.tsx index 2f4a3cbf50d..fedd94490d6 100644 --- a/tldraw/apps/tldraw-logseq/src/lib/tools/LogseqPortalTool/states/CreatingState.tsx +++ b/tldraw/apps/tldraw-logseq/src/lib/tools/LogseqPortalTool/states/CreatingState.tsx @@ -1,4 +1,4 @@ -import { TLApp, TLTargetType, TLToolState, uniqueId } from '@tldraw/core' +import { TLApp, TLTargetType, TLToolState, uniqueId, GRID_SIZE } from '@tldraw/core' import type { TLReactEventMap, TLReactEvents } from '@tldraw/react' import Vec from '@tldraw/vec' import { transaction } from 'mobx' @@ -20,10 +20,16 @@ export class CreatingState extends TLToolState< onEnter = () => { this.app.history.pause() transaction(() => { + let point = Vec.sub(this.app.inputs.originPoint, this.offset) + + if (this.app.settings.snapToGrid) { + point = Vec.snap(point, GRID_SIZE) + } + const shape = new LogseqPortalShape({ id: uniqueId(), parentId: this.app.currentPage.id, - point: Vec.sub(this.app.inputs.originPoint, this.offset), + point: point, size: LogseqPortalShape.defaultProps.size, fill: this.app.settings.color, stroke: this.app.settings.color, diff --git a/tldraw/packages/core/src/lib/TLApi/TLApi.ts b/tldraw/packages/core/src/lib/TLApi/TLApi.ts index 90d91e113ee..3b6989fb05c 100644 --- a/tldraw/packages/core/src/lib/TLApi/TLApi.ts +++ b/tldraw/packages/core/src/lib/TLApi/TLApi.ts @@ -172,6 +172,12 @@ export class TLApi { + const { settings } = this.app + settings.update({ snapToGrid: !settings.snapToGrid }) + return this + } + setColor = (color: string): this => { const { settings } = this.app diff --git a/tldraw/packages/core/src/lib/TLApp/TLApp.ts b/tldraw/packages/core/src/lib/TLApp/TLApp.ts index 92463664453..548cbebe966 100644 --- a/tldraw/packages/core/src/lib/TLApp/TLApp.ts +++ b/tldraw/packages/core/src/lib/TLApp/TLApp.ts @@ -10,7 +10,6 @@ import type { TLCallback, TLEventMap, TLEvents, - TLShortcut, TLStateEvents, TLSubscription, TLSubscriptionEventInfo, diff --git a/tldraw/packages/core/src/lib/TLSettings.ts b/tldraw/packages/core/src/lib/TLSettings.ts index e79b7d14089..c6383ef6f8f 100644 --- a/tldraw/packages/core/src/lib/TLSettings.ts +++ b/tldraw/packages/core/src/lib/TLSettings.ts @@ -4,6 +4,7 @@ import { observable, makeObservable, action } from 'mobx' export interface TLSettingsProps { mode: 'light' | 'dark' showGrid: boolean + snapToGrid: boolean color: string scaleLevel: string } @@ -15,6 +16,7 @@ export class TLSettings implements TLSettingsProps { @observable mode: 'dark' | 'light' = 'light' @observable showGrid = true + @observable snapToGrid = true @observable scaleLevel = 'md' @observable color = '' diff --git a/tldraw/packages/core/src/lib/TLViewport.ts b/tldraw/packages/core/src/lib/TLViewport.ts index 8fe2053a392..5d0b91d92dc 100644 --- a/tldraw/packages/core/src/lib/TLViewport.ts +++ b/tldraw/packages/core/src/lib/TLViewport.ts @@ -51,7 +51,7 @@ export class TLViewport { } panToPointWhenNearBounds = (point: number[]) => { - const threshold = [TLViewport.panThreshold, TLViewport.panThreshold] + const threshold = Vec.div([TLViewport.panThreshold, TLViewport.panThreshold], this.camera.zoom) const deltaMax = Vec.sub([this.currentView.maxX, this.currentView.maxY], Vec.add(point, threshold)) const deltaMin = Vec.sub([this.currentView.minX, this.currentView.minY], Vec.sub(point, threshold)) diff --git a/tldraw/packages/core/src/lib/tools/TLBoxTool/states/CreatingState.tsx b/tldraw/packages/core/src/lib/tools/TLBoxTool/states/CreatingState.tsx index 2bdfbb04eda..3bf671cf652 100644 --- a/tldraw/packages/core/src/lib/tools/TLBoxTool/states/CreatingState.tsx +++ b/tldraw/packages/core/src/lib/tools/TLBoxTool/states/CreatingState.tsx @@ -1,5 +1,6 @@ import type { TLBoxTool } from '../TLBoxTool' import Vec from '@tldraw/vec' +import { GRID_SIZE } from '@tldraw/core' import type { TLBounds } from '@tldraw/intersect' import { type TLEventMap, TLCursor, type TLStateEvents, TLResizeCorner } from '../../../../types' import { uniqueId, BoundsUtils } from '../../../../utils' @@ -68,7 +69,7 @@ export class CreatingState< if (!this.creatingShape) throw Error('Expected a creating shape.') const { initialBounds } = this const { currentPoint, originPoint, shiftKey } = this.app.inputs - const bounds = BoundsUtils.getTransformedBoundingBox( + let bounds = BoundsUtils.getTransformedBoundingBox( initialBounds, TLResizeCorner.BottomRight, Vec.sub(currentPoint, originPoint), @@ -78,6 +79,10 @@ export class CreatingState< !this.creatingShape.canChangeAspectRatio ) + if (this.app.settings.snapToGrid) { + bounds = BoundsUtils.snapBoundsToGrid(bounds, GRID_SIZE) + } + this.creatingShape.update({ point: [bounds.minX, bounds.minY], size: [bounds.width, bounds.height], diff --git a/tldraw/packages/core/src/lib/tools/TLSelectTool/states/ResizingState.ts b/tldraw/packages/core/src/lib/tools/TLSelectTool/states/ResizingState.ts index d056fd45e1a..628c80c5c28 100644 --- a/tldraw/packages/core/src/lib/tools/TLSelectTool/states/ResizingState.ts +++ b/tldraw/packages/core/src/lib/tools/TLSelectTool/states/ResizingState.ts @@ -1,4 +1,5 @@ import type { TLBounds } from '@tldraw/intersect' +import { GRID_SIZE } from '@tldraw/core' import { Vec } from '@tldraw/vec' import { type TLEventMap, @@ -216,6 +217,11 @@ export class ResizingState< // // Position the bounds at the center // relativeBounds = BoundsUtils.centerBounds(relativeBounds, center) // } + + if (this.app.settings.snapToGrid) { + relativeBounds = BoundsUtils.snapBoundsToGrid(relativeBounds, GRID_SIZE) + } + shape.onResize(initialShapeProps, { center, rotation, diff --git a/tldraw/packages/core/src/lib/tools/TLSelectTool/states/TranslatingState.ts b/tldraw/packages/core/src/lib/tools/TLSelectTool/states/TranslatingState.ts index 7d3fa8e34de..8e65399ea5c 100644 --- a/tldraw/packages/core/src/lib/tools/TLSelectTool/states/TranslatingState.ts +++ b/tldraw/packages/core/src/lib/tools/TLSelectTool/states/TranslatingState.ts @@ -1,11 +1,12 @@ import { Vec } from '@tldraw/vec' import { transaction } from 'mobx' import { type TLEventMap, TLCursor, type TLEvents } from '../../../../types' -import { dedupe, uniqueId } from '../../../../utils' +import { uniqueId } from '../../../../utils' import type { TLShape } from '../../../shapes' import type { TLApp } from '../../../TLApp' import { TLToolState } from '../../../TLToolState' import type { TLSelectTool } from '../TLSelectTool' +import { GRID_SIZE } from '../../../../constants' export class TranslatingState< S extends TLShape, @@ -46,9 +47,15 @@ export class TranslatingState< } transaction(() => { - this.app.allSelectedShapesArray.forEach(shape => { - if (!shape.props.isLocked) shape.update({ point: Vec.add(initialPoints[shape.id], delta) }) - }) + this.app.allSelectedShapesArray + .filter(s => !s.props.isLocked) + .forEach(shape => { + let position = Vec.add(initialPoints[shape.id], delta) + if (this.app.settings.snapToGrid) { + position = Vec.snap(position, GRID_SIZE) + } + shape.update({ point: position }) + }) }) }