Last active
July 6, 2018 07:09
-
-
Save giautm/8cb0a793de57244c8dd00a10d2ee7fe7 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { vec2 } from 'gl-matrix'; | |
const ZERO_VECTOR = vec2.create(); | |
function linePerpendicularToLine(out, vec, middlePoint, weight) { | |
if (weight <= 0 || vec2.equals(vec, ZERO_VECTOR)) { | |
vec2.copy(out[0], middlePoint); | |
vec2.copy(out[1], middlePoint); | |
} else { | |
const perpendicular = vec2.fromValues(vec[1], -vec[0]); | |
vec2.normalize(perpendicular, perpendicular); | |
const haflWeight = weight * 0.5; | |
vec2.scaleAndAdd(out[0], middlePoint, perpendicular, +haflWeight); | |
vec2.scaleAndAdd(out[1], middlePoint, perpendicular, -haflWeight); | |
} | |
return out; | |
} | |
export function lineCreate() { | |
return [vec2.create(), vec2.create()]; | |
} | |
export function lineAverage(out, lineA, lineB) { | |
vec2.scale(out[0], vec2.add(out[0], lineA[0], lineB[0]), 0.5); | |
vec2.scale(out[1], vec2.add(out[1], lineA[1], lineB[1]), 0.5); | |
return out; | |
} | |
export function linesPerpendicularToLine(pointA, pointB) { | |
const lineVec = vec2.subtract(vec2.create(), pointB.point, pointA.point); | |
return { | |
first: linePerpendicularToLine(lineCreate(), lineVec, pointA.point, pointA.weight), | |
second: linePerpendicularToLine(lineCreate(), lineVec, pointB.point, pointB.weight), | |
}; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { EventEmitter } from 'fbemitter'; | |
import { vec2 } from 'gl-matrix'; | |
class SignatureBezierProvider extends EventEmitter { | |
static dotWeight = 3; | |
static pointsPerLine = 4; | |
static touchDistanceThreshold = 2; | |
static events = ['doDot', 'doLine', 'doQuadCurve', 'doBezierCurve']; | |
static signatureWeightForLine(pointA, pointB) { | |
/** | |
* The is the maximum length that will vary weight. | |
* Anything higher will return the same weight. | |
*/ | |
const maxLengthRange = 50.0; | |
/** | |
* These are based on having a minimum line thickness of 2.0 and maximum of 7.0, | |
* linearly over line lengths 0-maxLengthRange. | |
* They fit into a typical linear equation: y = mx + c | |
* | |
* Note: Only the points of the two parallel bezier curves will be | |
* at least as thick as the constant. The bezier curves themselves | |
* could still be drawn with sharp angles, meaning there is no true | |
* 'minimum thickness' of the signature. | |
*/ | |
const gradient = 0.1; | |
const constant = 2.0; | |
const length = vec2.length(pointA, pointB); | |
const inversedLength = Math.max(maxLengthRange - length, 0); | |
return inversedLength * gradient + constant; | |
} | |
points = new Array(SignatureBezierProvider.pointsPerLine) | |
.fill(SignatureBezierProvider.dotWeight) | |
.map(weight => ({ point: vec2.create(), weight })); | |
addPointToSignature(point) { | |
if (this.isFirstPoint) { | |
this.startNewLine(point, SignatureBezierProvider.dotWeight); | |
} else { | |
let previousPoint = this.previousPoint; | |
if (vec2.length(previousPoint, point) < SignatureBezierProvider.touchDistanceThreshold) { | |
return; | |
} | |
if (this.isStartOfNextLine) { | |
this.finalizeBezier(point); | |
this.startNewLine(this.points[3].point, this.points[3].weight); | |
} | |
this.addPointAndWeight( | |
point, | |
SignatureBezierProvider.signatureWeightForLine(previousPoint, point) | |
); | |
} | |
this.generateBezierPath(this.nextPointIndex - 1); | |
} | |
finalizeBezier(point3rd) { | |
/** | |
* Smooth the join between beziers by modifying the last point of the current bezier | |
* to equal the average of the points either side of it. | |
*/ | |
const point2nd = this.points[2].point; | |
const pointAvg = this.points[3].point; | |
vec2.scale(pointAvg, vec2.add(pointAvg, point2nd, point3rd), 0.5); | |
this.points[3].weight = SignatureBezierProvider.signatureWeightForLine(point2nd, pointAvg); | |
this.generateBezierPath(3, true); | |
} | |
generateBezierPath(index, finalized = false) { | |
this.emit(SignatureBezierProvider.events[index], this.points, finalized); | |
} | |
startNewLine(point, weight) { | |
this.nextPointIndex = 0; | |
this.addPointAndWeight(point, weight); | |
} | |
addPointAndWeight(point, weight) { | |
vec2.copy(this.points[this.nextPointIndex].point, point); | |
this.points[this.nextPointIndex].weight = weight; | |
this.nextPointIndex += 1; | |
} | |
get isFirstPoint() { | |
return this.nextPointIndex === 0; | |
} | |
get isStartOfNextLine() { | |
return this.nextPointIndex >= SignatureBezierProvider.pointsPerLine; | |
} | |
get previousPoint() { | |
return this.points[this.nextPointIndex - 1].point; | |
} | |
} | |
export default SignatureBezierProvider; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment