kopia lustrzana https://github.com/Tldraw/Tldraw
128 wiersze
3.7 KiB
TypeScript
128 wiersze
3.7 KiB
TypeScript
import { EASINGS } from '@tldraw/editor'
|
|
import { StrokeOptions, StrokePoint } from './types'
|
|
|
|
const { min } = Math
|
|
|
|
// This is the rate of change for simulated pressure. It could be an option.
|
|
const RATE_OF_PRESSURE_CHANGE = 0.275
|
|
|
|
/** @public */
|
|
export function setStrokePointRadii(strokePoints: StrokePoint[], options: StrokeOptions) {
|
|
const {
|
|
size = 16,
|
|
thinning = 0.5,
|
|
simulatePressure = true,
|
|
easing = (t) => t,
|
|
start = {},
|
|
end = {},
|
|
} = options
|
|
|
|
const { easing: taperStartEase = EASINGS.easeOutQuad } = start
|
|
const { easing: taperEndEase = EASINGS.easeOutCubic } = end
|
|
|
|
const totalLength = strokePoints[strokePoints.length - 1].runningLength
|
|
|
|
let firstRadius: number | undefined
|
|
let prevPressure = strokePoints[0].pressure
|
|
let strokePoint: StrokePoint
|
|
|
|
if (!simulatePressure && totalLength < size) {
|
|
const max = strokePoints.reduce((max, curr) => Math.max(max, curr.pressure), 0.5)
|
|
strokePoints.forEach((sp) => {
|
|
sp.pressure = max
|
|
sp.radius = size * easing(0.5 - thinning * (0.5 - sp.pressure))
|
|
})
|
|
return strokePoints
|
|
} else {
|
|
// Calculate initial pressure based on the average of the first
|
|
// n number of points. This prevents "dots" at the start of the
|
|
// line. Drawn lines almost always start slow!
|
|
let p: number
|
|
for (let i = 0, n = strokePoints.length; i < n; i++) {
|
|
strokePoint = strokePoints[i]
|
|
if (strokePoint.runningLength > size * 5) break
|
|
const sp = min(1, strokePoint.distance / size)
|
|
if (simulatePressure) {
|
|
const rp = min(1, 1 - sp)
|
|
p = min(1, prevPressure + (rp - prevPressure) * (sp * RATE_OF_PRESSURE_CHANGE))
|
|
} else {
|
|
p = min(1, prevPressure + (strokePoint.pressure - prevPressure) * 0.5)
|
|
}
|
|
prevPressure = prevPressure + (p - prevPressure) * 0.5
|
|
}
|
|
|
|
// Now calculate pressure and radius for each point
|
|
for (let i = 0; i < strokePoints.length; i++) {
|
|
strokePoint = strokePoints[i]
|
|
if (thinning) {
|
|
let { pressure } = strokePoint
|
|
const sp = min(1, strokePoint.distance / size)
|
|
if (simulatePressure) {
|
|
// If we're simulating pressure, then do so based on the distance
|
|
// between the current point and the previous point, and the size
|
|
// of the stroke.
|
|
const rp = min(1, 1 - sp)
|
|
pressure = min(1, prevPressure + (rp - prevPressure) * (sp * RATE_OF_PRESSURE_CHANGE))
|
|
} else {
|
|
// Otherwise, use the input pressure slightly smoothed based on the
|
|
// distance between the current point and the previous point.
|
|
pressure = min(
|
|
1,
|
|
prevPressure + (pressure - prevPressure) * (sp * RATE_OF_PRESSURE_CHANGE)
|
|
)
|
|
}
|
|
|
|
strokePoint.radius = size * easing(0.5 - thinning * (0.5 - pressure))
|
|
|
|
prevPressure = pressure
|
|
} else {
|
|
strokePoint.radius = size / 2
|
|
}
|
|
|
|
if (firstRadius === undefined) {
|
|
firstRadius = strokePoint.radius
|
|
}
|
|
}
|
|
}
|
|
|
|
const taperStart =
|
|
start.taper === false
|
|
? 0
|
|
: start.taper === true
|
|
? Math.max(size, totalLength)
|
|
: (start.taper as number)
|
|
|
|
const taperEnd =
|
|
end.taper === false
|
|
? 0
|
|
: end.taper === true
|
|
? Math.max(size, totalLength)
|
|
: (end.taper as number)
|
|
|
|
if (taperStart || taperEnd) {
|
|
for (let i = 0; i < strokePoints.length; i++) {
|
|
strokePoint = strokePoints[i]
|
|
/*
|
|
Apply tapering
|
|
|
|
If the current length is within the taper distance at either the
|
|
start or the end, calculate the taper strengths. Apply the smaller
|
|
of the two taper strengths to the radius.
|
|
*/
|
|
|
|
const { runningLength } = strokePoint
|
|
|
|
const ts = runningLength < taperStart ? taperStartEase(runningLength / taperStart) : 1
|
|
|
|
const te =
|
|
totalLength - runningLength < taperEnd
|
|
? taperEndEase((totalLength - runningLength) / taperEnd)
|
|
: 1
|
|
|
|
strokePoint.radius = Math.max(0.01, strokePoint.radius * Math.min(ts, te))
|
|
}
|
|
}
|
|
|
|
return strokePoints
|
|
}
|