"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.HitContext = exports.SceneContext = exports.Context = void 0; const Util_1 = require("./Util"); const Global_1 = require("./Global"); function simplifyArray(arr) { var retArr = [], len = arr.length, util = Util_1.Util, n, val; for (n = 0; n < len; n++) { val = arr[n]; if (util._isNumber(val)) { val = Math.round(val * 1000) / 1000; } else if (!util._isString(val)) { val = val + ''; } retArr.push(val); } return retArr; } var COMMA = ',', OPEN_PAREN = '(', CLOSE_PAREN = ')', OPEN_PAREN_BRACKET = '([', CLOSE_BRACKET_PAREN = '])', SEMICOLON = ';', DOUBLE_PAREN = '()', EQUALS = '=', CONTEXT_METHODS = [ 'arc', 'arcTo', 'beginPath', 'bezierCurveTo', 'clearRect', 'clip', 'closePath', 'createLinearGradient', 'createPattern', 'createRadialGradient', 'drawImage', 'ellipse', 'fill', 'fillText', 'getImageData', 'createImageData', 'lineTo', 'moveTo', 'putImageData', 'quadraticCurveTo', 'rect', 'roundRect', 'restore', 'rotate', 'save', 'scale', 'setLineDash', 'setTransform', 'stroke', 'strokeText', 'transform', 'translate', ]; var CONTEXT_PROPERTIES = [ 'fillStyle', 'strokeStyle', 'shadowColor', 'shadowBlur', 'shadowOffsetX', 'shadowOffsetY', 'letterSpacing', 'lineCap', 'lineDashOffset', 'lineJoin', 'lineWidth', 'miterLimit', 'direction', 'font', 'textAlign', 'textBaseline', 'globalAlpha', 'globalCompositeOperation', 'imageSmoothingEnabled', ]; const traceArrMax = 100; class Context { constructor(canvas) { this.canvas = canvas; if (Global_1.Konva.enableTrace) { this.traceArr = []; this._enableTrace(); } } fillShape(shape) { if (shape.fillEnabled()) { this._fill(shape); } } _fill(shape) { } strokeShape(shape) { if (shape.hasStroke()) { this._stroke(shape); } } _stroke(shape) { } fillStrokeShape(shape) { if (shape.attrs.fillAfterStrokeEnabled) { this.strokeShape(shape); this.fillShape(shape); } else { this.fillShape(shape); this.strokeShape(shape); } } getTrace(relaxed, rounded) { var traceArr = this.traceArr, len = traceArr.length, str = '', n, trace, method, args; for (n = 0; n < len; n++) { trace = traceArr[n]; method = trace.method; if (method) { args = trace.args; str += method; if (relaxed) { str += DOUBLE_PAREN; } else { if (Util_1.Util._isArray(args[0])) { str += OPEN_PAREN_BRACKET + args.join(COMMA) + CLOSE_BRACKET_PAREN; } else { if (rounded) { args = args.map((a) => typeof a === 'number' ? Math.floor(a) : a); } str += OPEN_PAREN + args.join(COMMA) + CLOSE_PAREN; } } } else { str += trace.property; if (!relaxed) { str += EQUALS + trace.val; } } str += SEMICOLON; } return str; } clearTrace() { this.traceArr = []; } _trace(str) { var traceArr = this.traceArr, len; traceArr.push(str); len = traceArr.length; if (len >= traceArrMax) { traceArr.shift(); } } reset() { var pixelRatio = this.getCanvas().getPixelRatio(); this.setTransform(1 * pixelRatio, 0, 0, 1 * pixelRatio, 0, 0); } getCanvas() { return this.canvas; } clear(bounds) { var canvas = this.getCanvas(); if (bounds) { this.clearRect(bounds.x || 0, bounds.y || 0, bounds.width || 0, bounds.height || 0); } else { this.clearRect(0, 0, canvas.getWidth() / canvas.pixelRatio, canvas.getHeight() / canvas.pixelRatio); } } _applyLineCap(shape) { const lineCap = shape.attrs.lineCap; if (lineCap) { this.setAttr('lineCap', lineCap); } } _applyOpacity(shape) { var absOpacity = shape.getAbsoluteOpacity(); if (absOpacity !== 1) { this.setAttr('globalAlpha', absOpacity); } } _applyLineJoin(shape) { const lineJoin = shape.attrs.lineJoin; if (lineJoin) { this.setAttr('lineJoin', lineJoin); } } setAttr(attr, val) { this._context[attr] = val; } arc(x, y, radius, startAngle, endAngle, counterClockwise) { this._context.arc(x, y, radius, startAngle, endAngle, counterClockwise); } arcTo(x1, y1, x2, y2, radius) { this._context.arcTo(x1, y1, x2, y2, radius); } beginPath() { this._context.beginPath(); } bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y) { this._context.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y); } clearRect(x, y, width, height) { this._context.clearRect(x, y, width, height); } clip(...args) { this._context.clip.apply(this._context, args); } closePath() { this._context.closePath(); } createImageData(width, height) { var a = arguments; if (a.length === 2) { return this._context.createImageData(width, height); } else if (a.length === 1) { return this._context.createImageData(width); } } createLinearGradient(x0, y0, x1, y1) { return this._context.createLinearGradient(x0, y0, x1, y1); } createPattern(image, repetition) { return this._context.createPattern(image, repetition); } createRadialGradient(x0, y0, r0, x1, y1, r1) { return this._context.createRadialGradient(x0, y0, r0, x1, y1, r1); } drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight) { var a = arguments, _context = this._context; if (a.length === 3) { _context.drawImage(image, sx, sy); } else if (a.length === 5) { _context.drawImage(image, sx, sy, sWidth, sHeight); } else if (a.length === 9) { _context.drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight); } } ellipse(x, y, radiusX, radiusY, rotation, startAngle, endAngle, counterclockwise) { this._context.ellipse(x, y, radiusX, radiusY, rotation, startAngle, endAngle, counterclockwise); } isPointInPath(x, y, path, fillRule) { if (path) { return this._context.isPointInPath(path, x, y, fillRule); } return this._context.isPointInPath(x, y, fillRule); } fill(...args) { this._context.fill.apply(this._context, args); } fillRect(x, y, width, height) { this._context.fillRect(x, y, width, height); } strokeRect(x, y, width, height) { this._context.strokeRect(x, y, width, height); } fillText(text, x, y, maxWidth) { if (maxWidth) { this._context.fillText(text, x, y, maxWidth); } else { this._context.fillText(text, x, y); } } measureText(text) { return this._context.measureText(text); } getImageData(sx, sy, sw, sh) { return this._context.getImageData(sx, sy, sw, sh); } lineTo(x, y) { this._context.lineTo(x, y); } moveTo(x, y) { this._context.moveTo(x, y); } rect(x, y, width, height) { this._context.rect(x, y, width, height); } roundRect(x, y, width, height, radii) { this._context.roundRect(x, y, width, height, radii); } putImageData(imageData, dx, dy) { this._context.putImageData(imageData, dx, dy); } quadraticCurveTo(cpx, cpy, x, y) { this._context.quadraticCurveTo(cpx, cpy, x, y); } restore() { this._context.restore(); } rotate(angle) { this._context.rotate(angle); } save() { this._context.save(); } scale(x, y) { this._context.scale(x, y); } setLineDash(segments) { if (this._context.setLineDash) { this._context.setLineDash(segments); } else if ('mozDash' in this._context) { this._context['mozDash'] = segments; } else if ('webkitLineDash' in this._context) { this._context['webkitLineDash'] = segments; } } getLineDash() { return this._context.getLineDash(); } setTransform(a, b, c, d, e, f) { this._context.setTransform(a, b, c, d, e, f); } stroke(path2d) { if (path2d) { this._context.stroke(path2d); } else { this._context.stroke(); } } strokeText(text, x, y, maxWidth) { this._context.strokeText(text, x, y, maxWidth); } transform(a, b, c, d, e, f) { this._context.transform(a, b, c, d, e, f); } translate(x, y) { this._context.translate(x, y); } _enableTrace() { var that = this, len = CONTEXT_METHODS.length, origSetter = this.setAttr, n, args; var func = function (methodName) { var origMethod = that[methodName], ret; that[methodName] = function () { args = simplifyArray(Array.prototype.slice.call(arguments, 0)); ret = origMethod.apply(that, arguments); that._trace({ method: methodName, args: args, }); return ret; }; }; for (n = 0; n < len; n++) { func(CONTEXT_METHODS[n]); } that.setAttr = function () { origSetter.apply(that, arguments); var prop = arguments[0]; var val = arguments[1]; if (prop === 'shadowOffsetX' || prop === 'shadowOffsetY' || prop === 'shadowBlur') { val = val / this.canvas.getPixelRatio(); } that._trace({ property: prop, val: val, }); }; } _applyGlobalCompositeOperation(node) { const op = node.attrs.globalCompositeOperation; var def = !op || op === 'source-over'; if (!def) { this.setAttr('globalCompositeOperation', op); } } } exports.Context = Context; CONTEXT_PROPERTIES.forEach(function (prop) { Object.defineProperty(Context.prototype, prop, { get() { return this._context[prop]; }, set(val) { this._context[prop] = val; }, }); }); class SceneContext extends Context { constructor(canvas, { willReadFrequently = false } = {}) { super(canvas); this._context = canvas._canvas.getContext('2d', { willReadFrequently, }); } _fillColor(shape) { var fill = shape.fill(); this.setAttr('fillStyle', fill); shape._fillFunc(this); } _fillPattern(shape) { this.setAttr('fillStyle', shape._getFillPattern()); shape._fillFunc(this); } _fillLinearGradient(shape) { var grd = shape._getLinearGradient(); if (grd) { this.setAttr('fillStyle', grd); shape._fillFunc(this); } } _fillRadialGradient(shape) { const grd = shape._getRadialGradient(); if (grd) { this.setAttr('fillStyle', grd); shape._fillFunc(this); } } _fill(shape) { const hasColor = shape.fill(), fillPriority = shape.getFillPriority(); if (hasColor && fillPriority === 'color') { this._fillColor(shape); return; } const hasPattern = shape.getFillPatternImage(); if (hasPattern && fillPriority === 'pattern') { this._fillPattern(shape); return; } const hasLinearGradient = shape.getFillLinearGradientColorStops(); if (hasLinearGradient && fillPriority === 'linear-gradient') { this._fillLinearGradient(shape); return; } const hasRadialGradient = shape.getFillRadialGradientColorStops(); if (hasRadialGradient && fillPriority === 'radial-gradient') { this._fillRadialGradient(shape); return; } if (hasColor) { this._fillColor(shape); } else if (hasPattern) { this._fillPattern(shape); } else if (hasLinearGradient) { this._fillLinearGradient(shape); } else if (hasRadialGradient) { this._fillRadialGradient(shape); } } _strokeLinearGradient(shape) { const start = shape.getStrokeLinearGradientStartPoint(), end = shape.getStrokeLinearGradientEndPoint(), colorStops = shape.getStrokeLinearGradientColorStops(), grd = this.createLinearGradient(start.x, start.y, end.x, end.y); if (colorStops) { for (var n = 0; n < colorStops.length; n += 2) { grd.addColorStop(colorStops[n], colorStops[n + 1]); } this.setAttr('strokeStyle', grd); } } _stroke(shape) { var dash = shape.dash(), strokeScaleEnabled = shape.getStrokeScaleEnabled(); if (shape.hasStroke()) { if (!strokeScaleEnabled) { this.save(); var pixelRatio = this.getCanvas().getPixelRatio(); this.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0); } this._applyLineCap(shape); if (dash && shape.dashEnabled()) { this.setLineDash(dash); this.setAttr('lineDashOffset', shape.dashOffset()); } this.setAttr('lineWidth', shape.strokeWidth()); if (!shape.getShadowForStrokeEnabled()) { this.setAttr('shadowColor', 'rgba(0,0,0,0)'); } var hasLinearGradient = shape.getStrokeLinearGradientColorStops(); if (hasLinearGradient) { this._strokeLinearGradient(shape); } else { this.setAttr('strokeStyle', shape.stroke()); } shape._strokeFunc(this); if (!strokeScaleEnabled) { this.restore(); } } } _applyShadow(shape) { var _a, _b, _c; var color = (_a = shape.getShadowRGBA()) !== null && _a !== void 0 ? _a : 'black', blur = (_b = shape.getShadowBlur()) !== null && _b !== void 0 ? _b : 5, offset = (_c = shape.getShadowOffset()) !== null && _c !== void 0 ? _c : { x: 0, y: 0, }, scale = shape.getAbsoluteScale(), ratio = this.canvas.getPixelRatio(), scaleX = scale.x * ratio, scaleY = scale.y * ratio; this.setAttr('shadowColor', color); this.setAttr('shadowBlur', blur * Math.min(Math.abs(scaleX), Math.abs(scaleY))); this.setAttr('shadowOffsetX', offset.x * scaleX); this.setAttr('shadowOffsetY', offset.y * scaleY); } } exports.SceneContext = SceneContext; class HitContext extends Context { constructor(canvas) { super(canvas); this._context = canvas._canvas.getContext('2d', { willReadFrequently: true, }); } _fill(shape) { this.save(); this.setAttr('fillStyle', shape.colorKey); shape._fillFuncHit(this); this.restore(); } strokeShape(shape) { if (shape.hasHitStroke()) { this._stroke(shape); } } _stroke(shape) { if (shape.hasHitStroke()) { const strokeScaleEnabled = shape.getStrokeScaleEnabled(); if (!strokeScaleEnabled) { this.save(); var pixelRatio = this.getCanvas().getPixelRatio(); this.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0); } this._applyLineCap(shape); var hitStrokeWidth = shape.hitStrokeWidth(); var strokeWidth = hitStrokeWidth === 'auto' ? shape.strokeWidth() : hitStrokeWidth; this.setAttr('lineWidth', strokeWidth); this.setAttr('strokeStyle', shape.colorKey); shape._strokeFuncHit(this); if (!strokeScaleEnabled) { this.restore(); } } } } exports.HitContext = HitContext;