mirror of
https://github.com/skishore/makemeahanzi.git
synced 2025-10-30 02:18:16 +08:00
153 lines
4.4 KiB
JavaScript
153 lines
4.4 KiB
JavaScript
// Helper methods used by the handwriting class.
|
|
|
|
const kCrossWidth = 2;
|
|
const kMinWidth = 6;
|
|
const kMaxWidth = 10;
|
|
const kOffset = 10;
|
|
const kPositiveDecay = 16;
|
|
const kNegativeDecay = 64;
|
|
|
|
const createSketch = (element, handwriting) => {
|
|
let mousedown = false;
|
|
Sketch.create({
|
|
container: element[0],
|
|
autoclear: false,
|
|
fullscreen: false,
|
|
width: element.width(),
|
|
height: element.height(),
|
|
mousedown(e) {
|
|
mousedown = true;
|
|
handwriting._pushPoint([e.x, e.y]);
|
|
},
|
|
mouseup(e) {
|
|
mousedown = false;
|
|
handwriting._endStroke();
|
|
},
|
|
touchmove() {
|
|
if (mousedown && this.touches.length > 0) {
|
|
const touch = this.touches[0];
|
|
handwriting._maybePushPoint([touch.ox, touch.oy]);
|
|
handwriting._pushPoint([touch.x, touch.y]);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
const dottedLine = (x1, y1, x2, y2) => {
|
|
const result = new createjs.Shape();
|
|
result.graphics.setStrokeDash([kCrossWidth, kCrossWidth], 0);
|
|
result.graphics.setStrokeStyle(kCrossWidth)
|
|
result.graphics.beginStroke('#ccc');
|
|
result.graphics.moveTo(x1, y1);
|
|
result.graphics.lineTo(x2, y2);
|
|
return result;
|
|
}
|
|
|
|
const midpoint = (point1, point2) => {
|
|
return [(point1[0] + point2[0]) / 2, (point1[1] + point2[1]) / 2];
|
|
}
|
|
|
|
const renderCross = (stage) => {
|
|
const cross = new createjs.Container();
|
|
const height = stage.canvas.height;
|
|
const width = stage.canvas.width;
|
|
cross.addChild(dottedLine(0, 0, width, height));
|
|
cross.addChild(dottedLine(width, 0, 0, height));
|
|
cross.addChild(dottedLine(width / 2, 0, width / 2, height));
|
|
cross.addChild(dottedLine(0, height / 2, width, height / 2));
|
|
cross.cache(0, 0, width, height);
|
|
stage.addChild(cross);
|
|
}
|
|
|
|
// Methods for actually executing drawing commands.
|
|
|
|
this.makemeahanzi.Handwriting = class Handwriting {
|
|
constructor(element, callback, zoom) {
|
|
this._callback = callback;
|
|
this._zoom = zoom;
|
|
|
|
createSketch(element, this);
|
|
this._container = new createjs.Container();
|
|
this._stage = new createjs.Stage(element.find('canvas')[0]);
|
|
|
|
renderCross(this._stage);
|
|
this._stage.addChild(this._container);
|
|
this._reset();
|
|
}
|
|
clear() {
|
|
this._container.removeAllChildren();
|
|
this._reset();
|
|
}
|
|
undo() {
|
|
this._container.removeChildAt(this._container.children.length - 1);
|
|
this._reset();
|
|
}
|
|
_distance(point1, point2) {
|
|
const diagonal = this._stage.canvas.width * this._stage.canvas.width +
|
|
this._stage.canvas.height * this._stage.canvas.height;
|
|
const diff = [point1[0] - point2[0], point1[1] - point2[1]];
|
|
return (diff[0] * diff[0] + diff[1] * diff[1]) / diagonal;
|
|
}
|
|
_draw(point1, point2, control) {
|
|
const graphics = this._shape.graphics;
|
|
graphics.setStrokeStyle(this._width, 'round');
|
|
graphics.beginStroke('black');
|
|
graphics.moveTo(point1[0], point1[1]);
|
|
if (control) {
|
|
graphics.curveTo(control[0], control[1], point2[0], point2[1]);
|
|
} else {
|
|
graphics.lineTo(point2[0], point2[1]);
|
|
}
|
|
this._stage.update();
|
|
}
|
|
_endStroke() {
|
|
if (this._shape) {
|
|
this._callback(this._stroke);
|
|
this._shape.cache(0, 0, this._stage.canvas.width,
|
|
this._stage.canvas.height);
|
|
}
|
|
this._reset();
|
|
}
|
|
_maybePushPoint(point) {
|
|
if (this._stroke.length === 0) {
|
|
this._pushPoint(point);
|
|
}
|
|
}
|
|
_pushPoint(point) {
|
|
if (point[0] != null && point[1] != null) {
|
|
this._stroke.push(point.map((x) => Math.round(x / this._zoom)));
|
|
this._refresh();
|
|
}
|
|
}
|
|
_refresh() {
|
|
if (this._stroke.length < 2) {
|
|
return;
|
|
}
|
|
const i = this._stroke.length - 2;
|
|
const last = this._midpoint;
|
|
this._midpoint = midpoint(this._stroke[i], this._stroke[i + 1]);
|
|
if (this._shape) {
|
|
this._updateWidth(this._distance(this._stroke[i], this._stroke[i + 1]));
|
|
this._draw(last, this._midpoint, this._stroke[i]);
|
|
} else {
|
|
this._shape = new createjs.Shape();
|
|
this._container.addChild(this._shape);
|
|
this._draw(this._stroke[i], this._midpoint);
|
|
}
|
|
}
|
|
_reset() {
|
|
this._midpoint = null;
|
|
this._shape = null;
|
|
this._stroke = [];
|
|
this._width = kMaxWidth;
|
|
this._stage.update();
|
|
}
|
|
_updateWidth(distance) {
|
|
if (distance <= 0) return;
|
|
let offset = (Math.log(distance) + kOffset);
|
|
offset /= (offset > 0 ? kPositiveDecay : kNegativeDecay);
|
|
this._width = Math.max(Math.min(
|
|
this._width - offset, kMaxWidth), kMinWidth);
|
|
}
|
|
}
|