Skip to content

Commit

Permalink
Adds snapping to example
Browse files Browse the repository at this point in the history
  • Loading branch information
steveruizok committed Oct 29, 2021
1 parent 5d0221c commit 1dff036
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 5 deletions.
1 change: 1 addition & 0 deletions example-advanced/src/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ export default function App(): JSX.Element {
page={appState.data.page} // Required
pageState={appState.data.pageState} // Required
meta={appState.data.meta}
snapLines={appState.data.overlays.snapLines}
onPointShape={onPointShape}
onPointBounds={onPointBounds}
onPointCanvas={onPointCanvas}
Expand Down
7 changes: 6 additions & 1 deletion example-advanced/src/state/constants.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { TLBinding, TLPage, TLPageState } from '@tldraw/core'
import type { TLBinding, TLPage, TLPageState, TLSnapLine } from '@tldraw/core'
import type { Shape } from '../shapes'

export const INITIAL_PAGE: TLPage<Shape, TLBinding> = {
Expand Down Expand Up @@ -41,6 +41,9 @@ export const INITIAL_PAGE_STATE: TLPageState = {
export const INITIAL_DATA = {
page: INITIAL_PAGE,
pageState: INITIAL_PAGE_STATE,
overlays: {
snapLines: [] as TLSnapLine[],
},
meta: {
isDarkMode: false,
},
Expand All @@ -49,3 +52,5 @@ export const INITIAL_DATA = {
export type Data = typeof INITIAL_DATA

export const FIT_TO_SCREEN_PADDING = 100

export const SNAP_DISTANCE = 5
70 changes: 66 additions & 4 deletions example-advanced/src/state/machine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ import {
TLBoundsCorner,
TLBoundsEdge,
TLBoundsHandle,
TLBoundsWithCenter,
TLPageState,
TLPointerInfo,
TLSnapLine,
Utils,
} from '@tldraw/core'
import { BoxShape, getShapeUtils, shapeUtils } from '../shapes'
import { INITIAL_DATA } from './constants'
import { INITIAL_DATA, SNAP_DISTANCE } from './constants'
import { nanoid } from 'nanoid'
import { current } from 'immer'
import Vec from '@tldraw/vec'
Expand All @@ -20,6 +22,13 @@ let snapshot = INITIAL_DATA
let initialPoint = [0, 0]
let justShiftSelectedId: string | undefined
let isCloning = false
let snapInfo:
| {
initialBounds: TLBoundsWithCenter
all: TLBoundsWithCenter[]
others: TLBoundsWithCenter[]
}
| undefined
let initialBoundsHandle: TLBoundsHandle | undefined

export const setBounds = (newBounds: TLBounds) => (rendererBounds = newBounds)
Expand All @@ -42,7 +51,7 @@ export const state = createState({
initial: 'idle',
states: {
idle: {
onEnter: 'clearJustShiftSelectedId',
onEnter: ['clearJustShiftSelectedId', 'clearSnapInfo', 'clearSnapLines'],
on: {
CANCELLED: 'clearSelection',
DELETED: 'deleteSelection',
Expand Down Expand Up @@ -122,7 +131,7 @@ export const state = createState({
},
},
translatingSelection: {
onEnter: ['resetIsCloning'],
onEnter: ['resetIsCloning', 'setSnapInfo'],
on: {
TOGGLED_MODIFIER: 'translateSelection',
MOVED_POINTER: 'translateSelection',
Expand Down Expand Up @@ -220,6 +229,38 @@ export const state = createState({
resetIsCloning() {
isCloning = false
},
setSnapInfo(data) {
const all: TLBoundsWithCenter[] = []
const others: TLBoundsWithCenter[] = []

Object.values(data.page.shapes).forEach((shape) => {
const bounds = Utils.getBoundsWithCenter(getShapeUtils(shape).getRotatedBounds(shape))
all.push(bounds)
if (!data.pageState.selectedIds.includes(shape.id)) {
others.push(bounds)
}
})

const initialBounds = Utils.getBoundsWithCenter(
Utils.getCommonBounds(
data.pageState.selectedIds
.map((id) => data.page.shapes[id])
.map((shape) => getShapeUtils(shape).getBounds(shape))
)
)

snapInfo = {
initialBounds,
all,
others,
}
},
clearSnapInfo(data) {
snapInfo = undefined
},
clearSnapLines(data) {
data.overlays.snapLines = []
},
/* --------------------- Camera --------------------- */
panCamera(data, payload: TLPointerInfo) {
const { point, zoom } = data.pageState.camera
Expand Down Expand Up @@ -359,7 +400,7 @@ export const state = createState({
},
/* ------------------- Translating ------------------ */
translateSelection(data, payload: TLPointerInfo) {
const delta = Vec.sub(getPagePoint(payload.point, data.pageState), initialPoint)
let delta = Vec.sub(getPagePoint(payload.point, data.pageState), initialPoint)

if (payload.shiftKey) {
if (Math.abs(delta[0]) > Math.abs(delta[1])) {
Expand Down Expand Up @@ -401,6 +442,27 @@ export const state = createState({
data.pageState.selectedIds = [...snapshot.pageState.selectedIds]
}

let snapLines: TLSnapLine[] = []

if (snapInfo) {
const snapResult = Utils.getSnapPoints(
Utils.getBoundsWithCenter(Utils.translateBounds(snapInfo.initialBounds, delta)),
(isCloning ? snapInfo.all : snapInfo.others).filter(
(bounds) =>
Utils.boundsContain(rendererBounds, bounds) ||
Utils.boundsCollide(rendererBounds, bounds)
),
SNAP_DISTANCE / data.pageState.camera.zoom
)

if (snapResult) {
snapLines = snapResult.snapLines
delta = Vec.sub(delta, snapResult.offset)
}
}

data.overlays.snapLines = snapLines

data.pageState.selectedIds.forEach((id) => {
const initialShape = snapshot.page.shapes[id]
const shape = data.page.shapes[id]
Expand Down

0 comments on commit 1dff036

Please sign in to comment.