/**
* Drawing Circle
* If you want to draw a circle using DOM rendering, you need the [Raphael.js](http://raphaeljs.com) library, version 2.1.0 or newer.
*
* @class
* @extends collie.DisplayObject
* @requires http://raphaeljs.com
* @param {Object} [htOption] Options
* @param {Number} [htOption.radius=0] Radius (px)
* @param {String} [htOption.strokeColor] Stroke color
* @param {Number} [htOption.strokeWidth=0] Border width. Set this option to 0 to disable the border.
* @param {String} [htOption.fillColor] Color to fill the circle with. The default value is transparent.
* @param {String} [htOption.fillImage] Image to fill the circle with.
* @param {Number} [htOption.startAngle=0] Starting angle (degrees)
* @param {Number} [htOption.endAngle=360] Ending angle (degrees). Set a starting angle of 0 and an ending angle of 360 to fully fill the Circle.
* @param {Boolean} [htOption.closePath=false] Close the path (like a Pac-man).
* @param {Boolean} [htOption.autoExpand=true] Set this option to true to expand the Circle object to fit its size to diameter.
* @param {Boolean} [htOption.anticlockwise=false] Set this option to true to fill the Circle anticlockwise.
* @example
* // Draw a Circle
* var circle = new collie.Circle({
* radius : 20 // The Circle object just expands to fit its size to diameter. (width:40, height:40)
* }).addTo(layer);
*
* // Arc
* circle.set({
* startAngle : 0,
* endAngle : 270
* });
*
* // A Pac-man
* circle.set({
* startAngle : 45,
* endAngle : 315,
* closePath : true
* });
*/
collie.Circle = collie.Class(/** @lends collie.Circle.prototype */{
$init : function (htOption) {
this.option({
radius : 0,
strokeColor : '#000000',
strokeWidth : 0,
fillColor : '',
fillImage : '',
startAngle : 0,
endAngle : 360,
closePath : false,
anticlockwise : false,
autoExpand : true
}, null, true);
this._oPaper = null;
this.optionSetter("radius", this._expandSize.bind(this));
this._expandSize();
},
_expandSize : function () {
if (this._htOption.autoExpand && this._htOption.radius) {
var size = this._htOption.radius * 2 + this._htOption.strokeWidth;
this.set("width", size);
this.set("height", size);
}
},
/**
* Delegate
* @private
*/
onDOMDraw : function (oEvent) {
var el = oEvent.element;
if (typeof Raphael === "undefined") {
return;
}
var htInfo = this.get();
var nStrokeWidth = htInfo.strokeWidth;
var nRadius = htInfo.radius;
var nWidth = htInfo.width;
var nHeight = htInfo.height;
var htDirty = this.getDirty();
var circle;
if (this._oPaper === null) {
this._oPaper = Raphael(el, nWidth + nStrokeWidth, nHeight + nStrokeWidth);
this._oPaper.canvas.style.zIndex = 10;
} else if (htDirty && (htDirty.width || htDirty.height)) {
this._oPaper.setSize(nWidth, nHeight);
}
el.style.left = -(nStrokeWidth / 2) + "px";
el.style.top = -(nStrokeWidth / 2) + "px";
this._oPaper.clear();
if (nRadius) {
var rx = nRadius;
var ry = nRadius;
var x1 = rx + nRadius * Math.cos(collie.util.toRad(htInfo.startAngle));
var y1 = ry + nRadius * Math.sin(collie.util.toRad(htInfo.startAngle));
var x2 = rx + nRadius * Math.cos(collie.util.toRad(htInfo.endAngle));
var y2 = ry + nRadius * Math.sin(collie.util.toRad(htInfo.endAngle));
var angle = htInfo.anticlockwise ? htInfo.startAngle - htInfo.endAngle : htInfo.endAngle - htInfo.startAngle;
if (Math.abs(angle) >= 360) {
angle = 360;
} else if (angle < 0) {
angle += 360;
}
var flag1 = (angle > 180 ? 1 : 0);
var flag2 = htInfo.anticlockwise ? 0 : 1;
if (angle >= 360) {
circle = this._oPaper.circle(rx, ry, nRadius);
} else {
circle = this._oPaper.path("M" + x1 + "," + y1 + "a" + nRadius + "," + nRadius + ",0," + flag1 + "," + flag2 + "," + (x2 -x1) + "," + (y2 -y1) + (htInfo.closePath ? "L" + rx + "," + ry + "L" + x1 + "," + y1 + "Z" : ""));
}
}
if (circle) {
circle.transform("t" + (nStrokeWidth / 2) + "," + (nStrokeWidth / 2));
if (htInfo.fillImage) {
collie.ImageManager.getImage(htInfo.fillImage, function (el) {
circle.attr("fill", "url('" + el.src + "')");
});
} else if (htInfo.fillColor) {
circle.attr("fill", htInfo.fillColor);
}
if (htInfo.strokeColor) {
circle.attr("stroke", htInfo.strokeColor);
}
circle.attr("stroke-width", htInfo.strokeWidth);
}
},
/**
* Delegate
* @private
*/
onCanvasDraw : function (oEvent) {
var htInfo = this.get();
var oContext = oEvent.context;
var nX = oEvent.x;
var nY = oEvent.y;
var bIsRetinaDispaly = collie.Renderer.isRetinaDisplay();
var nRadius = htInfo.radius;
var nStrokeWidth = htInfo.strokeWidth;
var nWidth = htInfo.width;
var nHeight = htInfo.height;
if (bIsRetinaDispaly) {
nWidth *= 2;
nHeight *= 2;
nRadius *= 2;
nStrokeWidth *= 2;
}
if (htInfo.fillImage) {
var el = collie.ImageManager.getImage(htInfo.fillImage);
if (!el) {
collie.ImageManager.getImage(htInfo.fillImage, function () {
this.setChanged();
}.bind(this));
} else {
var pattern = oContext.createPattern(el, "repeat");
oContext.fillStyle = pattern;
}
} else if (htInfo.fillColor) {
oContext.fillStyle = htInfo.fillColor;
}
if (htInfo.strokeColor) {
oContext.strokeStyle = htInfo.strokeColor;
}
if (nStrokeWidth) {
oContext.lineWidth = nStrokeWidth;
}
if (nRadius) {
var rx = nX + nRadius;
var ry = nY + nRadius;
var bFullCircle = Math.abs(htInfo.startAngle - htInfo.endAngle) >= 360;
oContext.beginPath();
if (htInfo.closePath && !bFullCircle) {
oContext.moveTo(rx, ry);
}
oContext.arc(rx, ry, nRadius, collie.util.toRad(htInfo.startAngle), collie.util.toRad(htInfo.endAngle), htInfo.anticlockwise);
if (htInfo.closePath) {
oContext.closePath();
}
if (htInfo.fillColor || htInfo.fillImage) {
oContext.fill();
}
if (htInfo.strokeWidth) {
oContext.stroke();
}
}
},
/**
* Move the position of the Circle, relatively to its center.
*
* @param {Number} nCenterX
* @param {Number} nCenterY
* @return {collie.Circle} For the method chaining
*/
center : function (nCenterX, nCenterY) {
this.set("x", nCenterX - this._htOption.radius);
this.set("y", nCenterY - this._htOption.radius);
return this;
},
/**
* Returns information on the Class as String
*
* @return {String}
*/
toString : function () {
return "Circle" + (this._htOption.name ? " " + this._htOption.name : "")+ " #" + this.getId() + (this.getImage() ? "(image:" + this.getImage().src + ")" : "");
}
}, collie.DisplayObject);