Adds drawing
This commit is contained in:
parent
e86cd8100d
commit
7ef83dc508
13 changed files with 353 additions and 27 deletions
|
@ -31,7 +31,7 @@ export const Layout = styled("div", {
|
||||||
gridTemplateRows: "auto 1fr",
|
gridTemplateRows: "auto 1fr",
|
||||||
gridAutoRows: "28px",
|
gridAutoRows: "28px",
|
||||||
height: "100%",
|
height: "100%",
|
||||||
width: "100%",
|
width: "auto",
|
||||||
minWidth: "100%",
|
minWidth: "100%",
|
||||||
maxWidth: 560,
|
maxWidth: 560,
|
||||||
overflow: "hidden",
|
overflow: "hidden",
|
||||||
|
@ -41,30 +41,32 @@ export const Layout = styled("div", {
|
||||||
|
|
||||||
export const Header = styled("div", {
|
export const Header = styled("div", {
|
||||||
pointerEvents: "all",
|
pointerEvents: "all",
|
||||||
display: "grid",
|
display: "flex",
|
||||||
gridTemplateColumns: "auto 1fr auto",
|
width: "100%",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
justifyContent: "center",
|
justifyContent: "space-between",
|
||||||
borderBottom: "1px solid $border",
|
borderBottom: "1px solid $border",
|
||||||
|
position: "relative",
|
||||||
"& button": {
|
|
||||||
gridColumn: "1",
|
|
||||||
gridRow: "1",
|
|
||||||
},
|
|
||||||
|
|
||||||
"& h3": {
|
"& h3": {
|
||||||
gridColumn: "1 / span 3",
|
position: "absolute",
|
||||||
gridRow: "1",
|
top: 0,
|
||||||
|
left: 0,
|
||||||
|
width: "100%",
|
||||||
|
height: "100%",
|
||||||
textAlign: "center",
|
textAlign: "center",
|
||||||
margin: "0",
|
padding: 0,
|
||||||
padding: "0",
|
margin: 0,
|
||||||
|
display: "flex",
|
||||||
|
justifyContent: "center",
|
||||||
|
alignItems: "center",
|
||||||
fontSize: "13px",
|
fontSize: "13px",
|
||||||
|
pointerEvents: "none",
|
||||||
|
userSelect: "none",
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
export const ButtonsGroup = styled("div", {
|
export const ButtonsGroup = styled("div", {
|
||||||
gridRow: "1",
|
|
||||||
gridColumn: "3",
|
|
||||||
display: "flex",
|
display: "flex",
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -98,8 +98,8 @@ const CurrentColor = styled(DropdownMenu.Trigger, {
|
||||||
content: "''",
|
content: "''",
|
||||||
position: "absolute",
|
position: "absolute",
|
||||||
top: 0,
|
top: 0,
|
||||||
left: 4,
|
left: 0,
|
||||||
right: 4,
|
right: 0,
|
||||||
bottom: 0,
|
bottom: 0,
|
||||||
pointerEvents: "none",
|
pointerEvents: "none",
|
||||||
zIndex: -1,
|
zIndex: -1,
|
||||||
|
|
|
@ -73,9 +73,6 @@ function SelectedShapeStyles({}: {}) {
|
||||||
return (
|
return (
|
||||||
<Panel.Layout>
|
<Panel.Layout>
|
||||||
<Panel.Header>
|
<Panel.Header>
|
||||||
<IconButton onClick={() => state.send("TOGGLED_STYLE_PANEL_OPEN")}>
|
|
||||||
<X />
|
|
||||||
</IconButton>
|
|
||||||
<h3>Style</h3>
|
<h3>Style</h3>
|
||||||
<Panel.ButtonsGroup>
|
<Panel.ButtonsGroup>
|
||||||
<IconButton
|
<IconButton
|
||||||
|
@ -85,6 +82,9 @@ function SelectedShapeStyles({}: {}) {
|
||||||
<Trash />
|
<Trash />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</Panel.ButtonsGroup>
|
</Panel.ButtonsGroup>
|
||||||
|
<IconButton onClick={() => state.send("TOGGLED_STYLE_PANEL_OPEN")}>
|
||||||
|
<X />
|
||||||
|
</IconButton>
|
||||||
</Panel.Header>
|
</Panel.Header>
|
||||||
<Content>
|
<Content>
|
||||||
<ColorPicker
|
<ColorPicker
|
||||||
|
@ -112,6 +112,7 @@ const StylePanelRoot = styled(Panel.Root, {
|
||||||
minWidth: 1,
|
minWidth: 1,
|
||||||
width: 184,
|
width: 184,
|
||||||
maxWidth: 184,
|
maxWidth: 184,
|
||||||
|
overflow: "hidden",
|
||||||
position: "relative",
|
position: "relative",
|
||||||
|
|
||||||
variants: {
|
variants: {
|
||||||
|
|
|
@ -13,6 +13,7 @@ export default function Toolbar() {
|
||||||
line: "line",
|
line: "line",
|
||||||
polyline: "polyline",
|
polyline: "polyline",
|
||||||
rectangle: "rectangle",
|
rectangle: "rectangle",
|
||||||
|
draw: "draw",
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -28,6 +29,12 @@ export default function Toolbar() {
|
||||||
>
|
>
|
||||||
Select
|
Select
|
||||||
</Button>
|
</Button>
|
||||||
|
<Button
|
||||||
|
isSelected={activeTool === "draw"}
|
||||||
|
onClick={() => state.send("SELECTED_DRAW_TOOL")}
|
||||||
|
>
|
||||||
|
Draw
|
||||||
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
isSelected={activeTool === "dot"}
|
isSelected={activeTool === "dot"}
|
||||||
onClick={() => state.send("SELECTED_DOT_TOOL")}
|
onClick={() => state.send("SELECTED_DOT_TOOL")}
|
||||||
|
|
|
@ -115,6 +115,10 @@ export default function useKeyboardEvents() {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
case "d": {
|
case "d": {
|
||||||
|
state.send("SELECTED_DRAW_TOOL", getKeyboardEventInfo(e))
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case "t": {
|
||||||
if (metaKey(e)) {
|
if (metaKey(e)) {
|
||||||
state.send("DUPLICATED", getKeyboardEventInfo(e))
|
state.send("DUPLICATED", getKeyboardEventInfo(e))
|
||||||
} else {
|
} else {
|
||||||
|
|
162
lib/shape-utils/draw.tsx
Normal file
162
lib/shape-utils/draw.tsx
Normal file
|
@ -0,0 +1,162 @@
|
||||||
|
import { v4 as uuid } from "uuid"
|
||||||
|
import * as vec from "utils/vec"
|
||||||
|
import { DrawShape, ShapeType } from "types"
|
||||||
|
import { registerShapeUtils } from "./index"
|
||||||
|
import { intersectPolylineBounds } from "utils/intersections"
|
||||||
|
import { boundsContainPolygon } from "utils/bounds"
|
||||||
|
import { getBoundsFromPoints, translateBounds } from "utils/utils"
|
||||||
|
|
||||||
|
const draw = registerShapeUtils<DrawShape>({
|
||||||
|
boundsCache: new WeakMap([]),
|
||||||
|
|
||||||
|
create(props) {
|
||||||
|
return {
|
||||||
|
id: uuid(),
|
||||||
|
type: ShapeType.Draw,
|
||||||
|
isGenerated: false,
|
||||||
|
name: "Draw",
|
||||||
|
parentId: "page0",
|
||||||
|
childIndex: 0,
|
||||||
|
point: [0, 0],
|
||||||
|
points: [[0, 0]],
|
||||||
|
rotation: 0,
|
||||||
|
...props,
|
||||||
|
style: {
|
||||||
|
strokeWidth: 2,
|
||||||
|
strokeLinecap: "round",
|
||||||
|
strokeLinejoin: "round",
|
||||||
|
...props.style,
|
||||||
|
fill: "transparent",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
render({ id, points }) {
|
||||||
|
return <polyline id={id} points={points.toString()} />
|
||||||
|
},
|
||||||
|
|
||||||
|
applyStyles(shape, style) {
|
||||||
|
Object.assign(shape.style, style)
|
||||||
|
shape.style.fill = "transparent"
|
||||||
|
return this
|
||||||
|
},
|
||||||
|
|
||||||
|
getBounds(shape) {
|
||||||
|
if (!this.boundsCache.has(shape)) {
|
||||||
|
const bounds = getBoundsFromPoints(shape.points)
|
||||||
|
this.boundsCache.set(shape, bounds)
|
||||||
|
}
|
||||||
|
|
||||||
|
return translateBounds(this.boundsCache.get(shape), shape.point)
|
||||||
|
},
|
||||||
|
|
||||||
|
getRotatedBounds(shape) {
|
||||||
|
return this.getBounds(shape)
|
||||||
|
},
|
||||||
|
|
||||||
|
getCenter(shape) {
|
||||||
|
const bounds = this.getBounds(shape)
|
||||||
|
return [bounds.minX + bounds.width / 2, bounds.minY + bounds.height / 2]
|
||||||
|
},
|
||||||
|
|
||||||
|
hitTest(shape, point) {
|
||||||
|
let pt = vec.sub(point, shape.point)
|
||||||
|
let prev = shape.points[0]
|
||||||
|
|
||||||
|
for (let i = 1; i < shape.points.length; i++) {
|
||||||
|
let curr = shape.points[i]
|
||||||
|
if (vec.distanceToLineSegment(prev, curr, pt) < 4) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
prev = curr
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
},
|
||||||
|
|
||||||
|
hitTestBounds(this, shape, brushBounds) {
|
||||||
|
const b = this.getBounds(shape)
|
||||||
|
const center = [b.minX + b.width / 2, b.minY + b.height / 2]
|
||||||
|
|
||||||
|
const rotatedCorners = [
|
||||||
|
[b.minX, b.minY],
|
||||||
|
[b.maxX, b.minY],
|
||||||
|
[b.maxX, b.maxY],
|
||||||
|
[b.minX, b.maxY],
|
||||||
|
].map((point) => vec.rotWith(point, center, shape.rotation))
|
||||||
|
|
||||||
|
return (
|
||||||
|
boundsContainPolygon(brushBounds, rotatedCorners) ||
|
||||||
|
intersectPolylineBounds(
|
||||||
|
shape.points.map((point) => vec.add(point, shape.point)),
|
||||||
|
brushBounds
|
||||||
|
).length > 0
|
||||||
|
)
|
||||||
|
},
|
||||||
|
|
||||||
|
rotateTo(shape, rotation) {
|
||||||
|
shape.rotation = rotation
|
||||||
|
return this
|
||||||
|
},
|
||||||
|
|
||||||
|
translateTo(shape, point) {
|
||||||
|
shape.point = point
|
||||||
|
return this
|
||||||
|
},
|
||||||
|
|
||||||
|
transform(shape, bounds, { initialShape, scaleX, scaleY }) {
|
||||||
|
const initialShapeBounds = this.boundsCache.get(initialShape)
|
||||||
|
shape.points = initialShape.points.map(([x, y]) => {
|
||||||
|
return [
|
||||||
|
bounds.width *
|
||||||
|
(scaleX < 0
|
||||||
|
? 1 - x / initialShapeBounds.width
|
||||||
|
: x / initialShapeBounds.width),
|
||||||
|
bounds.height *
|
||||||
|
(scaleY < 0
|
||||||
|
? 1 - y / initialShapeBounds.height
|
||||||
|
: y / initialShapeBounds.height),
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
const newBounds = getBoundsFromPoints(shape.points)
|
||||||
|
|
||||||
|
shape.point = vec.sub(
|
||||||
|
[bounds.minX, bounds.minY],
|
||||||
|
[newBounds.minX, newBounds.minY]
|
||||||
|
)
|
||||||
|
return this
|
||||||
|
},
|
||||||
|
|
||||||
|
transformSingle(shape, bounds, info) {
|
||||||
|
this.transform(shape, bounds, info)
|
||||||
|
return this
|
||||||
|
},
|
||||||
|
|
||||||
|
setParent(shape, parentId) {
|
||||||
|
shape.parentId = parentId
|
||||||
|
return this
|
||||||
|
},
|
||||||
|
|
||||||
|
setChildIndex(shape, childIndex) {
|
||||||
|
shape.childIndex = childIndex
|
||||||
|
return this
|
||||||
|
},
|
||||||
|
|
||||||
|
setPoints(shape, points) {
|
||||||
|
// const bounds = getBoundsFromPoints(points)
|
||||||
|
// const corner = [bounds.minX, bounds.minY]
|
||||||
|
// const nudged = points.map((point) => vec.sub(point, corner))
|
||||||
|
// this.boundsCache.set(shape, translategetBoundsFromPoints(nudged))
|
||||||
|
// shape.point = vec.add(shape.point, corner)
|
||||||
|
|
||||||
|
shape.points = points
|
||||||
|
|
||||||
|
return this
|
||||||
|
},
|
||||||
|
|
||||||
|
canTransform: true,
|
||||||
|
canChangeAspectRatio: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
export default draw
|
|
@ -16,6 +16,7 @@ import rectangle from "./rectangle"
|
||||||
import ellipse from "./ellipse"
|
import ellipse from "./ellipse"
|
||||||
import line from "./line"
|
import line from "./line"
|
||||||
import ray from "./ray"
|
import ray from "./ray"
|
||||||
|
import draw from "./draw"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Shape Utiliies
|
Shape Utiliies
|
||||||
|
@ -91,6 +92,13 @@ export interface ShapeUtility<K extends Readonly<Shape>> {
|
||||||
childIndex: number
|
childIndex: number
|
||||||
): ShapeUtility<K>
|
): ShapeUtility<K>
|
||||||
|
|
||||||
|
// Add a point
|
||||||
|
setPoints?(
|
||||||
|
this: ShapeUtility<K>,
|
||||||
|
shape: K,
|
||||||
|
points: number[][]
|
||||||
|
): ShapeUtility<K>
|
||||||
|
|
||||||
// Render a shape to JSX.
|
// Render a shape to JSX.
|
||||||
render(this: ShapeUtility<K>, shape: K): JSX.Element
|
render(this: ShapeUtility<K>, shape: K): JSX.Element
|
||||||
|
|
||||||
|
@ -119,6 +127,7 @@ const shapeUtilityMap: Record<ShapeType, ShapeUtility<Shape>> = {
|
||||||
[ShapeType.Ellipse]: ellipse,
|
[ShapeType.Ellipse]: ellipse,
|
||||||
[ShapeType.Line]: line,
|
[ShapeType.Line]: line,
|
||||||
[ShapeType.Ray]: ray,
|
[ShapeType.Ray]: ray,
|
||||||
|
[ShapeType.Draw]: draw,
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -4,6 +4,7 @@ import direct from "./direct"
|
||||||
import distribute from "./distribute"
|
import distribute from "./distribute"
|
||||||
import generate from "./generate"
|
import generate from "./generate"
|
||||||
import move from "./move"
|
import move from "./move"
|
||||||
|
import points from "./points"
|
||||||
import rotate from "./rotate"
|
import rotate from "./rotate"
|
||||||
import stretch from "./stretch"
|
import stretch from "./stretch"
|
||||||
import style from "./style"
|
import style from "./style"
|
||||||
|
@ -18,6 +19,7 @@ const commands = {
|
||||||
distribute,
|
distribute,
|
||||||
generate,
|
generate,
|
||||||
move,
|
move,
|
||||||
|
points,
|
||||||
rotate,
|
rotate,
|
||||||
stretch,
|
stretch,
|
||||||
style,
|
style,
|
||||||
|
|
28
state/commands/points.ts
Normal file
28
state/commands/points.ts
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
import Command from "./command"
|
||||||
|
import history from "../history"
|
||||||
|
import { Data } from "types"
|
||||||
|
import { getPage } from "utils/utils"
|
||||||
|
import { getShapeUtils } from "lib/shape-utils"
|
||||||
|
|
||||||
|
export default function pointsCommand(
|
||||||
|
data: Data,
|
||||||
|
id: string,
|
||||||
|
before: number[][],
|
||||||
|
after: number[][]
|
||||||
|
) {
|
||||||
|
history.execute(
|
||||||
|
data,
|
||||||
|
new Command({
|
||||||
|
name: "set_points",
|
||||||
|
category: "canvas",
|
||||||
|
do(data) {
|
||||||
|
const shape = getPage(data).shapes[id]
|
||||||
|
getShapeUtils(shape).setPoints!(shape, after)
|
||||||
|
},
|
||||||
|
undo(data) {
|
||||||
|
const shape = getPage(data).shapes[id]
|
||||||
|
getShapeUtils(shape).setPoints!(shape, before)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
57
state/sessions/draw-session.ts
Normal file
57
state/sessions/draw-session.ts
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
import { current } from "immer"
|
||||||
|
import { Data, DrawShape } from "types"
|
||||||
|
import BaseSession from "./base-session"
|
||||||
|
import { getShapeUtils } from "lib/shape-utils"
|
||||||
|
import { getPage } from "utils/utils"
|
||||||
|
import * as vec from "utils/vec"
|
||||||
|
import commands from "state/commands"
|
||||||
|
|
||||||
|
export default class BrushSession extends BaseSession {
|
||||||
|
origin: number[]
|
||||||
|
points: number[][]
|
||||||
|
snapshot: DrawSnapshot
|
||||||
|
shapeId: string
|
||||||
|
|
||||||
|
constructor(data: Data, id: string, point: number[]) {
|
||||||
|
super(data)
|
||||||
|
this.shapeId = id
|
||||||
|
this.origin = point
|
||||||
|
this.points = [[0, 0]]
|
||||||
|
this.snapshot = getDrawSnapshot(data, id)
|
||||||
|
|
||||||
|
const page = getPage(data)
|
||||||
|
const shape = page.shapes[id]
|
||||||
|
getShapeUtils(shape).translateTo(shape, point)
|
||||||
|
}
|
||||||
|
|
||||||
|
update = (data: Data, point: number[]) => {
|
||||||
|
const { shapeId } = this
|
||||||
|
|
||||||
|
this.points.push(vec.sub(point, this.origin))
|
||||||
|
|
||||||
|
const page = getPage(data)
|
||||||
|
const shape = page.shapes[shapeId]
|
||||||
|
getShapeUtils(shape).setPoints!(shape, [...this.points])
|
||||||
|
}
|
||||||
|
|
||||||
|
cancel = (data: Data) => {
|
||||||
|
const { shapeId, snapshot } = this
|
||||||
|
const page = getPage(data)
|
||||||
|
const shape = page.shapes[shapeId]
|
||||||
|
getShapeUtils(shape).setPoints!(shape, snapshot.points)
|
||||||
|
}
|
||||||
|
|
||||||
|
complete = (data: Data) => {
|
||||||
|
commands.points(data, this.shapeId, this.snapshot.points, this.points)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getDrawSnapshot(data: Data, shapeId: string) {
|
||||||
|
const page = getPage(current(data))
|
||||||
|
const { points } = page.shapes[shapeId] as DrawShape
|
||||||
|
return {
|
||||||
|
points,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export type DrawSnapshot = ReturnType<typeof getDrawSnapshot>
|
|
@ -1,17 +1,19 @@
|
||||||
import BaseSession from "./base-session"
|
import BaseSession from "./base-session"
|
||||||
import BrushSession from "./brush-session"
|
import BrushSession from "./brush-session"
|
||||||
import TranslateSession from "./translate-session"
|
import DirectionSession from "./direction-session"
|
||||||
|
import DrawSession from "./draw-session"
|
||||||
|
import RotateSession from "./rotate-session"
|
||||||
import TransformSession from "./transform-session"
|
import TransformSession from "./transform-session"
|
||||||
import TransformSingleSession from "./transform-single-session"
|
import TransformSingleSession from "./transform-single-session"
|
||||||
import DirectionSession from "./direction-session"
|
import TranslateSession from "./translate-session"
|
||||||
import RotateSession from "./rotate-session"
|
|
||||||
|
|
||||||
export {
|
export {
|
||||||
BrushSession,
|
|
||||||
BaseSession,
|
BaseSession,
|
||||||
TranslateSession,
|
BrushSession,
|
||||||
|
DirectionSession,
|
||||||
|
DrawSession,
|
||||||
|
RotateSession,
|
||||||
TransformSession,
|
TransformSession,
|
||||||
TransformSingleSession,
|
TransformSingleSession,
|
||||||
DirectionSession,
|
TranslateSession,
|
||||||
RotateSession,
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,7 @@ import {
|
||||||
DistributeType,
|
DistributeType,
|
||||||
AlignType,
|
AlignType,
|
||||||
StretchType,
|
StretchType,
|
||||||
|
DrawShape,
|
||||||
} from "types"
|
} from "types"
|
||||||
|
|
||||||
const initialData: Data = {
|
const initialData: Data = {
|
||||||
|
@ -70,6 +71,7 @@ const state = createState({
|
||||||
do: "panCamera",
|
do: "panCamera",
|
||||||
},
|
},
|
||||||
SELECTED_SELECT_TOOL: { to: "selecting" },
|
SELECTED_SELECT_TOOL: { to: "selecting" },
|
||||||
|
SELECTED_DRAW_TOOL: { unless: "isReadOnly", to: "draw" },
|
||||||
SELECTED_DOT_TOOL: { unless: "isReadOnly", to: "dot" },
|
SELECTED_DOT_TOOL: { unless: "isReadOnly", to: "dot" },
|
||||||
SELECTED_CIRCLE_TOOL: { unless: "isReadOnly", to: "circle" },
|
SELECTED_CIRCLE_TOOL: { unless: "isReadOnly", to: "circle" },
|
||||||
SELECTED_ELLIPSE_TOOL: { unless: "isReadOnly", to: "ellipse" },
|
SELECTED_ELLIPSE_TOOL: { unless: "isReadOnly", to: "ellipse" },
|
||||||
|
@ -246,6 +248,32 @@ const state = createState({
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
draw: {
|
||||||
|
initial: "creating",
|
||||||
|
states: {
|
||||||
|
creating: {
|
||||||
|
on: {
|
||||||
|
POINTED_CANVAS: {
|
||||||
|
get: "newDraw",
|
||||||
|
do: "createShape",
|
||||||
|
to: "draw.editing",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
editing: {
|
||||||
|
onEnter: "startDrawSession",
|
||||||
|
on: {
|
||||||
|
STOPPED_POINTING: { do: "completeSession", to: "selecting" },
|
||||||
|
CANCELLED: {
|
||||||
|
do: ["cancelSession", "deleteSelectedIds"],
|
||||||
|
to: "selecting",
|
||||||
|
},
|
||||||
|
MOVED_POINTER: "updateDrawSession",
|
||||||
|
PANNED_CAMERA: "updateDrawSession",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
dot: {
|
dot: {
|
||||||
initial: "creating",
|
initial: "creating",
|
||||||
states: {
|
states: {
|
||||||
|
@ -451,6 +479,9 @@ const state = createState({
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
results: {
|
results: {
|
||||||
|
newDraw() {
|
||||||
|
return ShapeType.Draw
|
||||||
|
},
|
||||||
newDot() {
|
newDot() {
|
||||||
return ShapeType.Dot
|
return ShapeType.Dot
|
||||||
},
|
},
|
||||||
|
@ -646,6 +677,19 @@ const state = createState({
|
||||||
session.update(data, screenToWorld(payload.point, data))
|
session.update(data, screenToWorld(payload.point, data))
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Drawing
|
||||||
|
startDrawSession(data) {
|
||||||
|
const id = Array.from(data.selectedIds.values())[0]
|
||||||
|
session = new Sessions.DrawSession(
|
||||||
|
data,
|
||||||
|
id,
|
||||||
|
screenToWorld(inputs.pointer.origin, data)
|
||||||
|
)
|
||||||
|
},
|
||||||
|
updateDrawSession(data, payload: PointerInfo) {
|
||||||
|
session.update(data, screenToWorld(payload.point, data))
|
||||||
|
},
|
||||||
|
|
||||||
/* -------------------- Selection ------------------- */
|
/* -------------------- Selection ------------------- */
|
||||||
|
|
||||||
selectAll(data) {
|
selectAll(data) {
|
||||||
|
|
8
types.ts
8
types.ts
|
@ -53,6 +53,7 @@ export enum ShapeType {
|
||||||
Ray = "ray",
|
Ray = "ray",
|
||||||
Polyline = "polyline",
|
Polyline = "polyline",
|
||||||
Rectangle = "rectangle",
|
Rectangle = "rectangle",
|
||||||
|
Draw = "draw",
|
||||||
}
|
}
|
||||||
|
|
||||||
// Consider:
|
// Consider:
|
||||||
|
@ -111,6 +112,11 @@ export interface RectangleShape extends BaseShape {
|
||||||
radius: number
|
radius: number
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface DrawShape extends BaseShape {
|
||||||
|
type: ShapeType.Draw
|
||||||
|
points: number[][]
|
||||||
|
}
|
||||||
|
|
||||||
export type MutableShape =
|
export type MutableShape =
|
||||||
| DotShape
|
| DotShape
|
||||||
| CircleShape
|
| CircleShape
|
||||||
|
@ -118,6 +124,7 @@ export type MutableShape =
|
||||||
| LineShape
|
| LineShape
|
||||||
| RayShape
|
| RayShape
|
||||||
| PolylineShape
|
| PolylineShape
|
||||||
|
| DrawShape
|
||||||
| RectangleShape
|
| RectangleShape
|
||||||
|
|
||||||
export type Shape = Readonly<MutableShape>
|
export type Shape = Readonly<MutableShape>
|
||||||
|
@ -129,6 +136,7 @@ export interface Shapes {
|
||||||
[ShapeType.Line]: Readonly<LineShape>
|
[ShapeType.Line]: Readonly<LineShape>
|
||||||
[ShapeType.Ray]: Readonly<RayShape>
|
[ShapeType.Ray]: Readonly<RayShape>
|
||||||
[ShapeType.Polyline]: Readonly<PolylineShape>
|
[ShapeType.Polyline]: Readonly<PolylineShape>
|
||||||
|
[ShapeType.Draw]: Readonly<DrawShape>
|
||||||
[ShapeType.Rectangle]: Readonly<RectangleShape>
|
[ShapeType.Rectangle]: Readonly<RectangleShape>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue