Improves drawing
This commit is contained in:
parent
7ef83dc508
commit
c41def99d3
4 changed files with 80 additions and 5 deletions
|
@ -12,7 +12,6 @@ export default function Brush() {
|
||||||
y={brush.minY}
|
y={brush.minY}
|
||||||
width={brush.width}
|
width={brush.width}
|
||||||
height={brush.height}
|
height={brush.height}
|
||||||
className="brush"
|
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -20,4 +19,5 @@ export default function Brush() {
|
||||||
const BrushRect = styled("rect", {
|
const BrushRect = styled("rect", {
|
||||||
fill: "$brushFill",
|
fill: "$brushFill",
|
||||||
stroke: "$brushStroke",
|
stroke: "$brushStroke",
|
||||||
|
zStrokeWidth: 1,
|
||||||
})
|
})
|
||||||
|
|
|
@ -5,6 +5,9 @@ import { registerShapeUtils } from "./index"
|
||||||
import { intersectPolylineBounds } from "utils/intersections"
|
import { intersectPolylineBounds } from "utils/intersections"
|
||||||
import { boundsContainPolygon } from "utils/bounds"
|
import { boundsContainPolygon } from "utils/bounds"
|
||||||
import { getBoundsFromPoints, translateBounds } from "utils/utils"
|
import { getBoundsFromPoints, translateBounds } from "utils/utils"
|
||||||
|
import { DotCircle } from "components/canvas/misc"
|
||||||
|
|
||||||
|
const pathCache = new WeakMap<DrawShape, string>([])
|
||||||
|
|
||||||
const draw = registerShapeUtils<DrawShape>({
|
const draw = registerShapeUtils<DrawShape>({
|
||||||
boundsCache: new WeakMap([]),
|
boundsCache: new WeakMap([]),
|
||||||
|
@ -31,8 +34,34 @@ const draw = registerShapeUtils<DrawShape>({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
render({ id, points }) {
|
render(shape) {
|
||||||
return <polyline id={id} points={points.toString()} />
|
const { id, point, points } = shape
|
||||||
|
|
||||||
|
if (points.length < 2) {
|
||||||
|
return <DotCircle cx={point[0]} cy={point[1]} r={3} />
|
||||||
|
}
|
||||||
|
|
||||||
|
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(" ")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return <path id={id} d={pathCache.get(shape)} />
|
||||||
},
|
},
|
||||||
|
|
||||||
applyStyles(shape, style) {
|
applyStyles(shape, style) {
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { current } from "immer"
|
||||||
import { Data, DrawShape } from "types"
|
import { Data, DrawShape } from "types"
|
||||||
import BaseSession from "./base-session"
|
import BaseSession from "./base-session"
|
||||||
import { getShapeUtils } from "lib/shape-utils"
|
import { getShapeUtils } from "lib/shape-utils"
|
||||||
import { getPage } from "utils/utils"
|
import { getPage, simplify } from "utils/utils"
|
||||||
import * as vec from "utils/vec"
|
import * as vec from "utils/vec"
|
||||||
import commands from "state/commands"
|
import commands from "state/commands"
|
||||||
|
|
||||||
|
@ -42,7 +42,15 @@ export default class BrushSession extends BaseSession {
|
||||||
}
|
}
|
||||||
|
|
||||||
complete = (data: Data) => {
|
complete = (data: Data) => {
|
||||||
commands.points(data, this.shapeId, this.snapshot.points, this.points)
|
commands.points(
|
||||||
|
data,
|
||||||
|
this.shapeId,
|
||||||
|
this.snapshot.points,
|
||||||
|
simplify(this.points, 1).map(([x, y]) => [
|
||||||
|
Math.trunc(x * 100) / 100,
|
||||||
|
Math.trunc(y * 100) / 100,
|
||||||
|
])
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1492,3 +1492,41 @@ export function getCurrent<T extends object>(source: T): T {
|
||||||
Object.entries(source).map(([key, value]) => [key, value])
|
Object.entries(source).map(([key, value]) => [key, value])
|
||||||
) as T
|
) as T
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simplify a line (using Ramer-Douglas-Peucker algorithm).
|
||||||
|
* @param points An array of points as [x, y, ...][]
|
||||||
|
* @param tolerance The minimum line distance (also called epsilon).
|
||||||
|
* @returns Simplified array as [x, y, ...][]
|
||||||
|
*/
|
||||||
|
export function simplify(points: number[][], tolerance = 1) {
|
||||||
|
const len = points.length,
|
||||||
|
a = points[0],
|
||||||
|
b = points[len - 1],
|
||||||
|
[x1, y1] = a,
|
||||||
|
[x2, y2] = b
|
||||||
|
|
||||||
|
if (len > 2) {
|
||||||
|
let distance = 0,
|
||||||
|
index = 0,
|
||||||
|
max = Math.hypot(y2 - y1, x2 - x1)
|
||||||
|
|
||||||
|
for (let i = 1; i < len - 1; i++) {
|
||||||
|
const [x0, y0] = points[i],
|
||||||
|
d = Math.abs((y2 - y1) * x0 - (x2 - x1) * y0 + x2 * y1 - y2 * x1) / max
|
||||||
|
|
||||||
|
if (distance > d) continue
|
||||||
|
|
||||||
|
distance = d
|
||||||
|
index = i
|
||||||
|
}
|
||||||
|
|
||||||
|
if (distance > tolerance) {
|
||||||
|
let l0 = simplify(points.slice(0, index + 1), tolerance)
|
||||||
|
let l1 = simplify(points.slice(index + 1), tolerance)
|
||||||
|
return l0.concat(l1.slice(1))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [a, b]
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue