@disjukr/croquis-js
Version:
drawing tool library
253 lines (252 loc) • 9.59 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
var rgba_1 = __importDefault(require("polished/lib/color/rgba"));
var stylus_1 = require("../stylus");
var pi = Math.PI;
var one = pi + pi;
var quarter = pi * 0.5;
var toRad = pi / 180;
var min = Math.min;
var max = Math.max;
var abs = Math.abs;
var sin = Math.sin;
var cos = Math.cos;
var sqrt = Math.sqrt;
var atan2 = Math.atan2;
var noop = function () { };
exports.defaultBrushConfig = Object.freeze({
stamp: noop,
flow: 1,
applyPressureToFlow: false,
size: 10,
applyPressureToSize: true,
spacing: 0.1,
angle: 0,
rotateToTangent: false,
angleRandom: Math.random,
angleSpread: 0,
normalRandom: Math.random,
normalSpread: 0,
tangentRandom: Math.random,
tangentSpread: 0,
});
function getHardRoundStampFn(ctx, color) {
return getStampFn(ctx, getDrawHardRoundFn(color));
}
exports.getHardRoundStampFn = getHardRoundStampFn;
function getDrawHardRoundFn(color) {
return function drawHardRound(ctx, width, height) {
var halfWidth = width * 0.5;
var halfHeight = height * 0.5;
ctx.fillStyle = color;
ctx.beginPath();
ctx.arc(halfWidth, halfHeight, halfWidth, 0, one);
ctx.closePath();
ctx.fill();
};
}
exports.getDrawHardRoundFn = getDrawHardRoundFn;
function getSoftRoundStampFn(ctx, color) {
return getStampFn(ctx, getDrawSoftRoundFn(color));
}
exports.getSoftRoundStampFn = getSoftRoundStampFn;
function getDrawSoftRoundFn(color) {
return function drawSoftRound(ctx, width, height) {
var halfWidth = width * 0.5;
var halfHeight = height * 0.5;
var grd = ctx.createRadialGradient(halfWidth, halfHeight, 0, halfWidth, halfHeight, halfWidth);
grd.addColorStop(0, color);
grd.addColorStop(1, rgba_1.default(color, 0));
ctx.fillStyle = grd;
ctx.fillRect(0, 0, 100, 100);
};
}
exports.getDrawSoftRoundFn = getDrawSoftRoundFn;
function getStarStampFn(ctx, color, numPoints, innerRatio) {
return getStampFn(ctx, getDrawStarFn(color, numPoints, innerRatio));
}
exports.getStarStampFn = getStarStampFn;
function getDrawStarFn(color, numPoints, innerRatio) {
if (numPoints === void 0) { numPoints = 5; }
if (innerRatio === void 0) { innerRatio = 0.5; }
return function drawStar(ctx, width, height) {
var halfWidth = width * 0.5;
var halfHeight = height * 0.5;
var unit = one / numPoints;
var halfUnit = unit * 0.5;
ctx.fillStyle = color;
ctx.translate(halfWidth, halfHeight);
ctx.scale(halfWidth, halfHeight);
ctx.beginPath();
ctx.moveTo(0, -1);
ctx.rotate(-quarter);
for (var a = 0; a < one; a += unit) {
ctx.lineTo(cos(a), sin(a));
ctx.lineTo(cos(a + halfUnit) * innerRatio, sin(a + halfUnit) * innerRatio);
}
ctx.closePath();
ctx.fill();
};
}
exports.getDrawStarFn = getDrawStarFn;
function getBrushWidth(size, aspectRatio) {
return size * aspectRatio;
}
exports.getBrushWidth = getBrushWidth;
function getBrushHeight(size) {
return size;
}
exports.getBrushHeight = getBrushHeight;
function getStampFn(ctx, drawFn, aspectRatio) {
if (aspectRatio === void 0) { aspectRatio = 1; }
return function stamp(config, state, params) {
var size = config.applyPressureToSize ? config.size * params.pressure : config.size;
if (size <= 0)
return;
var width = getBrushWidth(size, aspectRatio);
var height = getBrushHeight(size);
var angleSpread = config.angleSpread && config.angleSpread * (config.angleRandom() - 0.5);
var angle = params.angle +
(config.rotateToTangent ? config.angle + state.tangent : config.angle) +
angleSpread;
var normalSpread = config.normalSpread && config.normalSpread * size * (config.normalRandom() - 0.5);
var tangentSpread = config.tangentSpread && config.tangentSpread * size * (config.tangentRandom() - 0.5);
var doSpread = normalSpread || tangentSpread;
var normal = state.tangent + quarter;
var spreadX = doSpread && cos(normal) * normalSpread + cos(state.tangent) * tangentSpread;
var spreadY = doSpread && sin(normal) * normalSpread + sin(state.tangent) * tangentSpread;
var x = params.x + spreadX;
var y = params.y + spreadY;
{
// draw
ctx.save();
ctx.translate(x, y);
ctx.rotate(angle);
ctx.translate(-(width * 0.5), -(height * 0.5));
ctx.globalAlpha = config.applyPressureToFlow ? config.flow * params.pressure : config.flow;
drawFn(ctx, width, height);
ctx.restore();
}
{
// expand bounding rect
var br = state.boundingRect;
var boundWidth = angle ? abs(height * sin(angle)) + abs(width * cos(angle)) : width;
var boundHeight = angle ? abs(width * sin(angle)) + abs(height * cos(angle)) : height;
var bx = x - boundWidth * 0.5;
var by = y - boundHeight * 0.5;
var rx = br.w > 0 ? min(br.x, bx) : bx;
var ry = br.h > 0 ? min(br.y, by) : by;
var right = max(br.x + br.w, bx + boundWidth);
var bottom = max(br.y + br.h, by + boundHeight);
state.boundingRect.x = rx;
state.boundingRect.y = ry;
state.boundingRect.w = right - rx;
state.boundingRect.h = bottom - ry;
}
};
}
exports.getStampFn = getStampFn;
exports.stroke = {
resume: function (config, prevState) {
return getDrawingContext(exports.stroke, config, prevState);
},
down: function (config, curr) {
var state = {
tangent: 0,
delta: 0,
lastStamp: {
x: curr.x,
y: curr.y,
angle: curr.twist * toRad,
pressure: curr.pressure,
},
reserved: false,
boundingRect: { x: 0, y: 0, w: 0, h: 0 },
prev: stylus_1.cloneStylusState(curr),
};
var drawingContext = getDrawingContext(exports.stroke, config, state);
if (config.rotateToTangent || config.normalSpread > 0 || config.tangentSpread > 0) {
state.reserved = true;
}
else {
config.stamp(config, state, state.lastStamp);
}
return drawingContext;
},
};
function getDrawingContext(stroke, config, state) {
return {
getConfig: function (target) {
if (!target || target === stroke)
return config;
throw undefined;
},
getState: function (target) {
if (!target || target === stroke)
return state;
throw undefined;
},
move: function (curr) {
try {
{
// accumulate delta
var dx = curr.x - state.prev.x;
var dy = curr.y - state.prev.y;
state.delta += sqrt(dx * dx + dy * dy);
}
var stamp = config.stamp;
var prevPressure = state.prev.pressure;
var currPressure = curr.pressure;
var lastStamp = state.lastStamp;
var drawSpacing = max(config.applyPressureToSize
? config.size * config.spacing * ((prevPressure + currPressure) * 0.5)
: config.size * config.spacing, 0.5);
var ldx = curr.x - lastStamp.x;
var ldy = curr.y - lastStamp.y;
state.tangent = atan2(ldy, ldx);
if (state.reserved && ldx !== 0 && ldy !== 0) {
stamp(config, state, state.lastStamp);
state.reserved = false;
}
if (state.delta < drawSpacing)
return;
lastStamp.angle = curr.twist * toRad;
lastStamp.pressure = curr.pressure;
if (sqrt(ldx * ldx + ldy * ldy) < drawSpacing) {
state.delta -= drawSpacing;
lastStamp.x = curr.x;
lastStamp.y = curr.y;
stamp(config, state, lastStamp);
return;
}
var pressureSpacing = (currPressure - prevPressure) * (drawSpacing / state.delta);
var tx = cos(state.tangent);
var ty = sin(state.tangent);
while (state.delta >= drawSpacing) {
lastStamp.x += tx * drawSpacing;
lastStamp.y += ty * drawSpacing;
lastStamp.pressure += pressureSpacing;
state.delta -= drawSpacing;
stamp(config, state, lastStamp);
}
}
finally {
stylus_1.copyStylusState(state.prev, curr);
}
},
up: function (curr) {
var lastStamp = state.lastStamp;
state.tangent = atan2(curr.y - lastStamp.y, curr.x - lastStamp.x);
if (state.reserved) {
config.stamp(config, state, state.lastStamp);
state.reserved = false;
}
return {
boundingRect: state.boundingRect,
};
},
};
}