konva/src/Shape.js

596 lines
18 KiB
JavaScript
Raw Normal View History

(function() {
/**
* Shape constructor. Shapes are primitive objects such as rectangles,
* circles, text, lines, etc.
* @constructor
* @augments Kinetic.Node
* @param {Object} config
*
* @param {String} [config.fill] fill color
*
* @param {Image} [config.fillPatternImage] fill pattern image
* @param {Number} [config.fillPatternX]
* @param {Number} [config.fillPatternY]
* @param {Array|Object} [config.fillPatternOffset] array with two elements or object with x and y component
* @param {Array|Object} [config.fillPatternScale] array with two elements or object with x and y component
* @param {Number} [config.fillPatternRotation]
* @param {String} [config.fillPatternRepeat] can be 'repeat', 'repeat-x', 'repeat-y', or 'no-repeat'. The default is 'no-repeat'
*
* @param {Array|Object} [config.fillLinearGradientStartPoint] array with two elements or object with x and y component
* @param {Array|Object} [config.fillLinearGradientEndPoint] array with two elements or object with x and y component
* @param {Array} [config.fillLinearGradientColorStops] array of color stops
*
* @param {Array|Object} [config.fillRadialGradientStartPoint] array with two elements or object with x and y component
* @param {Array|Object} [config.fillRadialGradientEndPoint] array with two elements or object with x and y component
* @param {Number} [config.fillRadialGradientStartRadius]
* @param {Number} [config.fillRadialGradientEndRadius]
* @param {Array} [config.fillRadialGradientColorStops] array of color stops
*
* @param {String} [config.stroke] stroke color
* @param {Number} [config.strokeWidth] stroke width
2013-01-03 14:43:12 +08:00
* @param {String} [config.lineJoin] can be miter, round, or bevel. The default
* is miter
2013-01-03 14:43:12 +08:00
* @param {String} [config.lineCap] can be butt, round, or sqare. The default
* is butt
* @param {String} [config.shadowColor]
* @param {Number} [config.shadowBlur]
* @param {Obect} [config.shadowOffset]
* @param {Number} [config.shadowOffset.x]
* @param {Number} [config.shadowOffset.y]
* @param {Number} [config.shadowOpacity] shadow opacity. Can be any real number
* between 0 and 1
* @param {Array} [config.dashArray]
*
*
*
* @param {Number} [config.x]
* @param {Number} [config.y]
* @param {Number} [config.width]
* @param {Number} [config.height]
* @param {Boolean} [config.visible]
* @param {Boolean} [config.listening] whether or not the node is listening for events
* @param {String} [config.id] unique id
* @param {String} [config.name] non-unique name
* @param {Number} [config.opacity] determines node opacity. Can be any number between 0 and 1
* @param {Object} [config.scale]
* @param {Number} [config.scale.x]
* @param {Number} [config.scale.y]
* @param {Number} [config.rotation] rotation in radians
* @param {Number} [config.rotationDeg] rotation in degrees
* @param {Object} [config.offset] offset from center point and rotation point
* @param {Number} [config.offset.x]
* @param {Number} [config.offset.y]
* @param {Boolean} [config.draggable]
* @param {Function} [config.dragBoundFunc]
2012-04-29 12:12:01 +08:00
*/
Kinetic.Shape = function(config) {
this._initShape(config);
};
2012-04-29 12:12:01 +08:00
Kinetic.Shape.prototype = {
_initShape: function(config) {
this.setDefaultAttrs({
fillEnabled: true,
strokeEnabled: true,
shadowEnabled: true,
dashArrayEnabled: true
});
this.nodeType = 'Shape';
// set colorKey
var shapes = Kinetic.Global.shapes;
var key;
while(true) {
key = Kinetic.Type._getRandomColorKey();
if(key && !( key in shapes)) {
break;
}
}
this.colorKey = key;
shapes[key] = this;
// call super constructor
Kinetic.Node.call(this, config);
},
/**
* get canvas context tied to the layer
* @name getContext
* @methodOf Kinetic.Shape.prototype
*/
getContext: function() {
return this.getLayer().getContext();
},
/**
2012-12-17 04:56:30 +08:00
* get canvas renderer tied to the layer. Note that this returns a canvas renderer, not a canvas element
* @name getCanvas
* @methodOf Kinetic.Shape.prototype
*/
getCanvas: function() {
return this.getLayer().getCanvas();
},
/**
* returns whether or not a shadow will be rendered
* @name hasShadow
* @methodOf Kinetic.Shape.prototype
*/
hasShadow: function() {
return !!(this.getShadowColor() || this.getShadowBlur() || this.getShadowOffset());
},
/**
* returns whether or not a fill will be rendered
* @name hasFill
* @methodOf Kinetic.Shape.prototype
*/
hasFill: function() {
return !!(this.getFill() || this.getFillPatternImage() || this.getFillLinearGradientStartPoint() || this.getFillRadialGradientStartPoint());
},
_get: function(selector) {
return this.nodeType === selector || this.shapeType === selector ? [this] : [];
},
/**
* determines if point is in the shape
2012-12-17 04:56:30 +08:00
* @name intersects
* @methodOf Kinetic.Shape.prototype
* @param {Object} point point can be an object containing
* an x and y property, or it can be an array with two elements
* in which the first element is the x component and the second
* element is the y component
*/
intersects: function() {
var pos = Kinetic.Type._getXY(Array.prototype.slice.call(arguments));
var stage = this.getStage();
var hitCanvas = stage.hitCanvas;
hitCanvas.clear();
this.drawScene(hitCanvas);
var p = hitCanvas.context.getImageData(Math.round(pos.x), Math.round(pos.y), 1, 1).data;
return p[3] > 0;
},
enableFill: function() {
this.setAttr('fillEnabled', true);
},
disableFill: function() {
this.setAttr('fillEnabled', false);
},
enableStroke: function() {
this.setAttr('strokeEnabled', true);
},
disableStroke: function() {
this.setAttr('strokeEnabled', false);
},
enableShadow: function() {
this.setAttr('shadowEnabled', true);
},
disableShadow: function() {
this.setAttr('shadowEnabled', false);
},
enableDashArray: function() {
this.setAttr('dashArrayEnabled', true);
},
disableDashArray: function() {
this.setAttr('dashArrayEnabled', false);
},
remove: function() {
Kinetic.Node.prototype.remove.call(this);
delete Kinetic.Global.shapes[this.colorKey];
},
drawScene: function(canvas) {
var attrs = this.attrs, drawFunc = attrs.drawFunc, canvas = canvas || this.getLayer().getCanvas(), context = canvas.getContext();
if(drawFunc && this.isVisible()) {
context.save();
canvas._handlePixelRatio();
canvas._applyOpacity(this);
canvas._applyLineJoin(this);
canvas._applyAncestorTransforms(this);
drawFunc.call(this, canvas);
context.restore();
}
},
drawHit: function() {
var attrs = this.attrs, drawFunc = attrs.drawHitFunc || attrs.drawFunc, canvas = this.getLayer().hitCanvas, context = canvas.getContext();
if(drawFunc && this.isVisible() && this.isListening()) {
context.save();
canvas._applyLineJoin(this);
canvas._applyAncestorTransforms(this);
drawFunc.call(this, canvas);
context.restore();
}
},
_setDrawFuncs: function() {
if(!this.attrs.drawFunc && this.drawFunc) {
this.setDrawFunc(this.drawFunc);
}
if(!this.attrs.drawHitFunc && this.drawHitFunc) {
this.setDrawHitFunc(this.drawHitFunc);
}
}
};
Kinetic.Global.extend(Kinetic.Shape, Kinetic.Node);
// add getters and setters
Kinetic.Node.addGettersSetters(Kinetic.Shape, ['stroke', 'lineJoin', 'lineCap', 'strokeWidth', 'drawFunc', 'drawHitFunc', 'dashArray', 'shadowColor', 'shadowBlur', 'shadowOpacity', 'fillPatternImage', 'fill', 'fillPatternX', 'fillPatternY', 'fillLinearGradientColorStops', 'fillRadialGradientStartRadius', 'fillRadialGradientEndRadius', 'fillRadialGradientColorStops', 'fillPatternRepeat', 'fillEnabled', 'strokeEnabled', 'shadowEnabled', 'dashArrayEnabled']);
/**
* set stroke color
* @name setStroke
* @methodOf Kinetic.Shape.prototype
* @param {String} stroke
*/
/**
* set line join
* @name setLineJoin
* @methodOf Kinetic.Shape.prototype
* @param {String} lineJoin. Can be miter, round, or bevel. The
* default is miter
*/
2013-01-03 13:35:51 +08:00
/**
* set line cap. Can be butt, round, or square
* @name setLineCap
* @methodOf Kinetic.Shape.prototype
* @param {String} lineCap
*/
/**
* set stroke width
* @name setStrokeWidth
* @methodOf Kinetic.Shape.prototype
* @param {Number} strokeWidth
*/
/**
* set draw function
* @name setDrawFunc
* @methodOf Kinetic.Shape.prototype
* @param {Function} drawFunc drawing function
*/
/**
* set draw hit function used for hit detection
* @name setDrawHitFunc
* @methodOf Kinetic.Shape.prototype
* @param {Function} drawHitFunc drawing function used for hit detection
*/
/**
* set dash array.
* @name setDashArray
2013-01-07 01:04:10 +08:00
* @methodOf Kinetic.Shape.prototype
* @param {Array} dashArray
* examples:<br>
* [10, 5] dashes are 10px long and 5 pixels apart
2012-12-17 04:56:30 +08:00
* [10, 20, 0.001, 20] if using a round lineCap, the line will
* be made up of alternating dashed lines that are 10px long
2012-12-17 04:56:30 +08:00
* and 20px apart, and dots that have a radius of 5px and are 20px
* apart
*/
/**
* set shadow color
* @name setShadowColor
* @methodOf Kinetic.Shape.prototype
* @param {String} color
*/
/**
* set shadow blur
* @name setShadowBlur
* @methodOf Kinetic.Shape.prototype
* @param {Number} blur
*/
/**
* set shadow opacity
* @name setShadowOpacity
* @methodOf Kinetic.Shape.prototype
* @param {Number} opacity must be a value between 0 and 1
*/
/**
2013-01-03 13:35:51 +08:00
* set fill pattern image
* @name setFillPatternImage
* @methodOf Kinetic.Shape.prototype
2013-01-03 13:35:51 +08:00
* @param {Image} image object
*/
/**
* set fill color
* @name setFill
* @methodOf Kinetic.Shape.prototype
* @param {String} color
*/
/**
* set fill pattern x
* @name setFillPatternX
* @methodOf Kinetic.Shape.prototype
* @param {Number} x
*/
/**
* set fill pattern y
* @name setFillPatternY
* @methodOf Kinetic.Shape.prototype
* @param {Number} y
*/
/**
* set fill linear gradient color stops
* @name setFillLinearGradientColorStops
* @methodOf Kinetic.Shape.prototype
* @param {Array} colorStops
*/
/**
* set fill radial gradient start radius
* @name setFillRadialGradientStartRadius
* @methodOf Kinetic.Shape.prototype
* @param {Number} radius
*/
/**
* set fill radial gradient end radius
* @name setFillRadialGradientEndRadius
* @methodOf Kinetic.Shape.prototype
* @param {Number} radius
*/
/**
* set fill radial gradient color stops
* @name setFillRadialGradientColorStops
* @methodOf Kinetic.Shape.prototype
* @param {Number} colorStops
*/
/**
* set fill pattern repeat
* @name setFillPatternRepeat
* @methodOf Kinetic.Shape.prototype
* @param {Number} repeat can be 'repeat', 'repeat-x', 'repeat-y', or 'no-repeat'. The default is 'no-repeat'
*/
/**
* get stroke color
* @name getStroke
* @methodOf Kinetic.Shape.prototype
*/
/**
* get line join
* @name getLineJoin
* @methodOf Kinetic.Shape.prototype
*/
2013-01-03 13:35:51 +08:00
/**
* get line cap
* @name getLineCap
* @methodOf Kinetic.Shape.prototype
*/
/**
* get stroke width
* @name getStrokeWidth
* @methodOf Kinetic.Shape.prototype
*/
/**
* get draw function
* @name getDrawFunc
* @methodOf Kinetic.Shape.prototype
*/
/**
* get draw hit function
* @name getDrawHitFunc
* @methodOf Kinetic.Shape.prototype
*/
2013-01-03 13:35:51 +08:00
/**
* get dash array
* @name getDashArray
2013-01-07 01:04:10 +08:00
* @methodOf Kinetic.Shape.prototype
2013-01-03 13:35:51 +08:00
*/
/**
* get shadow color
* @name getShadowColor
* @methodOf Kinetic.Shape.prototype
*/
/**
* get shadow blur
* @name getShadowBlur
* @methodOf Kinetic.Shape.prototype
*/
/**
* get shadow opacity
* @name getShadowOpacity
* @methodOf Kinetic.Shape.prototype
*/
2013-01-03 13:35:51 +08:00
/**
* get fill pattern image
* @name getFillPatternImage
* @methodOf Kinetic.Shape.prototype
*/
/**
* get fill color
* @name getFill
* @methodOf Kinetic.Shape.prototype
*/
/**
* get fill pattern x
* @name getFillPatternX
* @methodOf Kinetic.Shape.prototype
*/
/**
* get fill pattern y
* @name getFillPatternY
* @methodOf Kinetic.Shape.prototype
*/
/**
* get fill linear gradient color stops
* @name getFillLinearGradientColorStops
* @methodOf Kinetic.Shape.prototype
* @param {Array} colorStops
*/
/**
* get fill radial gradient start radius
* @name getFillRadialGradientStartRadius
* @methodOf Kinetic.Shape.prototype
*/
/**
* get fill radial gradient end radius
* @name getFillRadialGradientEndRadius
* @methodOf Kinetic.Shape.prototype
*/
/**
* get fill radial gradient color stops
* @name getFillRadialGradientColorStops
* @methodOf Kinetic.Shape.prototype
*/
/**
* get fill pattern repeat
* @name getFillPatternRepeat
* @methodOf Kinetic.Shape.prototype
*/
Kinetic.Node.addPointGettersSetters(Kinetic.Shape, ['fillPatternOffset', 'fillPatternScale', 'fillLinearGradientStartPoint', 'fillLinearGradientEndPoint', 'fillRadialGradientStartPoint', 'fillRadialGradientEndPoint', 'shadowOffset']);
/**
* set fill pattern offset
* @name setFillPatternOffset
* @methodOf Kinetic.Shape.prototype
* @param {Number|Array|Object} offset
*/
/**
* set fill pattern scale
* @name setFillPatternScale
* @methodOf Kinetic.Shape.prototype
* @param {Number|Array|Object} scale
*/
/**
* set fill linear gradient start point
* @name setFillLinearGradientStartPoint
* @methodOf Kinetic.Shape.prototype
* @param {Number|Array|Object} startPoint
*/
/**
* set fill linear gradient end point
* @name setFillLinearGradientEndPoint
* @methodOf Kinetic.Shape.prototype
* @param {Number|Array|Object} endPoint
*/
/**
* set fill radial gradient start point
* @name setFillRadialGradientStartPoint
* @methodOf Kinetic.Shape.prototype
* @param {Number|Array|Object} startPoint
*/
/**
* set fill radial gradient end point
* @name setFillRadialGradientEndPoint
* @methodOf Kinetic.Shape.prototype
* @param {Number|Array|Object} endPoint
*/
/**
* set shadow offset
* @name setShadowOffset
* @methodOf Kinetic.Shape.prototype
* @param {Number|Array|Object} offset
*/
/**
* get fill pattern offset
* @name getFillPatternOffset
* @methodOf Kinetic.Shape.prototype
*/
/**
* get fill pattern scale
* @name getFillPatternScale
* @methodOf Kinetic.Shape.prototype
*/
/**
* get fill linear gradient start point
* @name getFillLinearGradientStartPoint
* @methodOf Kinetic.Shape.prototype
*/
/**
* get fill linear gradient end point
* @name getFillLinearGradientEndPoint
* @methodOf Kinetic.Shape.prototype
*/
/**
* get fill radial gradient start point
* @name getFillRadialGradientStartPoint
* @methodOf Kinetic.Shape.prototype
*/
/**
* get fill radial gradient end point
* @name getFillRadialGradientEndPoint
* @methodOf Kinetic.Shape.prototype
*/
/**
* get shadow offset
* @name getShadowOffset
* @methodOf Kinetic.Shape.prototype
*/
2013-01-03 13:35:51 +08:00
Kinetic.Node.addRotationGettersSetters(Kinetic.Shape, ['fillPatternRotation']);
/**
2013-01-03 13:35:51 +08:00
* set fill pattern rotation in radians
* @name setFillPatternRotation
* @methodOf Kinetic.Shape.prototype
2013-01-03 13:35:51 +08:00
* @param {Number} rotation
*/
/**
2013-01-03 13:35:51 +08:00
* set fill pattern rotation in degrees
* @name setFillPatternRotationDeg
* @methodOf Kinetic.Shape.prototype
2013-01-03 13:35:51 +08:00
* @param {Number} rotationDeg
*/
/**
2013-01-03 13:35:51 +08:00
* get fill pattern rotation in radians
* @name getFillPatternRotation
* @methodOf Kinetic.Shape.prototype
*/
2013-01-03 13:35:51 +08:00
/**
* get fill pattern rotation in degrees
* @name getFillPatternRotationDeg
* @methodOf Kinetic.Shape.prototype
*/
})();