kopia lustrzana https://github.com/Tldraw/Tldraw
259 wiersze
6.8 KiB
TypeScript
259 wiersze
6.8 KiB
TypeScript
import { getRoundedInkyPolygonPath, getRoundedPolygonPoints, VecLike } from '@tldraw/primitives'
|
|
import { TLGeoShape } from '@tldraw/tlschema'
|
|
import * as React from 'react'
|
|
import { getShapeFillSvg, getSvgWithShapeFill, ShapeFill } from '../../shared/ShapeFill'
|
|
import { TLExportColors } from '../../shared/TLExportColors'
|
|
|
|
export const DrawStylePolygon = React.memo(function DrawStylePolygon({
|
|
id,
|
|
outline,
|
|
lines,
|
|
fill,
|
|
color,
|
|
strokeWidth,
|
|
}: Pick<TLGeoShape['props'], 'fill' | 'color'> & {
|
|
id: TLGeoShape['id']
|
|
outline: VecLike[]
|
|
strokeWidth: number
|
|
lines?: VecLike[][]
|
|
}) {
|
|
const polygonPoints = getRoundedPolygonPoints(id, outline, strokeWidth / 3, strokeWidth * 2, 2)
|
|
let strokePathData = getRoundedInkyPolygonPath(polygonPoints)
|
|
|
|
if (lines) {
|
|
for (const [A, B] of lines) {
|
|
strokePathData += `M${A.x},${A.y}L${B.x},${B.y}`
|
|
}
|
|
}
|
|
|
|
const innerPolygonPoints = getRoundedPolygonPoints(id, outline, 0, strokeWidth * 2, 1)
|
|
const innerPathData = getRoundedInkyPolygonPath(innerPolygonPoints)
|
|
|
|
return (
|
|
<>
|
|
<ShapeFill d={innerPathData} fill={fill} color={color} />
|
|
<path d={strokePathData} stroke="currentColor" strokeWidth={strokeWidth} fill="none" />
|
|
</>
|
|
)
|
|
})
|
|
|
|
export function DrawStylePolygonSvg({
|
|
id,
|
|
outline,
|
|
lines,
|
|
fill,
|
|
color,
|
|
colors,
|
|
strokeWidth,
|
|
}: Pick<TLGeoShape['props'], 'fill' | 'color'> & {
|
|
id: TLGeoShape['id']
|
|
outline: VecLike[]
|
|
lines?: VecLike[][]
|
|
strokeWidth: number
|
|
colors: TLExportColors
|
|
}) {
|
|
const polygonPoints = getRoundedPolygonPoints(id, outline, strokeWidth / 3, strokeWidth * 2, 2)
|
|
|
|
let strokePathData = getRoundedInkyPolygonPath(polygonPoints)
|
|
|
|
if (lines) {
|
|
for (const [A, B] of lines) {
|
|
strokePathData += `M${A.x},${A.y}L${B.x},${B.y}`
|
|
}
|
|
}
|
|
|
|
const innerPolygonPoints = getRoundedPolygonPoints(id, outline, 0, strokeWidth * 2, 1)
|
|
const innerPathData = getRoundedInkyPolygonPath(innerPolygonPoints)
|
|
|
|
const strokeElement = document.createElementNS('http://www.w3.org/2000/svg', 'path')
|
|
strokeElement.setAttribute('d', strokePathData)
|
|
strokeElement.setAttribute('fill', 'none')
|
|
strokeElement.setAttribute('stroke', colors.fill[color])
|
|
strokeElement.setAttribute('stroke-width', strokeWidth.toString())
|
|
|
|
// Get the fill element, if any
|
|
const fillElement = getShapeFillSvg({
|
|
d: innerPathData,
|
|
fill,
|
|
color,
|
|
colors,
|
|
})
|
|
|
|
return getSvgWithShapeFill(strokeElement, fillElement)
|
|
}
|
|
|
|
// function getPolygonDrawPoints(id: string, outline: VecLike[], strokeWidth: number) {
|
|
// const points: Vec2d[] = []
|
|
|
|
// const getRandom = rng(id)
|
|
|
|
// const start = Math.round(Math.abs(getRandom()) * outline.length)
|
|
|
|
// const corners = outline.map((p) =>
|
|
// Vec2d.AddXY(p, (getRandom() * strokeWidth) / 4, (getRandom() * strokeWidth) / 4)
|
|
// )
|
|
|
|
// const len = corners.length
|
|
|
|
// for (let i = 0, n = len + 1; i < n; i++) {
|
|
// const At = corners[(start + i) % len]
|
|
// const Bt = corners[(start + i + 1) % len]
|
|
|
|
// const dist = Math.min(Vec2d.Dist(At, Bt) / 2, strokeWidth / 2)
|
|
// const A = Vec2d.Nudge(At, Bt, dist)
|
|
|
|
// const D = Vec2d.Med(At, Bt)
|
|
|
|
// if (i === 0) {
|
|
// Bt.z = 0.7
|
|
// points.push(new Vec2d(D.x, D.y, 0.7), Bt)
|
|
// } else if (i === outline.length) {
|
|
// const lastSegPoints = Vec2d.PointsBetween(A, D, 4)
|
|
// lastSegPoints.forEach((p) => (p.z = 0.7))
|
|
// points.push(...lastSegPoints)
|
|
// } else {
|
|
// points.push(...Vec2d.PointsBetween(A, Bt, 6))
|
|
// }
|
|
// }
|
|
|
|
// return points
|
|
// }
|
|
|
|
// export function getPolygonIndicatorPath(id: string, outline: VecLike[], strokeWidth: number) {
|
|
// const points = getPolygonDrawPoints(id, outline, strokeWidth)
|
|
// const options = getPolygonStrokeOptions(strokeWidth)
|
|
// const strokePoints = getStrokePoints(points, options)
|
|
|
|
// return getSvgPathFromStrokePoints(strokePoints, true)
|
|
// }
|
|
|
|
// function getPolygonStrokeOptions(strokeWidth: number) {
|
|
// return {
|
|
// size: 1 + strokeWidth * 0.618,
|
|
// last: true,
|
|
// simulatePressure: false,
|
|
// streamline: 0.25,
|
|
// thinning: 0.9,
|
|
// }
|
|
// }
|
|
|
|
// function getPolygonstrokePathData(id: string, outline: VecLike[], strokeWidth: number) {
|
|
// // draw a line between all of the points
|
|
// let d = `M${outline[0].x},${outline[0].y}`
|
|
// d += 'Z'
|
|
|
|
// for (const { x, y } of outline) {
|
|
// d += `${x},${y}`
|
|
// }
|
|
|
|
// return d
|
|
// }
|
|
|
|
// function SimpleInkyPolygon(id: string, outline: VecLike[], offset: number) {
|
|
// const random = rng(id)
|
|
// let p = outline[0]
|
|
|
|
// let ox = random() * offset
|
|
// let oy = random() * offset
|
|
|
|
// let polylineA = `M${p.x - ox},${p.y - oy}L`
|
|
// let polylineB = `${p.x + ox},${p.y + oy} `
|
|
|
|
// for (let i = 1, n = outline.length; i < n; i++) {
|
|
// p = outline[i]
|
|
// ox = random() * offset
|
|
// oy = random() * offset
|
|
|
|
// polylineA += `${p.x - ox},${p.y - oy} `
|
|
// polylineB += `${p.x + ox},${p.y + oy} `
|
|
// }
|
|
|
|
// polylineB += 'Z'
|
|
|
|
// polylineA += polylineB
|
|
|
|
// return polylineA
|
|
// }
|
|
|
|
// function CubicInkyPolygon(id: string, outline: VecLike[], offset: number) {
|
|
// const random = rng(id)
|
|
// let p0 = outline[0]
|
|
// let p1 = p0
|
|
|
|
// let ox: number
|
|
// let oy: number
|
|
|
|
// let polylineA = `M${p0.x},${p0.y} L`
|
|
// let polylineB = `M${p0.x},${p0.y}`
|
|
|
|
// for (let i = 0, n = outline.length; i < n; i++) {
|
|
// p0 = outline[i]
|
|
// p1 = outline[(i + 1) % n]
|
|
|
|
// polylineA += `${p1.x},${p1.y} `
|
|
|
|
// ox = random() * offset
|
|
// oy = random() * offset
|
|
// const c1 = Vec2d.Lrp(p0, p1, 0.25)
|
|
// const c2 = Vec2d.Lrp(p0, p1, 0.75)
|
|
|
|
// polylineB += `C${c1.x + ox},${c1.y + oy} ${c2.x - ox},${c2.y - oy} ${p1.x},${p1.y}`
|
|
// }
|
|
|
|
// polylineB += 'Z'
|
|
|
|
// polylineA += polylineB
|
|
|
|
// return polylineA
|
|
// }
|
|
|
|
// function QuadraticInkyPolygon(id: string, outline: VecLike[], offset: number) {
|
|
// const random = rng(id)
|
|
// let p0 = outline[0]
|
|
// let p1 = p0
|
|
|
|
// let polylineA = `M${p0.x},${p0.y} Q`
|
|
|
|
// const len = outline.length
|
|
|
|
// for (let i = 0, n = len * 2; i < n; i++) {
|
|
// p0 = outline[i % len]
|
|
// p1 = outline[(i + 1) % len]
|
|
// const dist = Vec2d.Dist(p0, p1)
|
|
|
|
// const c1 = Vec2d.Lrp(p0, p1, 0.5 + random() / 2)
|
|
// polylineA += `${c1.x + random() * Math.min(dist / 10, offset)},${
|
|
// c1.y + random() * Math.min(dist / 10, offset)
|
|
// } ${p1.x + (random() * offset) / 2},${p1.y + (random() * offset) / 2} `
|
|
// }
|
|
|
|
// polylineA += 'Z'
|
|
|
|
// return polylineA
|
|
// }
|
|
|
|
// function GlobyInkyPolygon(id: string, outline: VecLike[], offset: number) {
|
|
// const random = rng(id)
|
|
// let p0 = outline[0]
|
|
// let p1 = p0
|
|
|
|
// let polylineA = `M${p0.x},${p0.y} Q`
|
|
|
|
// const len = outline.length
|
|
|
|
// for (let i = 0, n = len * 2; i < n; i++) {
|
|
// p0 = outline[i % len]
|
|
// p1 = outline[(i + 1) % len]
|
|
// const dist = Vec2d.Dist(p0, p1)
|
|
|
|
// const c1 = Vec2d.Lrp(p0, p1, 0.5 + random() / 2)
|
|
// polylineA += `${c1.x + random() * Math.min(dist / 10, offset)},${
|
|
// c1.y + random() * Math.min(dist / 10, offset)
|
|
// } ${p1.x + (random() * offset) / 2},${p1.y + (random() * offset) / 2} `
|
|
// }
|
|
|
|
// polylineA += 'Z'
|
|
|
|
// return polylineA
|
|
// }
|