konva
Version:
<p align="center"> <img src="https://raw.githubusercontent.com/konvajs/konvajs.github.io/master/apple-touch-icon-180x180.png" alt="Konva logo" height="180" /> </p>
521 lines (520 loc) • 22.9 kB
JavaScript
"use strict";
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
var Util_1 = require("./Util");
var Factory_1 = require("./Factory");
var Node_1 = require("./Node");
var Validators_1 = require("./Validators");
var Global_1 = require("./Global");
var PointerEvents = require("./PointerEvents");
var HAS_SHADOW = 'hasShadow';
var SHADOW_RGBA = 'shadowRGBA';
var patternImage = 'patternImage';
var linearGradient = 'linearGradient';
var radialGradient = 'radialGradient';
var dummyContext;
function getDummyContext() {
if (dummyContext) {
return dummyContext;
}
dummyContext = Util_1.Util.createCanvasElement().getContext('2d');
return dummyContext;
}
exports.shapes = {};
function _fillFunc(context) {
context.fill();
}
function _strokeFunc(context) {
context.stroke();
}
function _fillFuncHit(context) {
context.fill();
}
function _strokeFuncHit(context) {
context.stroke();
}
function _clearHasShadowCache() {
this._clearCache(HAS_SHADOW);
}
function _clearGetShadowRGBACache() {
this._clearCache(SHADOW_RGBA);
}
function _clearFillPatternCache() {
this._clearCache(patternImage);
}
function _clearLinearGradientCache() {
this._clearCache(linearGradient);
}
function _clearRadialGradientCache() {
this._clearCache(radialGradient);
}
var Shape = (function (_super) {
__extends(Shape, _super);
function Shape(config) {
var _this = _super.call(this, config) || this;
var key;
while (true) {
key = Util_1.Util.getRandomColor();
if (key && !(key in exports.shapes)) {
break;
}
}
_this.colorKey = key;
exports.shapes[key] = _this;
_this.on('shadowColorChange.konva shadowBlurChange.konva shadowOffsetChange.konva shadowOpacityChange.konva shadowEnabledChange.konva', _clearHasShadowCache);
_this.on('shadowColorChange.konva shadowOpacityChange.konva shadowEnabledChange.konva', _clearGetShadowRGBACache);
_this.on('fillPriorityChange.konva fillPatternImageChange.konva fillPatternRepeatChange.konva', _clearFillPatternCache);
_this.on('fillPriorityChange.konva fillLinearGradientColorStopsChange.konva fillLinearGradientStartPointXChange.konva fillLinearGradientStartPointYChange.konva fillLinearGradientEndPointXChange.konva fillLinearGradientEndPointYChange.konva', _clearLinearGradientCache);
_this.on('fillPriorityChange.konva fillRadialGradientColorStopsChange.konva fillRadialGradientStartPointXChange.konva fillRadialGradientStartPointYChange.konva fillRadialGradientEndPointXChange.konva fillRadialGradientEndPointYChange.konva fillRadialGradientStartRadiusChange.konva fillRadialGradientEndRadiusChange.konva', _clearRadialGradientCache);
return _this;
}
Shape.prototype.getContext = function () {
return this.getLayer().getContext();
};
Shape.prototype.getCanvas = function () {
return this.getLayer().getCanvas();
};
Shape.prototype.getSceneFunc = function () {
return this.attrs.sceneFunc || this['_sceneFunc'];
};
Shape.prototype.getHitFunc = function () {
return this.attrs.hitFunc || this['_hitFunc'];
};
Shape.prototype.hasShadow = function () {
return this._getCache(HAS_SHADOW, this._hasShadow);
};
Shape.prototype._hasShadow = function () {
return (this.shadowEnabled() &&
(this.shadowOpacity() !== 0 &&
!!(this.shadowColor() ||
this.shadowBlur() ||
this.shadowOffsetX() ||
this.shadowOffsetY())));
};
Shape.prototype._getFillPattern = function () {
return this._getCache(patternImage, this.__getFillPattern);
};
Shape.prototype.__getFillPattern = function () {
if (this.fillPatternImage()) {
var ctx = getDummyContext();
return ctx.createPattern(this.fillPatternImage(), this.fillPatternRepeat() || 'repeat');
}
};
Shape.prototype._getLinearGradient = function () {
return this._getCache(linearGradient, this.__getLinearGradient);
};
Shape.prototype.__getLinearGradient = function () {
var colorStops = this.fillLinearGradientColorStops();
if (colorStops) {
var ctx = getDummyContext();
var start = this.fillLinearGradientStartPoint();
var end = this.fillLinearGradientEndPoint();
var grd = ctx.createLinearGradient(start.x, start.y, end.x, end.y);
for (var n = 0; n < colorStops.length; n += 2) {
grd.addColorStop(colorStops[n], colorStops[n + 1]);
}
return grd;
}
};
Shape.prototype._getRadialGradient = function () {
return this._getCache(radialGradient, this.__getRadialGradient);
};
Shape.prototype.__getRadialGradient = function () {
var colorStops = this.fillRadialGradientColorStops();
if (colorStops) {
var ctx = getDummyContext();
var start = this.fillRadialGradientStartPoint();
var end = this.fillRadialGradientEndPoint();
var grd = ctx.createRadialGradient(start.x, start.y, this.fillRadialGradientStartRadius(), end.x, end.y, this.fillRadialGradientEndRadius());
for (var n = 0; n < colorStops.length; n += 2) {
grd.addColorStop(colorStops[n], colorStops[n + 1]);
}
return grd;
}
};
Shape.prototype.getShadowRGBA = function () {
return this._getCache(SHADOW_RGBA, this._getShadowRGBA);
};
Shape.prototype._getShadowRGBA = function () {
if (this.hasShadow()) {
var rgba = Util_1.Util.colorToRGBA(this.shadowColor());
return ('rgba(' +
rgba.r +
',' +
rgba.g +
',' +
rgba.b +
',' +
rgba.a * (this.shadowOpacity() || 1) +
')');
}
};
Shape.prototype.hasFill = function () {
return !!(this.fill() ||
this.fillPatternImage() ||
this.fillLinearGradientColorStops() ||
this.fillRadialGradientColorStops());
};
Shape.prototype.hasStroke = function () {
return (this.strokeEnabled() &&
this.strokeWidth() &&
!!(this.stroke() || this.strokeLinearGradientColorStops()));
};
Shape.prototype.intersects = function (point) {
var stage = this.getStage(), bufferHitCanvas = stage.bufferHitCanvas, p;
bufferHitCanvas.getContext().clear();
this.drawHit(bufferHitCanvas);
p = bufferHitCanvas.context.getImageData(Math.round(point.x), Math.round(point.y), 1, 1).data;
return p[3] > 0;
};
Shape.prototype.destroy = function () {
Node_1.Node.prototype.destroy.call(this);
delete exports.shapes[this.colorKey];
delete this.colorKey;
return this;
};
Shape.prototype._useBufferCanvas = function (caching) {
return !!((!caching || this.hasShadow()) &&
this.perfectDrawEnabled() &&
this.getAbsoluteOpacity() !== 1 &&
this.hasFill() &&
this.hasStroke() &&
this.getStage());
};
Shape.prototype.setStrokeHitEnabled = function (val) {
if (val) {
this.hitStrokeWidth('auto');
}
else {
this.hitStrokeWidth(0);
}
};
Shape.prototype.getStrokeHitEnabled = function () {
if (this.hitStrokeWidth() === 0) {
return false;
}
else {
return true;
}
};
Shape.prototype.getSelfRect = function () {
var size = this.size();
return {
x: this._centroid ? Math.round(-size.width / 2) : 0,
y: this._centroid ? Math.round(-size.height / 2) : 0,
width: size.width,
height: size.height
};
};
Shape.prototype.getClientRect = function (attrs) {
attrs = attrs || {};
var skipTransform = attrs.skipTransform;
var relativeTo = attrs.relativeTo;
var fillRect = this.getSelfRect();
var applyStroke = !attrs.skipStroke && this.hasStroke();
var strokeWidth = (applyStroke && this.strokeWidth()) || 0;
var fillAndStrokeWidth = fillRect.width + strokeWidth;
var fillAndStrokeHeight = fillRect.height + strokeWidth;
var applyShadow = !attrs.skipShadow && this.hasShadow();
var shadowOffsetX = applyShadow ? this.shadowOffsetX() : 0;
var shadowOffsetY = applyShadow ? this.shadowOffsetY() : 0;
var preWidth = fillAndStrokeWidth + Math.abs(shadowOffsetX);
var preHeight = fillAndStrokeHeight + Math.abs(shadowOffsetY);
var blurRadius = (applyShadow && this.shadowBlur()) || 0;
var width = preWidth + blurRadius * 2;
var height = preHeight + blurRadius * 2;
var roundingOffset = 0;
if (Math.round(strokeWidth / 2) !== strokeWidth / 2) {
roundingOffset = 1;
}
var rect = {
width: width + roundingOffset,
height: height + roundingOffset,
x: -Math.round(strokeWidth / 2 + blurRadius) +
Math.min(shadowOffsetX, 0) +
fillRect.x,
y: -Math.round(strokeWidth / 2 + blurRadius) +
Math.min(shadowOffsetY, 0) +
fillRect.y
};
if (!skipTransform) {
return this._transformedRect(rect, relativeTo);
}
return rect;
};
Shape.prototype.drawScene = function (can, top, caching, skipBuffer) {
var layer = this.getLayer(), canvas = can || layer.getCanvas(), context = canvas.getContext(), cachedCanvas = this._getCanvasCache(), drawFunc = this.sceneFunc(), hasShadow = this.hasShadow(), hasStroke = this.hasStroke(), stage, bufferCanvas, bufferContext;
if (!this.isVisible() && !caching) {
return this;
}
if (cachedCanvas) {
context.save();
layer._applyTransform(this, context, top);
this._drawCachedSceneCanvas(context);
context.restore();
return this;
}
if (!drawFunc) {
return this;
}
context.save();
if (this._useBufferCanvas(caching) && !skipBuffer) {
stage = this.getStage();
bufferCanvas = stage.bufferCanvas;
bufferContext = bufferCanvas.getContext();
bufferContext.clear();
bufferContext.save();
bufferContext._applyLineJoin(this);
if (!caching) {
if (layer) {
layer._applyTransform(this, bufferContext, top);
}
else {
var m = this.getAbsoluteTransform(top).getMatrix();
context.transform(m[0], m[1], m[2], m[3], m[4], m[5]);
}
}
drawFunc.call(this, bufferContext, this);
bufferContext.restore();
var ratio = bufferCanvas.pixelRatio;
if (hasShadow && !canvas.hitCanvas) {
context.save();
context._applyShadow(this);
context._applyOpacity(this);
context._applyGlobalCompositeOperation(this);
context.drawImage(bufferCanvas._canvas, 0, 0, bufferCanvas.width / ratio, bufferCanvas.height / ratio);
context.restore();
}
else {
context._applyOpacity(this);
context._applyGlobalCompositeOperation(this);
context.drawImage(bufferCanvas._canvas, 0, 0, bufferCanvas.width / ratio, bufferCanvas.height / ratio);
}
}
else {
context._applyLineJoin(this);
if (!caching) {
if (layer) {
layer._applyTransform(this, context, top);
}
else {
var o = this.getAbsoluteTransform(top).getMatrix();
context.transform(o[0], o[1], o[2], o[3], o[4], o[5]);
}
}
if (hasShadow && hasStroke && !canvas.hitCanvas) {
context.save();
if (!caching) {
context._applyOpacity(this);
context._applyGlobalCompositeOperation(this);
}
context._applyShadow(this);
drawFunc.call(this, context, this);
context.restore();
if (this.hasFill() && this.shadowForStrokeEnabled()) {
drawFunc.call(this, context, this);
}
}
else if (hasShadow && !canvas.hitCanvas) {
context.save();
if (!caching) {
context._applyOpacity(this);
context._applyGlobalCompositeOperation(this);
}
context._applyShadow(this);
drawFunc.call(this, context, this);
context.restore();
}
else {
if (!caching) {
context._applyOpacity(this);
context._applyGlobalCompositeOperation(this);
}
drawFunc.call(this, context, this);
}
}
context.restore();
return this;
};
Shape.prototype.drawHit = function (can, top, caching) {
var layer = this.getLayer(), canvas = can || layer.hitCanvas, context = canvas && canvas.getContext(), drawFunc = this.hitFunc() || this.sceneFunc(), cachedCanvas = this._getCanvasCache(), cachedHitCanvas = cachedCanvas && cachedCanvas.hit;
if (!this.colorKey) {
Util_1.Util.warn('Looks like your canvas has a destroyed shape in it. Do not reuse shape after you destroyed it. See the shape in logs above. If you want to reuse shape you should call remove() instead of destroy()');
}
if (!this.shouldDrawHit() && !caching) {
return this;
}
if (cachedHitCanvas) {
context.save();
layer._applyTransform(this, context, top);
this._drawCachedHitCanvas(context);
context.restore();
return this;
}
if (!drawFunc) {
return this;
}
context.save();
context._applyLineJoin(this);
if (!caching) {
if (layer) {
layer._applyTransform(this, context, top);
}
else {
var o = this.getAbsoluteTransform(top).getMatrix();
context.transform(o[0], o[1], o[2], o[3], o[4], o[5]);
}
}
drawFunc.call(this, context, this);
context.restore();
return this;
};
Shape.prototype.drawHitFromCache = function (alphaThreshold) {
if (alphaThreshold === void 0) { alphaThreshold = 0; }
var cachedCanvas = this._getCanvasCache(), sceneCanvas = this._getCachedSceneCanvas(), hitCanvas = cachedCanvas.hit, hitContext = hitCanvas.getContext(), hitWidth = hitCanvas.getWidth(), hitHeight = hitCanvas.getHeight(), hitImageData, hitData, len, rgbColorKey, i, alpha;
hitContext.clear();
hitContext.drawImage(sceneCanvas._canvas, 0, 0, hitWidth, hitHeight);
try {
hitImageData = hitContext.getImageData(0, 0, hitWidth, hitHeight);
hitData = hitImageData.data;
len = hitData.length;
rgbColorKey = Util_1.Util._hexToRgb(this.colorKey);
for (i = 0; i < len; i += 4) {
alpha = hitData[i + 3];
if (alpha > alphaThreshold) {
hitData[i] = rgbColorKey.r;
hitData[i + 1] = rgbColorKey.g;
hitData[i + 2] = rgbColorKey.b;
hitData[i + 3] = 255;
}
else {
hitData[i + 3] = 0;
}
}
hitContext.putImageData(hitImageData, 0, 0);
}
catch (e) {
Util_1.Util.error('Unable to draw hit graph from cached scene canvas. ' + e.message);
}
return this;
};
Shape.prototype.hasPointerCapture = function (pointerId) {
return PointerEvents.hasPointerCapture(pointerId, this);
};
Shape.prototype.setPointerCapture = function (pointerId) {
PointerEvents.setPointerCapture(pointerId, this);
};
Shape.prototype.releaseCapture = function (pointerId) {
PointerEvents.releaseCapture(pointerId, this);
};
return Shape;
}(Node_1.Node));
exports.Shape = Shape;
Shape.prototype._fillFunc = _fillFunc;
Shape.prototype._strokeFunc = _strokeFunc;
Shape.prototype._fillFuncHit = _fillFuncHit;
Shape.prototype._strokeFuncHit = _strokeFuncHit;
Shape.prototype._centroid = false;
Shape.prototype.nodeType = 'Shape';
Global_1._registerNode(Shape);
Factory_1.Factory.addGetterSetter(Shape, 'stroke', undefined, Validators_1.getStringValidator());
Factory_1.Factory.addGetterSetter(Shape, 'strokeWidth', 2, Validators_1.getNumberValidator());
Factory_1.Factory.addGetterSetter(Shape, 'hitStrokeWidth', 'auto', Validators_1.getNumberOrAutoValidator());
Factory_1.Factory.addGetterSetter(Shape, 'strokeHitEnabled', true, Validators_1.getBooleanValidator());
Factory_1.Factory.addGetterSetter(Shape, 'perfectDrawEnabled', true, Validators_1.getBooleanValidator());
Factory_1.Factory.addGetterSetter(Shape, 'shadowForStrokeEnabled', true, Validators_1.getBooleanValidator());
Factory_1.Factory.addGetterSetter(Shape, 'lineJoin');
Factory_1.Factory.addGetterSetter(Shape, 'lineCap');
Factory_1.Factory.addGetterSetter(Shape, 'sceneFunc');
Factory_1.Factory.addGetterSetter(Shape, 'hitFunc');
Factory_1.Factory.addGetterSetter(Shape, 'dash');
Factory_1.Factory.addGetterSetter(Shape, 'dashOffset', 0, Validators_1.getNumberValidator());
Factory_1.Factory.addGetterSetter(Shape, 'shadowColor', undefined, Validators_1.getStringValidator());
Factory_1.Factory.addGetterSetter(Shape, 'shadowBlur', 0, Validators_1.getNumberValidator());
Factory_1.Factory.addGetterSetter(Shape, 'shadowOpacity', 1, Validators_1.getNumberValidator());
Factory_1.Factory.addComponentsGetterSetter(Shape, 'shadowOffset', ['x', 'y']);
Factory_1.Factory.addGetterSetter(Shape, 'shadowOffsetX', 0, Validators_1.getNumberValidator());
Factory_1.Factory.addGetterSetter(Shape, 'shadowOffsetY', 0, Validators_1.getNumberValidator());
Factory_1.Factory.addGetterSetter(Shape, 'fillPatternImage');
Factory_1.Factory.addGetterSetter(Shape, 'fill', undefined, Validators_1.getStringValidator());
Factory_1.Factory.addGetterSetter(Shape, 'fillPatternX', 0, Validators_1.getNumberValidator());
Factory_1.Factory.addGetterSetter(Shape, 'fillPatternY', 0, Validators_1.getNumberValidator());
Factory_1.Factory.addGetterSetter(Shape, 'fillLinearGradientColorStops');
Factory_1.Factory.addGetterSetter(Shape, 'strokeLinearGradientColorStops');
Factory_1.Factory.addGetterSetter(Shape, 'fillRadialGradientStartRadius', 0);
Factory_1.Factory.addGetterSetter(Shape, 'fillRadialGradientEndRadius', 0);
Factory_1.Factory.addGetterSetter(Shape, 'fillRadialGradientColorStops');
Factory_1.Factory.addGetterSetter(Shape, 'fillPatternRepeat', 'repeat');
Factory_1.Factory.addGetterSetter(Shape, 'fillEnabled', true);
Factory_1.Factory.addGetterSetter(Shape, 'strokeEnabled', true);
Factory_1.Factory.addGetterSetter(Shape, 'shadowEnabled', true);
Factory_1.Factory.addGetterSetter(Shape, 'dashEnabled', true);
Factory_1.Factory.addGetterSetter(Shape, 'strokeScaleEnabled', true);
Factory_1.Factory.addGetterSetter(Shape, 'fillPriority', 'color');
Factory_1.Factory.addComponentsGetterSetter(Shape, 'fillPatternOffset', ['x', 'y']);
Factory_1.Factory.addGetterSetter(Shape, 'fillPatternOffsetX', 0, Validators_1.getNumberValidator());
Factory_1.Factory.addGetterSetter(Shape, 'fillPatternOffsetY', 0, Validators_1.getNumberValidator());
Factory_1.Factory.addComponentsGetterSetter(Shape, 'fillPatternScale', ['x', 'y']);
Factory_1.Factory.addGetterSetter(Shape, 'fillPatternScaleX', 1, Validators_1.getNumberValidator());
Factory_1.Factory.addGetterSetter(Shape, 'fillPatternScaleY', 1, Validators_1.getNumberValidator());
Factory_1.Factory.addComponentsGetterSetter(Shape, 'fillLinearGradientStartPoint', [
'x',
'y'
]);
Factory_1.Factory.addComponentsGetterSetter(Shape, 'strokeLinearGradientStartPoint', [
'x',
'y'
]);
Factory_1.Factory.addGetterSetter(Shape, 'fillLinearGradientStartPointX', 0);
Factory_1.Factory.addGetterSetter(Shape, 'strokeLinearGradientStartPointX', 0);
Factory_1.Factory.addGetterSetter(Shape, 'fillLinearGradientStartPointY', 0);
Factory_1.Factory.addGetterSetter(Shape, 'strokeLinearGradientStartPointY', 0);
Factory_1.Factory.addComponentsGetterSetter(Shape, 'fillLinearGradientEndPoint', [
'x',
'y'
]);
Factory_1.Factory.addComponentsGetterSetter(Shape, 'strokeLinearGradientEndPoint', [
'x',
'y'
]);
Factory_1.Factory.addGetterSetter(Shape, 'fillLinearGradientEndPointX', 0);
Factory_1.Factory.addGetterSetter(Shape, 'strokeLinearGradientEndPointX', 0);
Factory_1.Factory.addGetterSetter(Shape, 'fillLinearGradientEndPointY', 0);
Factory_1.Factory.addGetterSetter(Shape, 'strokeLinearGradientEndPointY', 0);
Factory_1.Factory.addComponentsGetterSetter(Shape, 'fillRadialGradientStartPoint', [
'x',
'y'
]);
Factory_1.Factory.addGetterSetter(Shape, 'fillRadialGradientStartPointX', 0);
Factory_1.Factory.addGetterSetter(Shape, 'fillRadialGradientStartPointY', 0);
Factory_1.Factory.addComponentsGetterSetter(Shape, 'fillRadialGradientEndPoint', [
'x',
'y'
]);
Factory_1.Factory.addGetterSetter(Shape, 'fillRadialGradientEndPointX', 0);
Factory_1.Factory.addGetterSetter(Shape, 'fillRadialGradientEndPointY', 0);
Factory_1.Factory.addGetterSetter(Shape, 'fillPatternRotation', 0);
Factory_1.Factory.backCompat(Shape, {
dashArray: 'dash',
getDashArray: 'getDash',
setDashArray: 'getDash',
drawFunc: 'sceneFunc',
getDrawFunc: 'getSceneFunc',
setDrawFunc: 'setSceneFunc',
drawHitFunc: 'hitFunc',
getDrawHitFunc: 'getHitFunc',
setDrawHitFunc: 'setHitFunc'
});
Util_1.Collection.mapMethods(Shape);