diff --git a/components/style-panel/style-panel.tsx b/components/style-panel/style-panel.tsx index 52e64455f..f92fda422 100644 --- a/components/style-panel/style-panel.tsx +++ b/components/style-panel/style-panel.tsx @@ -5,7 +5,7 @@ import { useRef } from "react" import { IconButton } from "components/shared" import { Circle, Trash, X } from "react-feather" import { deepCompare, deepCompareArrays, getSelectedShapes } from "utils/utils" -import { shades, fills, strokes } from "state/data" +import { shades, fills, strokes } from "lib/colors" import ColorPicker from "./color-picker" import AlignDistribute from "./align-distribute" diff --git a/lib/colors.ts b/lib/colors.ts new file mode 100644 index 000000000..357b1e8e8 --- /dev/null +++ b/lib/colors.ts @@ -0,0 +1,38 @@ +export const shades = { + transparent: "transparent", + white: "rgba(248, 249, 250, 1.000)", + lightGray: "rgba(224, 226, 230, 1.000)", + gray: "rgba(172, 181, 189, 1.000)", + darkGray: "rgba(52, 58, 64, 1.000)", + black: "rgba(0,0,0, 1.000)", +} + +export const strokes = { + lime: "rgba(115, 184, 23, 1.000)", + green: "rgba(54, 178, 77, 1.000)", + teal: "rgba(9, 167, 120, 1.000)", + cyan: "rgba(14, 152, 173, 1.000)", + blue: "rgba(28, 126, 214, 1.000)", + indigo: "rgba(66, 99, 235, 1.000)", + violet: "rgba(112, 72, 232, 1.000)", + grape: "rgba(174, 62, 200, 1.000)", + pink: "rgba(214, 51, 108, 1.000)", + red: "rgba(240, 63, 63, 1.000)", + orange: "rgba(247, 103, 6, 1.000)", + yellow: "rgba(245, 159, 0, 1.000)", +} + +export const fills = { + lime: "rgba(217, 245, 162, 1.000)", + green: "rgba(177, 242, 188, 1.000)", + teal: "rgba(149, 242, 215, 1.000)", + cyan: "rgba(153, 233, 242, 1.000)", + blue: "rgba(166, 216, 255, 1.000)", + indigo: "rgba(186, 200, 255, 1.000)", + violet: "rgba(208, 191, 255, 1.000)", + grape: "rgba(237, 190, 250, 1.000)", + pink: "rgba(252, 194, 215, 1.000)", + red: "rgba(255, 201, 201, 1.000)", + orange: "rgba(255, 216, 168, 1.000)", + yellow: "rgba(255, 236, 153, 1.000)", +} diff --git a/lib/shape-utils/draw.tsx b/lib/shape-utils/draw.tsx index 651ca4322..78a2d846a 100644 --- a/lib/shape-utils/draw.tsx +++ b/lib/shape-utils/draw.tsx @@ -4,8 +4,14 @@ 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" +import getStroke from "perfect-freehand" +import { + getBoundsFromPoints, + getSvgPathFromStroke, + translateBounds, +} from "utils/utils" import { DotCircle } from "components/canvas/misc" +import { shades } from "lib/colors" const pathCache = new WeakMap([]) @@ -29,7 +35,7 @@ const draw = registerShapeUtils({ strokeLinecap: "round", strokeLinejoin: "round", ...props.style, - fill: "transparent", + stroke: "transparent", }, } }, @@ -42,23 +48,7 @@ const draw = registerShapeUtils({ } if (!pathCache.has(shape)) { - pathCache.set( - shape, - points - .reduce( - (acc, [x0, y0], i, arr) => { - if (i === points.length - 1) { - acc.push("L", x0, y0) - } else { - const [x1, y1] = arr[i + 1] - acc.push(x0, y0, (x0 + x1) / 2, (y0 + y1) / 2) - } - return acc - }, - ["M", ...points[0], "Q"] - ) - .join(" ") - ) + pathCache.set(shape, getSvgPathFromStroke(getStroke(points))) } return diff --git a/package.json b/package.json index 9d7ebf136..ffd557431 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "framer-motion": "^4.1.16", "ismobilejs": "^1.1.1", "next": "10.2.0", - "perfect-freehand": "^0.4.7", + "perfect-freehand": "^0.4.71", "prettier": "^2.3.0", "react": "17.0.2", "react-dom": "17.0.2", diff --git a/state/commands/draw.ts b/state/commands/draw.ts index 66b2912d9..fde2aac3d 100644 --- a/state/commands/draw.ts +++ b/state/commands/draw.ts @@ -11,7 +11,6 @@ export default function drawCommand( before: number[][], after: number[][] ) { - const selectedIds = Array.from(data.selectedIds.values()) const restoreShape = current(getPage(data).shapes[id]) getShapeUtils(restoreShape).setPoints!(restoreShape, after) @@ -31,9 +30,6 @@ export default function drawCommand( undo(data) { delete getPage(data).shapes[id] data.selectedIds.clear() - for (let id of selectedIds) { - data.selectedIds.add(id) - } }, }) ) diff --git a/state/data.ts b/state/data.ts index 464a2478c..7868ff964 100644 --- a/state/data.ts +++ b/state/data.ts @@ -1,44 +1,6 @@ import { Data, ShapeType } from "types" import shapeUtils from "lib/shape-utils" - -export const shades = { - transparent: "transparent", - white: "rgba(248, 249, 250, 1.000)", - lightGray: "rgba(224, 226, 230, 1.000)", - gray: "rgba(172, 181, 189, 1.000)", - darkGray: "rgba(52, 58, 64, 1.000)", - black: "rgba(0,0,0, 1.000)", -} - -export const strokes = { - lime: "rgba(115, 184, 23, 1.000)", - green: "rgba(54, 178, 77, 1.000)", - teal: "rgba(9, 167, 120, 1.000)", - cyan: "rgba(14, 152, 173, 1.000)", - blue: "rgba(28, 126, 214, 1.000)", - indigo: "rgba(66, 99, 235, 1.000)", - violet: "rgba(112, 72, 232, 1.000)", - grape: "rgba(174, 62, 200, 1.000)", - pink: "rgba(214, 51, 108, 1.000)", - red: "rgba(240, 63, 63, 1.000)", - orange: "rgba(247, 103, 6, 1.000)", - yellow: "rgba(245, 159, 0, 1.000)", -} - -export const fills = { - lime: "rgba(217, 245, 162, 1.000)", - green: "rgba(177, 242, 188, 1.000)", - teal: "rgba(149, 242, 215, 1.000)", - cyan: "rgba(153, 233, 242, 1.000)", - blue: "rgba(166, 216, 255, 1.000)", - indigo: "rgba(186, 200, 255, 1.000)", - violet: "rgba(208, 191, 255, 1.000)", - grape: "rgba(237, 190, 250, 1.000)", - pink: "rgba(252, 194, 215, 1.000)", - red: "rgba(255, 201, 201, 1.000)", - orange: "rgba(255, 216, 168, 1.000)", - yellow: "rgba(255, 236, 153, 1.000)", -} +import { shades } from "lib/colors" export const defaultDocument: Data["document"] = { pages: { diff --git a/state/state.ts b/state/state.ts index 19905072c..35e7064da 100644 --- a/state/state.ts +++ b/state/state.ts @@ -1,7 +1,8 @@ import { createSelectorHook, createState } from "@state-designer/react" import * as vec from "utils/vec" import inputs from "./inputs" -import { shades, defaultDocument } from "./data" +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" @@ -92,6 +93,7 @@ const state = createState({ do: "zoomCameraToSelectionActual", else: "zoomCameraToActual", }, + SELECTED_ALL: { to: "selecting", do: "selectAll" }, }, initial: "loading", states: { @@ -133,7 +135,6 @@ const state = createState({ states: { notPointing: { on: { - SELECTED_ALL: "selectAll", POINTED_CANVAS: { to: "brushSelecting" }, POINTED_BOUNDS: { to: "pointingBounds" }, POINTED_BOUNDS_HANDLE: { @@ -262,7 +263,10 @@ const state = createState({ editing: { onEnter: "startDrawSession", on: { - STOPPED_POINTING: { do: "completeSession", to: "selecting" }, + STOPPED_POINTING: { + do: "completeSession", + to: "draw.creating", + }, CANCELLED: { do: ["cancelSession", "deleteSelectedIds"], to: "selecting", @@ -927,7 +931,7 @@ const state = createState({ }, restoreSavedData(data) { - // history.load(data) + history.load(data) }, clearBoundsRotation(data) { diff --git a/utils/utils.ts b/utils/utils.ts index 9f6c9d8fb..9765048f5 100644 --- a/utils/utils.ts +++ b/utils/utils.ts @@ -1530,3 +1530,19 @@ export function simplify(points: number[][], tolerance = 1) { return [a, b] } + +export function getSvgPathFromStroke(stroke: number[][]) { + if (!stroke.length) return "" + + const d = stroke.reduce( + (acc, [x0, y0], i, arr) => { + const [x1, y1] = arr[(i + 1) % arr.length] + acc.push(x0, y0, (x0 + x1) / 2, (y0 + y1) / 2) + return acc + }, + ["M", ...stroke[0], "Q"] + ) + + d.push("Z") + return d.join(" ") +} diff --git a/yarn.lock b/yarn.lock index e51000f0d..d26890712 100644 --- a/yarn.lock +++ b/yarn.lock @@ -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.7: - version "0.4.7" - resolved "https://registry.yarnpkg.com/perfect-freehand/-/perfect-freehand-0.4.7.tgz#4d85fd64881ba81b2a4eaa6ac4e8983ccb21dd43" - integrity sha512-SSSFL8VzXiOHQdUTyNyOb0JC+btVZRy9bi6jos7Nb7PBTI0PHX5jM6RgCTSrubQ8Ul9qOYWmWgJBrwVGHwyJZQ== +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== performance-now@^2.1.0: version "2.1.0"