UNPKG

@disjukr/croquis-js

Version:
253 lines (252 loc) 9.59 kB
"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, }; }, }; }