2013-04-19 20:25:50 -04:00
|
|
|
/*
|
|
|
|
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
|
|
|
* http://paperjs.org/
|
|
|
|
*
|
|
|
|
* Copyright (c) 2011 - 2013, Juerg Lehni & Jonathan Puckey
|
|
|
|
* http://lehni.org/ & http://jonathanpuckey.com/
|
|
|
|
*
|
|
|
|
* Distributed under the MIT license. See LICENSE file for details.
|
|
|
|
*
|
|
|
|
* All rights reserved.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @name Shape
|
|
|
|
*
|
|
|
|
* @class
|
|
|
|
*
|
|
|
|
* @extends Item
|
|
|
|
*/
|
2013-05-27 15:48:58 -04:00
|
|
|
var Shape = Item.extend(/** @lends Shape# */{
|
2013-06-23 23:18:32 -04:00
|
|
|
_class: 'Shape',
|
2013-06-18 18:50:11 -04:00
|
|
|
_transformContent: false,
|
2013-04-19 20:25:50 -04:00
|
|
|
|
2013-05-27 15:48:58 -04:00
|
|
|
initialize: function Shape(type, point, size) {
|
2013-05-27 12:11:50 -04:00
|
|
|
Item.call(this, point);
|
2013-04-19 20:25:50 -04:00
|
|
|
this._type = type;
|
|
|
|
this._size = size;
|
|
|
|
},
|
|
|
|
|
|
|
|
_draw: function(ctx, param) {
|
|
|
|
var style = this._style,
|
|
|
|
size = this._size,
|
|
|
|
width = size.width,
|
|
|
|
height = size.height,
|
2013-04-19 22:31:29 -04:00
|
|
|
fillColor = style.getFillColor(),
|
|
|
|
strokeColor = style.getStrokeColor();
|
2013-04-19 20:25:50 -04:00
|
|
|
if (fillColor || strokeColor || param.clip) {
|
|
|
|
ctx.beginPath();
|
|
|
|
switch (this._type) {
|
|
|
|
case 'rect':
|
|
|
|
ctx.rect(-width / 2, -height / 2, width, height);
|
|
|
|
break;
|
|
|
|
case 'circle':
|
2013-04-20 23:53:40 -04:00
|
|
|
// Average half of width & height for radius...
|
|
|
|
ctx.arc(0, 0, (width + height) / 4, 0, Math.PI * 2, true);
|
2013-04-19 20:25:50 -04:00
|
|
|
break;
|
|
|
|
case 'ellipse':
|
2013-06-12 23:13:39 -04:00
|
|
|
// Use four bezier curves and KAPPA value to aproximate ellipse
|
2013-04-19 21:57:31 -04:00
|
|
|
var mx = width / 2,
|
|
|
|
my = height / 2,
|
|
|
|
kappa = Numerical.KAPPA,
|
|
|
|
cx = mx * kappa,
|
|
|
|
cy = my * kappa;
|
2013-06-13 13:30:54 -04:00
|
|
|
ctx.moveTo(-mx, 0);
|
|
|
|
ctx.bezierCurveTo(-mx, -cy, -cx, -my, 0, -my);
|
|
|
|
ctx.bezierCurveTo(cx, -my, mx, -cy, mx, 0);
|
|
|
|
ctx.bezierCurveTo(mx, cy, cx, my, 0, my);
|
|
|
|
ctx.bezierCurveTo(-cx, my, -mx, cy, -mx, 0);
|
2013-04-19 20:25:50 -04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!param.clip && (fillColor || strokeColor)) {
|
|
|
|
this._setStyles(ctx);
|
|
|
|
if (fillColor)
|
|
|
|
ctx.fill();
|
|
|
|
if (strokeColor)
|
|
|
|
ctx.stroke();
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2013-06-19 11:22:08 -04:00
|
|
|
_canComposite: function() {
|
|
|
|
// A path with only a fill or a stroke can be directly blended, but if
|
|
|
|
// it has both, it needs to be drawn into a separate canvas first.
|
|
|
|
return !(this.hasFill() && this.hasStroke());
|
|
|
|
},
|
|
|
|
|
2013-06-13 13:31:21 -04:00
|
|
|
_getBounds: function(getter, matrix) {
|
|
|
|
var rect = new Rectangle(this._size).setCenter(0, 0);
|
2013-06-13 13:40:54 -04:00
|
|
|
if (getter !== 'getBounds' && this.hasStroke())
|
2013-06-13 13:31:21 -04:00
|
|
|
rect = rect.expand(this.getStrokeWidth());
|
|
|
|
return matrix ? matrix._transformBounds(rect) : rect;
|
|
|
|
},
|
|
|
|
|
2013-05-27 13:04:05 -04:00
|
|
|
_contains: function _contains(point) {
|
2013-04-20 23:54:06 -04:00
|
|
|
switch (this._type) {
|
|
|
|
case 'rect':
|
2013-05-27 13:04:05 -04:00
|
|
|
return _contains.base.call(this, point);
|
2013-04-20 23:54:06 -04:00
|
|
|
case 'circle':
|
|
|
|
case 'ellipse':
|
|
|
|
return point.divide(this._size).getLength() <= 0.5;
|
|
|
|
}
|
2013-04-20 23:41:52 -04:00
|
|
|
},
|
|
|
|
|
2013-06-24 13:15:54 -04:00
|
|
|
_hitTest: function _hitTest(point) {
|
2013-06-13 13:31:21 -04:00
|
|
|
if (this.hasStroke()) {
|
|
|
|
var type = this._type,
|
|
|
|
strokeWidth = this.getStrokeWidth();
|
|
|
|
switch (type) {
|
|
|
|
case 'rect':
|
2013-06-13 13:40:54 -04:00
|
|
|
var rect = new Rectangle(this._size).setCenter(0, 0),
|
|
|
|
outer = rect.expand(strokeWidth),
|
|
|
|
inner = rect.expand(-strokeWidth);
|
|
|
|
if (outer._containsPoint(point) && !inner._containsPoint(point))
|
|
|
|
return new HitResult('stroke', this);
|
2013-06-13 13:31:21 -04:00
|
|
|
break;
|
|
|
|
case 'circle':
|
|
|
|
case 'ellipse':
|
|
|
|
var size = this._size,
|
|
|
|
width = size.width,
|
|
|
|
height = size.height,
|
|
|
|
radius;
|
|
|
|
if (type === 'ellipse') {
|
|
|
|
// Calculate ellipse radius at angle
|
|
|
|
var angle = point.getAngleInRadians(),
|
|
|
|
x = width * Math.sin(angle),
|
|
|
|
y = height * Math.cos(angle);
|
|
|
|
radius = width * height / (2 * Math.sqrt(x * x + y * y));
|
|
|
|
} else {
|
|
|
|
// Average half of width & height for radius...
|
|
|
|
radius = (width + height) / 4;
|
|
|
|
}
|
|
|
|
if (2 * Math.abs(point.getLength() - radius) <= strokeWidth)
|
|
|
|
return new HitResult('stroke', this);
|
2013-06-13 13:40:54 -04:00
|
|
|
break;
|
2013-06-13 13:31:21 -04:00
|
|
|
}
|
|
|
|
}
|
2013-06-12 22:30:23 -04:00
|
|
|
return _hitTest.base.apply(this, arguments);
|
2013-04-20 23:24:16 -04:00
|
|
|
},
|
|
|
|
|
2013-06-12 23:13:39 -04:00
|
|
|
statics: new function() {
|
|
|
|
function createShape(type, point, size, args) {
|
|
|
|
var shape = new Shape(type, point, size),
|
|
|
|
named = Base.getNamed(args);
|
|
|
|
if (named)
|
|
|
|
shape._set(named);
|
|
|
|
return shape;
|
|
|
|
}
|
2013-04-19 20:25:50 -04:00
|
|
|
|
2013-06-12 23:13:39 -04:00
|
|
|
return {
|
|
|
|
Circle: function(/* center, radius */) {
|
|
|
|
var center = Point.readNamed(arguments, 'center'),
|
|
|
|
radius = Base.readNamed(arguments, 'radius');
|
|
|
|
return createShape('circle', center, new Size(radius * 2),
|
|
|
|
arguments);
|
|
|
|
},
|
2013-04-19 20:25:50 -04:00
|
|
|
|
2013-06-12 23:13:39 -04:00
|
|
|
Rectangle: function(/* rectangle */) {
|
|
|
|
var rect = Rectangle.readNamed(arguments, 'rectangle');
|
|
|
|
return createShape('rect', rect.getCenter(true),
|
|
|
|
rect.getSize(true), arguments);
|
|
|
|
},
|
|
|
|
|
|
|
|
Ellipse: function(/* rectangle */) {
|
|
|
|
var rect = Rectangle.readNamed(arguments, 'rectangle');
|
|
|
|
return createShape('ellipse', rect.getCenter(true),
|
|
|
|
rect.getSize(true), arguments);
|
|
|
|
}
|
|
|
|
};
|
2013-04-19 20:25:50 -04:00
|
|
|
}
|
|
|
|
});
|