Continues on drawing / rotation
This commit is contained in:
parent
79c254a938
commit
c95c54dae6
11 changed files with 311 additions and 324 deletions
|
@ -7,7 +7,6 @@ import CenterHandle from './center-handle'
|
|||
import CornerHandle from './corner-handle'
|
||||
import EdgeHandle from './edge-handle'
|
||||
import RotateHandle from './rotate-handle'
|
||||
import Selected from '../selected'
|
||||
|
||||
export default function Bounds() {
|
||||
const isBrushing = useSelector((s) => s.isIn('brushSelecting'))
|
||||
|
@ -32,7 +31,6 @@ export default function Bounds() {
|
|||
${(bounds.minY + bounds.maxY) / 2})
|
||||
translate(${bounds.minX},${bounds.minY})`}
|
||||
>
|
||||
<Selected bounds={bounds} />
|
||||
<CenterHandle bounds={bounds} />
|
||||
<EdgeHandle size={size} bounds={bounds} edge={Edge.Top} />
|
||||
<EdgeHandle size={size} bounds={bounds} edge={Edge.Right} />
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import styled from 'styles'
|
||||
import state from 'state'
|
||||
import state, { useSelector } from 'state'
|
||||
import inputs from 'state/inputs'
|
||||
import React, { useCallback, useRef } from 'react'
|
||||
import useZoomEvents from 'hooks/useZoomEvents'
|
||||
|
@ -9,6 +9,7 @@ import Page from './page'
|
|||
import Brush from './brush'
|
||||
import Bounds from './bounds/bounding-box'
|
||||
import BoundsBg from './bounds/bounds-bg'
|
||||
import Selected from './selected'
|
||||
|
||||
export default function Canvas() {
|
||||
const rCanvas = useRef<SVGSVGElement>(null)
|
||||
|
@ -17,6 +18,8 @@ export default function Canvas() {
|
|||
|
||||
useCamera(rGroup)
|
||||
|
||||
const isReady = useSelector((s) => s.isIn('ready'))
|
||||
|
||||
const handlePointerDown = useCallback((e: React.PointerEvent) => {
|
||||
rCanvas.current.setPointerCapture(e.pointerId)
|
||||
state.send('POINTED_CANVAS', inputs.pointerDown(e, 'canvas'))
|
||||
|
@ -40,12 +43,15 @@ export default function Canvas() {
|
|||
onPointerUp={handlePointerUp}
|
||||
>
|
||||
<Defs />
|
||||
<MainGroup ref={rGroup}>
|
||||
{isReady && (
|
||||
<g ref={rGroup}>
|
||||
<BoundsBg />
|
||||
<Page />
|
||||
<Bounds />
|
||||
<Selected />
|
||||
<Brush />
|
||||
</MainGroup>
|
||||
</g>
|
||||
)}
|
||||
</MainSVG>
|
||||
)
|
||||
}
|
||||
|
@ -63,5 +69,3 @@ const MainSVG = styled('svg', {
|
|||
userSelect: 'none',
|
||||
},
|
||||
})
|
||||
|
||||
const MainGroup = styled('g', {})
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { getShapeUtils } from "lib/shape-utils"
|
||||
import { useSelector } from "state"
|
||||
import { deepCompareArrays, getPage } from "utils/utils"
|
||||
import { getShapeUtils } from 'lib/shape-utils'
|
||||
import { useSelector } from 'state'
|
||||
import { deepCompareArrays, getPage } from 'utils/utils'
|
||||
|
||||
export default function Defs() {
|
||||
const currentPageShapeIds = useSelector(({ data }) => {
|
||||
|
@ -20,6 +20,6 @@ export default function Defs() {
|
|||
|
||||
export function Def({ id }: { id: string }) {
|
||||
const shape = useSelector(({ data }) => getPage(data).shapes[id])
|
||||
|
||||
if (!shape) return null
|
||||
return getShapeUtils(shape).render(shape)
|
||||
}
|
||||
|
|
|
@ -1,48 +1,48 @@
|
|||
import styled from 'styles'
|
||||
import { useSelector } from 'state'
|
||||
import {
|
||||
deepCompareArrays,
|
||||
getBoundsCenter,
|
||||
getPage,
|
||||
getSelectedShapes,
|
||||
} from 'utils/utils'
|
||||
import * as vec from 'utils/vec'
|
||||
import { deepCompareArrays, getPage } from 'utils/utils'
|
||||
import { getShapeUtils } from 'lib/shape-utils'
|
||||
import { Bounds } from 'types'
|
||||
import useShapeEvents from 'hooks/useShapeEvents'
|
||||
import { useRef } from 'react'
|
||||
|
||||
export default function Selected({ bounds }: { bounds: Bounds }) {
|
||||
export default function Selected() {
|
||||
const currentPageShapeIds = useSelector(({ data }) => {
|
||||
return Array.from(data.selectedIds.values())
|
||||
}, deepCompareArrays)
|
||||
|
||||
const isSelecting = useSelector((s) => s.isIn('selecting'))
|
||||
|
||||
if (!isSelecting) return null
|
||||
|
||||
return (
|
||||
<g>
|
||||
{currentPageShapeIds.map((id) => (
|
||||
<ShapeOutline key={id} id={id} bounds={bounds} />
|
||||
<ShapeOutline key={id} id={id} />
|
||||
))}
|
||||
</g>
|
||||
)
|
||||
}
|
||||
|
||||
export function ShapeOutline({ id, bounds }: { id: string; bounds: Bounds }) {
|
||||
export function ShapeOutline({ id }: { id: string }) {
|
||||
const rIndicator = useRef<SVGUseElement>(null)
|
||||
|
||||
const shape = useSelector(({ data }) => getPage(data).shapes[id])
|
||||
|
||||
const shapeBounds = getShapeUtils(shape).getBounds(shape)
|
||||
|
||||
const events = useShapeEvents(id, rIndicator)
|
||||
|
||||
if (!shape) return null
|
||||
|
||||
const transform = `
|
||||
rotate(${shape.rotation * (180 / Math.PI)},
|
||||
${getShapeUtils(shape).getCenter(shape)})
|
||||
translate(${shape.point})`
|
||||
|
||||
return (
|
||||
<Indicator
|
||||
ref={rIndicator}
|
||||
as="use"
|
||||
href={'#' + id}
|
||||
transform={`rotate(${shape.rotation * (180 / Math.PI)},${getBoundsCenter(
|
||||
shapeBounds
|
||||
)}) translate(${vec.sub(shape.point, [bounds.minX, bounds.minY])})`}
|
||||
transform={transform}
|
||||
{...events}
|
||||
/>
|
||||
)
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import React, { useCallback, useRef, memo } from 'react'
|
||||
import state, { useSelector } from 'state'
|
||||
import inputs from 'state/inputs'
|
||||
import React, { useRef, memo } from 'react'
|
||||
import { useSelector } from 'state'
|
||||
import styled from 'styles'
|
||||
import { getShapeUtils } from 'lib/shape-utils'
|
||||
import { getPage } from 'utils/utils'
|
||||
import { ShapeStyles } from 'types'
|
||||
import useShapeEvents from 'hooks/useShapeEvents'
|
||||
|
||||
function Shape({ id, isSelecting }: { id: string; isSelecting: boolean }) {
|
||||
const isHovered = useSelector((state) => state.data.hoveredId === id)
|
||||
|
@ -15,42 +15,7 @@ function Shape({ id, isSelecting }: { id: string; isSelecting: boolean }) {
|
|||
|
||||
const rGroup = useRef<SVGGElement>(null)
|
||||
|
||||
const handlePointerDown = useCallback(
|
||||
(e: React.PointerEvent) => {
|
||||
e.stopPropagation()
|
||||
rGroup.current.setPointerCapture(e.pointerId)
|
||||
state.send('POINTED_SHAPE', inputs.pointerDown(e, id))
|
||||
},
|
||||
[id]
|
||||
)
|
||||
|
||||
const handlePointerUp = useCallback(
|
||||
(e: React.PointerEvent) => {
|
||||
e.stopPropagation()
|
||||
rGroup.current.releasePointerCapture(e.pointerId)
|
||||
state.send('STOPPED_POINTING', inputs.pointerUp(e))
|
||||
},
|
||||
[id]
|
||||
)
|
||||
|
||||
const handlePointerEnter = useCallback(
|
||||
(e: React.PointerEvent) => {
|
||||
state.send('HOVERED_SHAPE', inputs.pointerEnter(e, id))
|
||||
},
|
||||
[id, shape]
|
||||
)
|
||||
|
||||
const handlePointerMove = useCallback(
|
||||
(e: React.PointerEvent) => {
|
||||
state.send('MOVED_OVER_SHAPE', inputs.pointerEnter(e, id))
|
||||
},
|
||||
[id, shape]
|
||||
)
|
||||
|
||||
const handlePointerLeave = useCallback(
|
||||
() => state.send('UNHOVERED_SHAPE', { target: id }),
|
||||
[id]
|
||||
)
|
||||
const events = useShapeEvents(id, rGroup)
|
||||
|
||||
// This is a problem with deleted shapes. The hooks in this component
|
||||
// may sometimes run before the hook in the Page component, which means
|
||||
|
@ -58,19 +23,18 @@ function Shape({ id, isSelecting }: { id: string; isSelecting: boolean }) {
|
|||
// detects the change and pulls this component.
|
||||
if (!shape) return null
|
||||
|
||||
const transform = `
|
||||
rotate(${shape.rotation * (180 / Math.PI)},
|
||||
${getShapeUtils(shape).getCenter(shape)})
|
||||
translate(${shape.point})`
|
||||
|
||||
return (
|
||||
<StyledGroup
|
||||
ref={rGroup}
|
||||
isHovered={isHovered}
|
||||
isSelected={isSelected}
|
||||
transform={`rotate(${shape.rotation * (180 / Math.PI)},${getShapeUtils(
|
||||
shape
|
||||
).getCenter(shape)}) translate(${shape.point})`}
|
||||
onPointerDown={handlePointerDown}
|
||||
onPointerUp={handlePointerUp}
|
||||
onPointerEnter={handlePointerEnter}
|
||||
onPointerLeave={handlePointerLeave}
|
||||
onPointerMove={handlePointerMove}
|
||||
transform={transform}
|
||||
{...events}
|
||||
>
|
||||
{isSelecting && <HoverIndicator as="use" href={'#' + id} />}
|
||||
<StyledShape id={id} style={shape.style} />
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import React, { useEffect, useRef } from "react"
|
||||
import state from "state"
|
||||
import inputs from "state/inputs"
|
||||
import * as vec from "utils/vec"
|
||||
import { usePinch } from "react-use-gesture"
|
||||
import React, { useEffect, useRef } from 'react'
|
||||
import state from 'state'
|
||||
import inputs from 'state/inputs'
|
||||
import * as vec from 'utils/vec'
|
||||
import { usePinch } from 'react-use-gesture'
|
||||
|
||||
/**
|
||||
* Capture zoom gestures (pinches, wheels and pans) and send to the state.
|
||||
|
@ -21,16 +21,17 @@ export default function useZoomEvents(
|
|||
|
||||
function handleWheel(e: WheelEvent) {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
|
||||
if (e.ctrlKey) {
|
||||
state.send("ZOOMED_CAMERA", {
|
||||
state.send('ZOOMED_CAMERA', {
|
||||
delta: e.deltaY,
|
||||
...inputs.wheel(e),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
state.send("PANNED_CAMERA", {
|
||||
state.send('PANNED_CAMERA', {
|
||||
delta: [e.deltaX, e.deltaY],
|
||||
...inputs.wheel(e),
|
||||
})
|
||||
|
@ -38,6 +39,7 @@ export default function useZoomEvents(
|
|||
|
||||
function handleTouchMove(e: TouchEvent) {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
|
||||
if (e.touches.length === 2) {
|
||||
const { clientX: x0, clientY: y0 } = e.touches[0]
|
||||
|
@ -46,7 +48,7 @@ export default function useZoomEvents(
|
|||
const dist = vec.dist([x0, y0], [x1, y1])
|
||||
const point = vec.med([x0, y0], [x1, y1])
|
||||
|
||||
state.send("WHEELED", {
|
||||
state.send('WHEELED', {
|
||||
delta: dist - rTouchDist.current,
|
||||
point,
|
||||
})
|
||||
|
@ -55,38 +57,37 @@ export default function useZoomEvents(
|
|||
}
|
||||
}
|
||||
|
||||
element.addEventListener("wheel", handleWheel)
|
||||
element.addEventListener("touchstart", handleTouchMove)
|
||||
element.addEventListener("touchmove", handleTouchMove)
|
||||
element.addEventListener('wheel', handleWheel, { passive: false })
|
||||
element.addEventListener('touchstart', handleTouchMove, { passive: false })
|
||||
element.addEventListener('touchmove', handleTouchMove, { passive: false })
|
||||
|
||||
return () => {
|
||||
element.removeEventListener("wheel", handleWheel)
|
||||
element.removeEventListener("touchstart", handleTouchMove)
|
||||
element.removeEventListener("touchmove", handleTouchMove)
|
||||
element.removeEventListener('wheel', handleWheel)
|
||||
element.removeEventListener('touchstart', handleTouchMove)
|
||||
element.removeEventListener('touchmove', handleTouchMove)
|
||||
}
|
||||
}, [ref])
|
||||
|
||||
const rPinchDa = useRef<number[] | undefined>(undefined)
|
||||
const rPinchAngle = useRef<number>(undefined)
|
||||
const rPinchPoint = useRef<number[] | undefined>(undefined)
|
||||
|
||||
const bind = usePinch(({ pinching, da, origin }) => {
|
||||
if (!pinching) {
|
||||
state.send("STOPPED_PINCHING")
|
||||
state.send('STOPPED_PINCHING')
|
||||
rPinchDa.current = undefined
|
||||
rPinchPoint.current = undefined
|
||||
return
|
||||
}
|
||||
|
||||
if (rPinchPoint.current === undefined) {
|
||||
state.send("STARTED_PINCHING")
|
||||
state.send('STARTED_PINCHING')
|
||||
rPinchDa.current = da
|
||||
rPinchPoint.current = origin
|
||||
}
|
||||
|
||||
const [distanceDelta, angleDelta] = vec.sub(rPinchDa.current, da)
|
||||
|
||||
state.send("PINCHED", {
|
||||
state.send('PINCHED', {
|
||||
delta: vec.sub(rPinchPoint.current, origin),
|
||||
point: origin,
|
||||
distanceDelta,
|
||||
|
|
|
@ -7,11 +7,10 @@ import { boundsContainPolygon } from 'utils/bounds'
|
|||
import getStroke from 'perfect-freehand'
|
||||
import {
|
||||
getBoundsFromPoints,
|
||||
getRotatedCorners,
|
||||
getSvgPathFromStroke,
|
||||
translateBounds,
|
||||
} from 'utils/utils'
|
||||
import { DotCircle } from 'components/canvas/misc'
|
||||
import { shades } from 'lib/colors'
|
||||
|
||||
const pathCache = new WeakMap<number[][], string>([])
|
||||
|
||||
|
@ -43,13 +42,18 @@ const draw = registerShapeUtils<DrawShape>({
|
|||
render(shape) {
|
||||
const { id, point, points } = shape
|
||||
|
||||
if (points.length < 2) {
|
||||
return <DotCircle id={id} cx={point[0]} cy={point[1]} r={3} />
|
||||
}
|
||||
|
||||
if (!pathCache.has(points)) {
|
||||
if (points.length < 2) {
|
||||
const left = vec.add(point, [6, 0])
|
||||
let d: number[][] = []
|
||||
for (let i = 0; i < 10; i++) {
|
||||
d.push(vec.rotWith(left, point, i * ((Math.PI * 2) / 8)))
|
||||
}
|
||||
pathCache.set(points, getSvgPathFromStroke(d))
|
||||
} else {
|
||||
pathCache.set(points, getSvgPathFromStroke(getStroke(points)))
|
||||
}
|
||||
}
|
||||
|
||||
return <path id={id} d={pathCache.get(points)} />
|
||||
},
|
||||
|
@ -69,11 +73,13 @@ const draw = registerShapeUtils<DrawShape>({
|
|||
},
|
||||
|
||||
getRotatedBounds(shape) {
|
||||
return this.getBounds(shape)
|
||||
return getBoundsFromPoints(
|
||||
getRotatedCorners(this.getBounds(shape), shape.rotation)
|
||||
)
|
||||
},
|
||||
|
||||
getCenter(shape) {
|
||||
const bounds = this.getBounds(shape)
|
||||
const bounds = this.getRotatedBounds(shape)
|
||||
return [bounds.minX + bounds.width / 2, bounds.minY + bounds.height / 2]
|
||||
},
|
||||
|
||||
|
@ -114,6 +120,10 @@ const draw = registerShapeUtils<DrawShape>({
|
|||
|
||||
rotateTo(shape, rotation) {
|
||||
shape.rotation = rotation
|
||||
// console.log(shape.points.map(([x, y]) => [x, y]))
|
||||
// const bounds = this.getBounds(shape)
|
||||
// const center = [bounds.width / 2, bounds.height / 2]
|
||||
// shape.points = shape.points.map((pt) => vec.rotWith(pt, center, rotation))
|
||||
return this
|
||||
},
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
"framer-motion": "^4.1.16",
|
||||
"ismobilejs": "^1.1.1",
|
||||
"next": "10.2.0",
|
||||
"perfect-freehand": "^0.4.71",
|
||||
"perfect-freehand": "^0.4.8",
|
||||
"prettier": "^2.3.0",
|
||||
"react": "17.0.2",
|
||||
"react-dom": "17.0.2",
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { Data } from "types"
|
||||
import * as vec from "utils/vec"
|
||||
import BaseSession from "./base-session"
|
||||
import commands from "state/commands"
|
||||
import { current } from "immer"
|
||||
import { Data } from 'types'
|
||||
import * as vec from 'utils/vec'
|
||||
import BaseSession from './base-session'
|
||||
import commands from 'state/commands'
|
||||
import { current } from 'immer'
|
||||
import {
|
||||
clampToRotationToSegments,
|
||||
getBoundsCenter,
|
||||
|
@ -10,8 +10,8 @@ import {
|
|||
getPage,
|
||||
getSelectedShapes,
|
||||
getShapeBounds,
|
||||
} from "utils/utils"
|
||||
import { getShapeUtils } from "lib/shape-utils"
|
||||
} from 'utils/utils'
|
||||
import { getShapeUtils } from 'lib/shape-utils'
|
||||
|
||||
const PI2 = Math.PI * 2
|
||||
|
||||
|
|
422
state/state.ts
422
state/state.ts
|
@ -1,13 +1,13 @@
|
|||
import { createSelectorHook, createState } from "@state-designer/react"
|
||||
import * as vec from "utils/vec"
|
||||
import inputs from "./inputs"
|
||||
import { defaultDocument } from "./data"
|
||||
import { shades } from "lib/colors"
|
||||
import { createShape, getShapeUtils } from "lib/shape-utils"
|
||||
import history from "state/history"
|
||||
import * as Sessions from "./sessions"
|
||||
import commands from "./commands"
|
||||
import { updateFromCode } from "lib/code/generate"
|
||||
import { createSelectorHook, createState } from '@state-designer/react'
|
||||
import * as vec from 'utils/vec'
|
||||
import inputs from './inputs'
|
||||
import { defaultDocument } from './data'
|
||||
import { shades } from 'lib/colors'
|
||||
import { createShape, getShapeUtils } from 'lib/shape-utils'
|
||||
import history from 'state/history'
|
||||
import * as Sessions from './sessions'
|
||||
import commands from './commands'
|
||||
import { updateFromCode } from 'lib/code/generate'
|
||||
import {
|
||||
clamp,
|
||||
getChildren,
|
||||
|
@ -18,7 +18,7 @@ import {
|
|||
getShape,
|
||||
screenToWorld,
|
||||
setZoomCSS,
|
||||
} from "utils/utils"
|
||||
} from 'utils/utils'
|
||||
import {
|
||||
Data,
|
||||
PointerInfo,
|
||||
|
@ -32,7 +32,7 @@ import {
|
|||
DistributeType,
|
||||
AlignType,
|
||||
StretchType,
|
||||
} from "types"
|
||||
} from 'types'
|
||||
|
||||
const initialData: Data = {
|
||||
isReadOnly: false,
|
||||
|
@ -55,8 +55,8 @@ const initialData: Data = {
|
|||
pointedId: null,
|
||||
hoveredId: null,
|
||||
selectedIds: new Set([]),
|
||||
currentPageId: "page0",
|
||||
currentCodeFileId: "file0",
|
||||
currentPageId: 'page0',
|
||||
currentCodeFileId: 'file0',
|
||||
codeControls: {},
|
||||
document: defaultDocument,
|
||||
}
|
||||
|
@ -65,109 +65,116 @@ const state = createState({
|
|||
data: initialData,
|
||||
on: {
|
||||
ZOOMED_CAMERA: {
|
||||
do: "zoomCamera",
|
||||
do: 'zoomCamera',
|
||||
},
|
||||
PANNED_CAMERA: {
|
||||
do: "panCamera",
|
||||
do: 'panCamera',
|
||||
},
|
||||
SELECTED_SELECT_TOOL: { to: "selecting" },
|
||||
SELECTED_DRAW_TOOL: { unless: "isReadOnly", to: "draw" },
|
||||
SELECTED_DOT_TOOL: { unless: "isReadOnly", to: "dot" },
|
||||
SELECTED_CIRCLE_TOOL: { unless: "isReadOnly", to: "circle" },
|
||||
SELECTED_ELLIPSE_TOOL: { unless: "isReadOnly", to: "ellipse" },
|
||||
SELECTED_RAY_TOOL: { unless: "isReadOnly", to: "ray" },
|
||||
SELECTED_LINE_TOOL: { unless: "isReadOnly", to: "line" },
|
||||
SELECTED_POLYLINE_TOOL: { unless: "isReadOnly", to: "polyline" },
|
||||
SELECTED_RECTANGLE_TOOL: { unless: "isReadOnly", to: "rectangle" },
|
||||
TOGGLED_CODE_PANEL_OPEN: "toggleCodePanel",
|
||||
TOGGLED_STYLE_PANEL_OPEN: "toggleStylePanel",
|
||||
CHANGED_STYLE: ["updateStyles", "applyStylesToSelection"],
|
||||
RESET_CAMERA: "resetCamera",
|
||||
ZOOMED_TO_FIT: "zoomCameraToFit",
|
||||
SELECTED_SELECT_TOOL: { to: 'selecting' },
|
||||
SELECTED_DRAW_TOOL: { unless: 'isReadOnly', to: 'draw' },
|
||||
SELECTED_DOT_TOOL: { unless: 'isReadOnly', to: 'dot' },
|
||||
SELECTED_CIRCLE_TOOL: { unless: 'isReadOnly', to: 'circle' },
|
||||
SELECTED_ELLIPSE_TOOL: { unless: 'isReadOnly', to: 'ellipse' },
|
||||
SELECTED_RAY_TOOL: { unless: 'isReadOnly', to: 'ray' },
|
||||
SELECTED_LINE_TOOL: { unless: 'isReadOnly', to: 'line' },
|
||||
SELECTED_POLYLINE_TOOL: { unless: 'isReadOnly', to: 'polyline' },
|
||||
SELECTED_RECTANGLE_TOOL: { unless: 'isReadOnly', to: 'rectangle' },
|
||||
TOGGLED_CODE_PANEL_OPEN: 'toggleCodePanel',
|
||||
TOGGLED_STYLE_PANEL_OPEN: 'toggleStylePanel',
|
||||
CHANGED_STYLE: ['updateStyles', 'applyStylesToSelection'],
|
||||
RESET_CAMERA: 'resetCamera',
|
||||
ZOOMED_TO_FIT: 'zoomCameraToFit',
|
||||
ZOOMED_TO_SELECTION: {
|
||||
if: "hasSelection",
|
||||
do: "zoomCameraToSelection",
|
||||
if: 'hasSelection',
|
||||
do: 'zoomCameraToSelection',
|
||||
},
|
||||
ZOOMED_TO_ACTUAL: {
|
||||
if: "hasSelection",
|
||||
do: "zoomCameraToSelectionActual",
|
||||
else: "zoomCameraToActual",
|
||||
if: 'hasSelection',
|
||||
do: 'zoomCameraToSelectionActual',
|
||||
else: 'zoomCameraToActual',
|
||||
},
|
||||
SELECTED_ALL: { to: "selecting", do: "selectAll" },
|
||||
SELECTED_ALL: { to: 'selecting', do: 'selectAll' },
|
||||
},
|
||||
initial: "loading",
|
||||
initial: 'loading',
|
||||
states: {
|
||||
loading: {
|
||||
on: {
|
||||
MOUNTED: {
|
||||
do: ["restoreSavedData", "zoomCameraToFit"],
|
||||
to: "ready",
|
||||
MOUNTED: [
|
||||
'restoreSavedData',
|
||||
{
|
||||
if: 'hasSelection',
|
||||
do: 'zoomCameraToSelectionActual',
|
||||
else: ['zoomCameraToFit', 'zoomCameraToActual'],
|
||||
},
|
||||
{
|
||||
to: 'ready',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
ready: {
|
||||
on: {
|
||||
UNMOUNTED: [
|
||||
{ unless: "isReadOnly", do: "forceSave" },
|
||||
{ to: "loading" },
|
||||
{ unless: 'isReadOnly', do: 'forceSave' },
|
||||
{ to: 'loading' },
|
||||
],
|
||||
},
|
||||
initial: "selecting",
|
||||
initial: 'selecting',
|
||||
states: {
|
||||
selecting: {
|
||||
on: {
|
||||
SAVED: "forceSave",
|
||||
UNDO: { do: "undo" },
|
||||
REDO: { do: "redo" },
|
||||
CANCELLED: { do: "clearSelectedIds" },
|
||||
DELETED: { do: "deleteSelectedIds" },
|
||||
SAVED_CODE: "saveCode",
|
||||
GENERATED_FROM_CODE: ["setCodeControls", "setGeneratedShapes"],
|
||||
INCREASED_CODE_FONT_SIZE: "increaseCodeFontSize",
|
||||
DECREASED_CODE_FONT_SIZE: "decreaseCodeFontSize",
|
||||
CHANGED_CODE_CONTROL: "updateControls",
|
||||
ALIGNED: "alignSelection",
|
||||
STRETCHED: "stretchSelection",
|
||||
DISTRIBUTED: "distributeSelection",
|
||||
MOVED: "moveSelection",
|
||||
STARTED_PINCHING: { to: "pinching" },
|
||||
SAVED: 'forceSave',
|
||||
UNDO: { do: 'undo' },
|
||||
REDO: { do: 'redo' },
|
||||
CANCELLED: { do: 'clearSelectedIds' },
|
||||
DELETED: { do: 'deleteSelectedIds' },
|
||||
SAVED_CODE: 'saveCode',
|
||||
GENERATED_FROM_CODE: ['setCodeControls', 'setGeneratedShapes'],
|
||||
INCREASED_CODE_FONT_SIZE: 'increaseCodeFontSize',
|
||||
DECREASED_CODE_FONT_SIZE: 'decreaseCodeFontSize',
|
||||
CHANGED_CODE_CONTROL: 'updateControls',
|
||||
ALIGNED: 'alignSelection',
|
||||
STRETCHED: 'stretchSelection',
|
||||
DISTRIBUTED: 'distributeSelection',
|
||||
MOVED: 'moveSelection',
|
||||
STARTED_PINCHING: { to: 'pinching' },
|
||||
},
|
||||
initial: "notPointing",
|
||||
initial: 'notPointing',
|
||||
states: {
|
||||
notPointing: {
|
||||
on: {
|
||||
POINTED_CANVAS: { to: "brushSelecting" },
|
||||
POINTED_BOUNDS: { to: "pointingBounds" },
|
||||
POINTED_CANVAS: { to: 'brushSelecting' },
|
||||
POINTED_BOUNDS: { to: 'pointingBounds' },
|
||||
POINTED_BOUNDS_HANDLE: {
|
||||
if: "isPointingRotationHandle",
|
||||
to: "rotatingSelection",
|
||||
else: { to: "transformingSelection" },
|
||||
if: 'isPointingRotationHandle',
|
||||
to: 'rotatingSelection',
|
||||
else: { to: 'transformingSelection' },
|
||||
},
|
||||
MOVED_OVER_SHAPE: {
|
||||
if: "pointHitsShape",
|
||||
if: 'pointHitsShape',
|
||||
then: {
|
||||
unless: "shapeIsHovered",
|
||||
do: "setHoveredId",
|
||||
unless: 'shapeIsHovered',
|
||||
do: 'setHoveredId',
|
||||
},
|
||||
else: { if: "shapeIsHovered", do: "clearHoveredId" },
|
||||
else: { if: 'shapeIsHovered', do: 'clearHoveredId' },
|
||||
},
|
||||
UNHOVERED_SHAPE: "clearHoveredId",
|
||||
UNHOVERED_SHAPE: 'clearHoveredId',
|
||||
POINTED_SHAPE: [
|
||||
{
|
||||
if: "isPressingMetaKey",
|
||||
to: "brushSelecting",
|
||||
if: 'isPressingMetaKey',
|
||||
to: 'brushSelecting',
|
||||
},
|
||||
"setPointedId",
|
||||
'setPointedId',
|
||||
{
|
||||
unless: "isPointedShapeSelected",
|
||||
unless: 'isPointedShapeSelected',
|
||||
then: {
|
||||
if: "isPressingShiftKey",
|
||||
do: ["pushPointedIdToSelectedIds", "clearPointedId"],
|
||||
else: ["clearSelectedIds", "pushPointedIdToSelectedIds"],
|
||||
if: 'isPressingShiftKey',
|
||||
do: ['pushPointedIdToSelectedIds', 'clearPointedId'],
|
||||
else: ['clearSelectedIds', 'pushPointedIdToSelectedIds'],
|
||||
},
|
||||
},
|
||||
{
|
||||
to: "pointingBounds",
|
||||
to: 'pointingBounds',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
@ -176,151 +183,153 @@ const state = createState({
|
|||
on: {
|
||||
STOPPED_POINTING: [
|
||||
{
|
||||
if: "isPressingShiftKey",
|
||||
if: 'isPressingShiftKey',
|
||||
then: {
|
||||
if: "isPointedShapeSelected",
|
||||
do: "pullPointedIdFromSelectedIds",
|
||||
if: 'isPointedShapeSelected',
|
||||
do: 'pullPointedIdFromSelectedIds',
|
||||
},
|
||||
else: {
|
||||
unless: "isPointingBounds",
|
||||
do: ["clearSelectedIds", "pushPointedIdToSelectedIds"],
|
||||
unless: 'isPointingBounds',
|
||||
do: ['clearSelectedIds', 'pushPointedIdToSelectedIds'],
|
||||
},
|
||||
},
|
||||
{ to: "notPointing" },
|
||||
{ to: 'notPointing' },
|
||||
],
|
||||
MOVED_POINTER: {
|
||||
unless: "isReadOnly",
|
||||
if: "distanceImpliesDrag",
|
||||
to: "draggingSelection",
|
||||
unless: 'isReadOnly',
|
||||
if: 'distanceImpliesDrag',
|
||||
to: 'draggingSelection',
|
||||
},
|
||||
},
|
||||
},
|
||||
rotatingSelection: {
|
||||
onEnter: "startRotateSession",
|
||||
onExit: "clearBoundsRotation",
|
||||
onEnter: 'startRotateSession',
|
||||
onExit: 'clearBoundsRotation',
|
||||
on: {
|
||||
MOVED_POINTER: "updateRotateSession",
|
||||
PANNED_CAMERA: "updateRotateSession",
|
||||
PRESSED_SHIFT_KEY: "keyUpdateRotateSession",
|
||||
RELEASED_SHIFT_KEY: "keyUpdateRotateSession",
|
||||
STOPPED_POINTING: { do: "completeSession", to: "selecting" },
|
||||
CANCELLED: { do: "cancelSession", to: "selecting" },
|
||||
MOVED_POINTER: 'updateRotateSession',
|
||||
PANNED_CAMERA: 'updateRotateSession',
|
||||
PRESSED_SHIFT_KEY: 'keyUpdateRotateSession',
|
||||
RELEASED_SHIFT_KEY: 'keyUpdateRotateSession',
|
||||
STOPPED_POINTING: { do: 'completeSession', to: 'selecting' },
|
||||
CANCELLED: { do: 'cancelSession', to: 'selecting' },
|
||||
},
|
||||
},
|
||||
transformingSelection: {
|
||||
onEnter: "startTransformSession",
|
||||
onEnter: 'startTransformSession',
|
||||
on: {
|
||||
MOVED_POINTER: "updateTransformSession",
|
||||
PANNED_CAMERA: "updateTransformSession",
|
||||
PRESSED_SHIFT_KEY: "keyUpdateTransformSession",
|
||||
RELEASED_SHIFT_KEY: "keyUpdateTransformSession",
|
||||
STOPPED_POINTING: { do: "completeSession", to: "selecting" },
|
||||
CANCELLED: { do: "cancelSession", to: "selecting" },
|
||||
MOVED_POINTER: 'updateTransformSession',
|
||||
PANNED_CAMERA: 'updateTransformSession',
|
||||
PRESSED_SHIFT_KEY: 'keyUpdateTransformSession',
|
||||
RELEASED_SHIFT_KEY: 'keyUpdateTransformSession',
|
||||
STOPPED_POINTING: { do: 'completeSession', to: 'selecting' },
|
||||
CANCELLED: { do: 'cancelSession', to: 'selecting' },
|
||||
},
|
||||
},
|
||||
draggingSelection: {
|
||||
onEnter: "startTranslateSession",
|
||||
onEnter: 'startTranslateSession',
|
||||
on: {
|
||||
MOVED_POINTER: "updateTranslateSession",
|
||||
PANNED_CAMERA: "updateTranslateSession",
|
||||
PRESSED_SHIFT_KEY: "keyUpdateTranslateSession",
|
||||
RELEASED_SHIFT_KEY: "keyUpdateTranslateSession",
|
||||
PRESSED_ALT_KEY: "keyUpdateTranslateSession",
|
||||
RELEASED_ALT_KEY: "keyUpdateTranslateSession",
|
||||
STOPPED_POINTING: { do: "completeSession", to: "selecting" },
|
||||
CANCELLED: { do: "cancelSession", to: "selecting" },
|
||||
MOVED_POINTER: 'updateTranslateSession',
|
||||
PANNED_CAMERA: 'updateTranslateSession',
|
||||
PRESSED_SHIFT_KEY: 'keyUpdateTranslateSession',
|
||||
RELEASED_SHIFT_KEY: 'keyUpdateTranslateSession',
|
||||
PRESSED_ALT_KEY: 'keyUpdateTranslateSession',
|
||||
RELEASED_ALT_KEY: 'keyUpdateTranslateSession',
|
||||
STOPPED_POINTING: { do: 'completeSession', to: 'selecting' },
|
||||
CANCELLED: { do: 'cancelSession', to: 'selecting' },
|
||||
},
|
||||
},
|
||||
brushSelecting: {
|
||||
onEnter: [
|
||||
{
|
||||
unless: ["isPressingMetaKey", "isPressingShiftKey"],
|
||||
do: "clearSelectedIds",
|
||||
unless: ['isPressingMetaKey', 'isPressingShiftKey'],
|
||||
do: 'clearSelectedIds',
|
||||
},
|
||||
"clearBoundsRotation",
|
||||
"startBrushSession",
|
||||
'clearBoundsRotation',
|
||||
'startBrushSession',
|
||||
],
|
||||
on: {
|
||||
MOVED_POINTER: "updateBrushSession",
|
||||
PANNED_CAMERA: "updateBrushSession",
|
||||
STOPPED_POINTING: { do: "completeSession", to: "selecting" },
|
||||
CANCELLED: { do: "cancelSession", to: "selecting" },
|
||||
MOVED_POINTER: 'updateBrushSession',
|
||||
PANNED_CAMERA: 'updateBrushSession',
|
||||
STOPPED_POINTING: { do: 'completeSession', to: 'selecting' },
|
||||
CANCELLED: { do: 'cancelSession', to: 'selecting' },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
pinching: {
|
||||
on: {
|
||||
STOPPED_PINCHING: { to: "selecting" },
|
||||
PINCHED: { do: "pinchCamera" },
|
||||
STOPPED_PINCHING: { to: 'selecting' },
|
||||
PINCHED: { do: 'pinchCamera' },
|
||||
},
|
||||
},
|
||||
draw: {
|
||||
initial: "creating",
|
||||
initial: 'creating',
|
||||
states: {
|
||||
creating: {
|
||||
on: {
|
||||
CANCELLED: { to: 'selecting' },
|
||||
POINTED_CANVAS: {
|
||||
get: "newDraw",
|
||||
do: "createShape",
|
||||
to: "draw.editing",
|
||||
get: 'newDraw',
|
||||
do: 'createShape',
|
||||
to: 'draw.editing',
|
||||
},
|
||||
UNDO: { do: "undo" },
|
||||
REDO: { do: "redo" },
|
||||
UNDO: { do: 'undo' },
|
||||
REDO: { do: 'redo' },
|
||||
},
|
||||
},
|
||||
editing: {
|
||||
onEnter: "startDrawSession",
|
||||
onEnter: 'startDrawSession',
|
||||
on: {
|
||||
STOPPED_POINTING: {
|
||||
do: "completeSession",
|
||||
to: "draw.creating",
|
||||
do: 'completeSession',
|
||||
to: 'draw.creating',
|
||||
},
|
||||
CANCELLED: {
|
||||
do: ["cancelSession", "deleteSelectedIds"],
|
||||
to: "selecting",
|
||||
do: ['cancelSession', 'deleteSelectedIds'],
|
||||
to: 'selecting',
|
||||
},
|
||||
MOVED_POINTER: "updateDrawSession",
|
||||
PANNED_CAMERA: "updateDrawSession",
|
||||
MOVED_POINTER: 'updateDrawSession',
|
||||
PANNED_CAMERA: 'updateDrawSession',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
dot: {
|
||||
initial: "creating",
|
||||
initial: 'creating',
|
||||
states: {
|
||||
creating: {
|
||||
on: {
|
||||
CANCELLED: { to: 'selecting' },
|
||||
POINTED_CANVAS: {
|
||||
get: "newDot",
|
||||
do: "createShape",
|
||||
to: "dot.editing",
|
||||
get: 'newDot',
|
||||
do: 'createShape',
|
||||
to: 'dot.editing',
|
||||
},
|
||||
},
|
||||
},
|
||||
editing: {
|
||||
on: {
|
||||
STOPPED_POINTING: { do: "completeSession", to: "selecting" },
|
||||
STOPPED_POINTING: { do: 'completeSession', to: 'selecting' },
|
||||
CANCELLED: {
|
||||
do: ["cancelSession", "deleteSelectedIds"],
|
||||
to: "selecting",
|
||||
do: ['cancelSession', 'deleteSelectedIds'],
|
||||
to: 'selecting',
|
||||
},
|
||||
},
|
||||
initial: "inactive",
|
||||
initial: 'inactive',
|
||||
states: {
|
||||
inactive: {
|
||||
on: {
|
||||
MOVED_POINTER: {
|
||||
if: "distanceImpliesDrag",
|
||||
to: "dot.editing.active",
|
||||
if: 'distanceImpliesDrag',
|
||||
to: 'dot.editing.active',
|
||||
},
|
||||
},
|
||||
},
|
||||
active: {
|
||||
onEnter: "startTranslateSession",
|
||||
onEnter: 'startTranslateSession',
|
||||
on: {
|
||||
MOVED_POINTER: "updateTranslateSession",
|
||||
PANNED_CAMERA: "updateTranslateSession",
|
||||
MOVED_POINTER: 'updateTranslateSession',
|
||||
PANNED_CAMERA: 'updateTranslateSession',
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -328,25 +337,26 @@ const state = createState({
|
|||
},
|
||||
},
|
||||
circle: {
|
||||
initial: "creating",
|
||||
initial: 'creating',
|
||||
states: {
|
||||
creating: {
|
||||
on: {
|
||||
CANCELLED: { to: 'selecting' },
|
||||
POINTED_CANVAS: {
|
||||
to: "circle.editing",
|
||||
to: 'circle.editing',
|
||||
},
|
||||
},
|
||||
},
|
||||
editing: {
|
||||
on: {
|
||||
STOPPED_POINTING: { to: "selecting" },
|
||||
CANCELLED: { to: "selecting" },
|
||||
STOPPED_POINTING: { to: 'selecting' },
|
||||
CANCELLED: { to: 'selecting' },
|
||||
MOVED_POINTER: {
|
||||
if: "distanceImpliesDrag",
|
||||
if: 'distanceImpliesDrag',
|
||||
then: {
|
||||
get: "newCircle",
|
||||
do: "createShape",
|
||||
to: "drawingShape.bounds",
|
||||
get: 'newCircle',
|
||||
do: 'createShape',
|
||||
to: 'drawingShape.bounds',
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -354,26 +364,26 @@ const state = createState({
|
|||
},
|
||||
},
|
||||
ellipse: {
|
||||
initial: "creating",
|
||||
initial: 'creating',
|
||||
states: {
|
||||
creating: {
|
||||
on: {
|
||||
CANCELLED: { to: "selecting" },
|
||||
CANCELLED: { to: 'selecting' },
|
||||
POINTED_CANVAS: {
|
||||
to: "ellipse.editing",
|
||||
to: 'ellipse.editing',
|
||||
},
|
||||
},
|
||||
},
|
||||
editing: {
|
||||
on: {
|
||||
STOPPED_POINTING: { to: "selecting" },
|
||||
CANCELLED: { to: "selecting" },
|
||||
STOPPED_POINTING: { to: 'selecting' },
|
||||
CANCELLED: { to: 'selecting' },
|
||||
MOVED_POINTER: {
|
||||
if: "distanceImpliesDrag",
|
||||
if: 'distanceImpliesDrag',
|
||||
then: {
|
||||
get: "newEllipse",
|
||||
do: "createShape",
|
||||
to: "drawingShape.bounds",
|
||||
get: 'newEllipse',
|
||||
do: 'createShape',
|
||||
to: 'drawingShape.bounds',
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -381,26 +391,26 @@ const state = createState({
|
|||
},
|
||||
},
|
||||
rectangle: {
|
||||
initial: "creating",
|
||||
initial: 'creating',
|
||||
states: {
|
||||
creating: {
|
||||
on: {
|
||||
CANCELLED: { to: "selecting" },
|
||||
CANCELLED: { to: 'selecting' },
|
||||
POINTED_CANVAS: {
|
||||
to: "rectangle.editing",
|
||||
to: 'rectangle.editing',
|
||||
},
|
||||
},
|
||||
},
|
||||
editing: {
|
||||
on: {
|
||||
STOPPED_POINTING: { to: "selecting" },
|
||||
CANCELLED: { to: "selecting" },
|
||||
STOPPED_POINTING: { to: 'selecting' },
|
||||
CANCELLED: { to: 'selecting' },
|
||||
MOVED_POINTER: {
|
||||
if: "distanceImpliesDrag",
|
||||
if: 'distanceImpliesDrag',
|
||||
then: {
|
||||
get: "newRectangle",
|
||||
do: "createShape",
|
||||
to: "drawingShape.bounds",
|
||||
get: 'newRectangle',
|
||||
do: 'createShape',
|
||||
to: 'drawingShape.bounds',
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -408,50 +418,50 @@ const state = createState({
|
|||
},
|
||||
},
|
||||
ray: {
|
||||
initial: "creating",
|
||||
initial: 'creating',
|
||||
states: {
|
||||
creating: {
|
||||
on: {
|
||||
CANCELLED: { to: "selecting" },
|
||||
CANCELLED: { to: 'selecting' },
|
||||
POINTED_CANVAS: {
|
||||
get: "newRay",
|
||||
do: "createShape",
|
||||
to: "ray.editing",
|
||||
get: 'newRay',
|
||||
do: 'createShape',
|
||||
to: 'ray.editing',
|
||||
},
|
||||
},
|
||||
},
|
||||
editing: {
|
||||
on: {
|
||||
STOPPED_POINTING: { to: "selecting" },
|
||||
CANCELLED: { to: "selecting" },
|
||||
STOPPED_POINTING: { to: 'selecting' },
|
||||
CANCELLED: { to: 'selecting' },
|
||||
MOVED_POINTER: {
|
||||
if: "distanceImpliesDrag",
|
||||
to: "drawingShape.direction",
|
||||
if: 'distanceImpliesDrag',
|
||||
to: 'drawingShape.direction',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
line: {
|
||||
initial: "creating",
|
||||
initial: 'creating',
|
||||
states: {
|
||||
creating: {
|
||||
on: {
|
||||
CANCELLED: { to: "selecting" },
|
||||
CANCELLED: { to: 'selecting' },
|
||||
POINTED_CANVAS: {
|
||||
get: "newLine",
|
||||
do: "createShape",
|
||||
to: "line.editing",
|
||||
get: 'newLine',
|
||||
do: 'createShape',
|
||||
to: 'line.editing',
|
||||
},
|
||||
},
|
||||
},
|
||||
editing: {
|
||||
on: {
|
||||
STOPPED_POINTING: { to: "selecting" },
|
||||
CANCELLED: { to: "selecting" },
|
||||
STOPPED_POINTING: { to: 'selecting' },
|
||||
CANCELLED: { to: 'selecting' },
|
||||
MOVED_POINTER: {
|
||||
if: "distanceImpliesDrag",
|
||||
to: "drawingShape.direction",
|
||||
if: 'distanceImpliesDrag',
|
||||
to: 'drawingShape.direction',
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -463,28 +473,28 @@ const state = createState({
|
|||
drawingShape: {
|
||||
on: {
|
||||
STOPPED_POINTING: {
|
||||
do: "completeSession",
|
||||
to: "selecting",
|
||||
do: 'completeSession',
|
||||
to: 'selecting',
|
||||
},
|
||||
CANCELLED: {
|
||||
do: ["cancelSession", "deleteSelectedIds"],
|
||||
to: "selecting",
|
||||
do: ['cancelSession', 'deleteSelectedIds'],
|
||||
to: 'selecting',
|
||||
},
|
||||
},
|
||||
initial: "drawingShapeBounds",
|
||||
initial: 'drawingShapeBounds',
|
||||
states: {
|
||||
bounds: {
|
||||
onEnter: "startDrawTransformSession",
|
||||
onEnter: 'startDrawTransformSession',
|
||||
on: {
|
||||
MOVED_POINTER: "updateTransformSession",
|
||||
PANNED_CAMERA: "updateTransformSession",
|
||||
MOVED_POINTER: 'updateTransformSession',
|
||||
PANNED_CAMERA: 'updateTransformSession',
|
||||
},
|
||||
},
|
||||
direction: {
|
||||
onEnter: "startDirectionSession",
|
||||
onEnter: 'startDirectionSession',
|
||||
on: {
|
||||
MOVED_POINTER: "updateDirectionSession",
|
||||
PANNED_CAMERA: "updateDirectionSession",
|
||||
MOVED_POINTER: 'updateDirectionSession',
|
||||
PANNED_CAMERA: 'updateDirectionSession',
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -515,7 +525,7 @@ const state = createState({
|
|||
},
|
||||
conditions: {
|
||||
isPointingBounds(data, payload: PointerInfo) {
|
||||
return payload.target === "bounds"
|
||||
return payload.target === 'bounds'
|
||||
},
|
||||
isReadOnly(data) {
|
||||
return data.isReadOnly
|
||||
|
@ -545,9 +555,9 @@ const state = createState({
|
|||
},
|
||||
isPointingRotationHandle(
|
||||
data,
|
||||
payload: { target: Edge | Corner | "rotate" }
|
||||
payload: { target: Edge | Corner | 'rotate' }
|
||||
) {
|
||||
return payload.target === "rotate"
|
||||
return payload.target === 'rotate'
|
||||
},
|
||||
hasSelection(data) {
|
||||
return data.selectedIds.size > 0
|
||||
|
@ -753,7 +763,7 @@ const state = createState({
|
|||
data.camera.zoom = 1
|
||||
data.camera.point = [window.innerWidth / 2, window.innerHeight / 2]
|
||||
|
||||
document.documentElement.style.setProperty("--camera-zoom", "1")
|
||||
document.documentElement.style.setProperty('--camera-zoom', '1')
|
||||
},
|
||||
zoomCameraToActual(data) {
|
||||
const { camera } = data
|
||||
|
@ -983,7 +993,7 @@ const state = createState({
|
|||
|
||||
if (selectedIds.size === 1) {
|
||||
if (!shapes[0]) {
|
||||
console.error("Could not find that shape! Clearing selected IDs.")
|
||||
console.error('Could not find that shape! Clearing selected IDs.')
|
||||
data.selectedIds.clear()
|
||||
return null
|
||||
}
|
||||
|
|
|
@ -6392,10 +6392,10 @@ pend@~1.2.0:
|
|||
resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50"
|
||||
integrity sha1-elfrVQpng/kRUzH89GY9XI4AelA=
|
||||
|
||||
perfect-freehand@^0.4.71:
|
||||
version "0.4.71"
|
||||
resolved "https://registry.yarnpkg.com/perfect-freehand/-/perfect-freehand-0.4.71.tgz#b98ffc3cbc4e3cd930528e8d74a8849ee77475fb"
|
||||
integrity sha512-bJ3w2E6WcUfZJTXWPlS7DI6FIT9rRIYSCXgDYjvST8sAe/c+zNnJnlfJp3q8Hk1uPt9dH7bFuj8Sico6CKZw7A==
|
||||
perfect-freehand@^0.4.8:
|
||||
version "0.4.8"
|
||||
resolved "https://registry.yarnpkg.com/perfect-freehand/-/perfect-freehand-0.4.8.tgz#0054995322fdd9939c0c38c260d96a9d0f22eb4f"
|
||||
integrity sha512-zU0hvTh0ctjb/h5+nwFhb+/5ZnqS8Z16mn7lY2tYy3NwTkjrEKZ8CJvQ2phlOV5kk+BnCDFGVz7tkKrl9+Mr9w==
|
||||
|
||||
performance-now@^2.1.0:
|
||||
version "2.1.0"
|
||||
|
|
Loading…
Reference in a new issue