You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							2172 lines
						
					
					
						
							72 KiB
						
					
					
				
			
		
		
	
	
							2172 lines
						
					
					
						
							72 KiB
						
					
					
				/** | 
						|
 * Represents a canvas on which BPMN 2.0 constructs can be drawn. | 
						|
 *  | 
						|
 * Some of the icons used are licenced under a Creative Commons Attribution 2.5 | 
						|
 * License, see http://www.famfamfam.com/lab/icons/silk/ | 
						|
 *  | 
						|
 * @see ProcessDiagramGenerator | 
						|
 * @author (Java) Joram Barrez | 
						|
 * @author (Javascript) Dmitry Farafonov | 
						|
 */ | 
						|
  | 
						|
//Color.Cornsilk | 
						|
 | 
						|
var ARROW_HEAD_SIMPLE = "simple"; | 
						|
var ARROW_HEAD_EMPTY = "empty"; | 
						|
var ARROW_HEAD_FILL = "FILL"; | 
						|
var MULTILINE_VERTICAL_ALIGN_TOP = "top"; | 
						|
var MULTILINE_VERTICAL_ALIGN_MIDDLE = "middle"; | 
						|
var MULTILINE_VERTICAL_ALIGN_BOTTOM = "bottom"; | 
						|
var MULTILINE_HORIZONTAL_ALIGN_LEFT = "start"; | 
						|
var MULTILINE_HORIZONTAL_ALIGN_MIDDLE = "middle"; | 
						|
var MULTILINE_HORIZONTAL_ALIGN_RIGHT = "end"; | 
						|
 | 
						|
// Predefined sized | 
						|
var TEXT_PADDING = 3; | 
						|
var ARROW_WIDTH = 4; | 
						|
var CONDITIONAL_INDICATOR_WIDTH = 16; | 
						|
var MARKER_WIDTH = 12; | 
						|
var ANNOTATION_TEXT_PADDING = 7; | 
						|
 | 
						|
// Colors | 
						|
var TASK_COLOR = Color.OldLace; // original: Color.get(255, 255, 204); | 
						|
var TASK_STROKE_COLOR = Color.black; /*Color.SlateGrey; */ | 
						|
//var EXPANDED_SUBPROCESS_ATTRS = Color.black; /*Color.SlateGrey; */ | 
						|
var BOUNDARY_EVENT_COLOR = Color.white; | 
						|
var CONDITIONAL_INDICATOR_COLOR = Color.get(255, 255, 255); | 
						|
var HIGHLIGHT_COLOR = Color.Firebrick1; | 
						|
//var SEQUENCEFLOW_COLOR = Color.DimGrey; | 
						|
var SEQUENCEFLOW_COLOR = Color.black; | 
						|
 | 
						|
var CATCHING_EVENT_COLOR = Color.black; /* Color.SlateGrey; */ | 
						|
var START_EVENT_COLOR = Color.get(251,251,251); | 
						|
var START_EVENT_STROKE_COLOR = Color.black; /* Color.SlateGrey; */ | 
						|
var END_EVENT_COLOR = Color.get(251,251,251); | 
						|
//var END_EVENT_STROKE_COLOR = Color.black; | 
						|
var NONE_END_EVENT_COLOR = Color.Firebrick4; | 
						|
var NONE_END_EVENT_STROKE_COLOR = Color.Firebrick4; | 
						|
var ERROR_END_EVENT_COLOR = Color.Firebrick; | 
						|
var ERROR_END_EVENT_STROKE_COLOR = Color.Firebrick; | 
						|
//var LABEL_COLOR = Color.get(112, 146, 190); | 
						|
var LABEL_COLOR = Color.get(72, 106, 150); | 
						|
 | 
						|
// Fonts | 
						|
var NORMAL_FONT = {font: "10px Arial", opacity: 1, fill: Color.black}; | 
						|
var LABEL_FONT = {font: "11px Arial", "font-style":"italic", opacity: 1, "fill": LABEL_COLOR}; | 
						|
var LABEL_FONT_SMOOTH = {font: "10px Arial", "font-style":"italic", opacity: 1, "fill": LABEL_COLOR, stroke: LABEL_COLOR, "stroke-width":.4}; | 
						|
var TASK_FONT = {font: "11px Arial", opacity: 1, fill: Color.black}; | 
						|
var TASK_FONT_SMOOTH = {font: "11px Arial", opacity: 1, fill: Color.black, stroke: LABEL_COLOR, "stroke-width":.4}; | 
						|
var POOL_LANE_FONT = {font: "11px Arial", opacity: 1, fill: Color.black}; | 
						|
var EXPANDED_SUBPROCESS_FONT = {font: "11px Arial", opacity: 1, fill: Color.black}; | 
						|
 | 
						|
// Strokes | 
						|
var NORMAL_STROKE = 1; | 
						|
var SEQUENCEFLOW_STROKE = 1.5; | 
						|
var SEQUENCEFLOW_HIGHLIGHT_STROKE = 2; | 
						|
var THICK_TASK_BORDER_STROKE = 2.5; | 
						|
var GATEWAY_TYPE_STROKE = 3.2; | 
						|
var END_EVENT_STROKE = NORMAL_STROKE+2; | 
						|
var MULTI_INSTANCE_STROKE = 1.3; | 
						|
var EVENT_SUBPROCESS_ATTRS = 	{"stroke": Color.black, "stroke-width": NORMAL_STROKE, "stroke-dasharray": ". "}; | 
						|
//var EXPANDED_SUBPROCESS_ATTRS = {"stroke": Color.black, "stroke-width": NORMAL_STROKE, "fill": Color.FloralWhite}; | 
						|
var EXPANDED_SUBPROCESS_ATTRS = {"stroke": Color.black, "stroke-width": NORMAL_STROKE, "fill": Color.WhiteSmoke}; | 
						|
var NON_INTERRUPTING_EVENT_STROKE = "- "; | 
						|
 | 
						|
var TASK_CORNER_ROUND = 10; | 
						|
var EXPANDED_SUBPROCESS_CORNER_ROUND = 10; | 
						|
 | 
						|
// icons | 
						|
var ICON_SIZE = 16; | 
						|
var ICON_PADDING = 4; | 
						|
var USERTASK_IMAGE = 		"images/deployer/user.png"; | 
						|
var SCRIPTTASK_IMAGE = 		"images/deployer/script.png"; | 
						|
var SERVICETASK_IMAGE = 	"images/deployer/service.png"; | 
						|
var RECEIVETASK_IMAGE = 	"images/deployer/receive.png"; | 
						|
var SENDTASK_IMAGE = 		"images/deployer/send.png"; | 
						|
var MANUALTASK_IMAGE = 		"images/deployer/manual.png"; | 
						|
var BUSINESS_RULE_TASK_IMAGE = "images/deployer/business_rule.png"; | 
						|
var TIMER_IMAGE = 			"images/deployer/timer.png"; | 
						|
var MESSAGE_CATCH_IMAGE = 	"images/deployer/message_catch.png"; | 
						|
var MESSAGE_THROW_IMAGE = 	"images/deployer/message_throw.png"; | 
						|
var ERROR_THROW_IMAGE = 	"images/deployer/error_throw.png"; | 
						|
var ERROR_CATCH_IMAGE = 	"images/deployer/error_catch.png"; | 
						|
var SIGNAL_CATCH_IMAGE = 	"images/deployer/signal_catch.png"; | 
						|
var SIGNAL_THROW_IMAGE = 	"images/deployer/signal_throw.png"; | 
						|
var MULTIPLE_CATCH_IMAGE = 	"images/deployer/multiple_catch.png"; | 
						|
 | 
						|
 | 
						|
var ObjectType = { | 
						|
	ELLIPSE: "ellipse", | 
						|
	FLOW: "flow", | 
						|
	RECT: "rect", | 
						|
	RHOMBUS: "rhombus" | 
						|
}; | 
						|
 | 
						|
function OBJ(type){ | 
						|
	this.c = null; | 
						|
	this.type = type; | 
						|
	this.nestedElements = []; | 
						|
}; | 
						|
OBJ.prototype = { | 
						|
	 | 
						|
}; | 
						|
 | 
						|
var CONNECTION_TYPE = { | 
						|
	SEQUENCE_FLOW: "sequence_flow", | 
						|
	MESSAGE_FLOW: "message_flow", | 
						|
	ASSOCIATION: "association" | 
						|
}; | 
						|
 | 
						|
var ProcessDiagramCanvas = function(){ | 
						|
}; | 
						|
ProcessDiagramCanvas.prototype = { | 
						|
// var DefaultProcessDiagramCanvas = { | 
						|
	canvasHolder: "holder", | 
						|
	canvasWidth: 0,  | 
						|
	canvasHeight: 0, | 
						|
	paint: Color.black, | 
						|
	strokeWidth: 0, | 
						|
	font: null, | 
						|
	fontSmoothing: null, | 
						|
	 | 
						|
	g: null, | 
						|
	ninjaPaper: null, | 
						|
	 | 
						|
	objects: [], | 
						|
	 | 
						|
	processDefinitionId: null, | 
						|
	activity: null, | 
						|
	 | 
						|
	frame: null, | 
						|
	 | 
						|
	 | 
						|
	debug: false, | 
						|
	 | 
						|
	/** | 
						|
	* Creates an empty canvas with given width and height. | 
						|
	*/ | 
						|
	init: function(width, height, processDefinitionId){ | 
						|
		this.canvasWidth = width; | 
						|
		this.canvasHeight = height; | 
						|
		 | 
						|
		// TODO: name it as 'canvasName' | 
						|
		if (!processDefinitionId) | 
						|
			processDefinitionId = "holder"; | 
						|
		 | 
						|
		this.processDefinitionId = processDefinitionId; | 
						|
		this.canvasHolder = this.processDefinitionId; | 
						|
 | 
						|
		var h = document.getElementById(this.canvasHolder); | 
						|
		if (!h) return; | 
						|
		 | 
						|
		h.style.width = this.canvasWidth; | 
						|
		h.style.height = this.canvasHeight; | 
						|
		 | 
						|
		this.g = Raphael(this.canvasHolder); | 
						|
		this.g.clear(); | 
						|
	 | 
						|
		//this.setPaint(Color.DimGrey); | 
						|
		this.setPaint(Color.black); | 
						|
		//this.setPaint(Color.white); | 
						|
		this.setStroke(NORMAL_STROKE); | 
						|
		 | 
						|
		//this.setFont("Arial", 11); | 
						|
		this.setFont(NORMAL_FONT); | 
						|
		//this.font = this.g.getFont("Arial"); | 
						|
		 | 
						|
		this.fontSmoothing = true; | 
						|
		 | 
						|
		// ninja! | 
						|
		var RaphaelOriginal = Raphael; | 
						|
		this.ninjaPaper =(function (local_raphael) { | 
						|
			var paper = local_raphael(1, 1, 1, 1, processDefinitionId); | 
						|
			return paper; | 
						|
		})(Raphael.ninja()); | 
						|
		Raphael = RaphaelOriginal; | 
						|
	}, | 
						|
	setPaint: function(color){ | 
						|
		this.paint = color; | 
						|
	}, | 
						|
	getPaint: function(){ | 
						|
		return this.paint; | 
						|
	}, | 
						|
	setStroke: function(strokeWidth){ | 
						|
		this.strokeWidth = strokeWidth; | 
						|
	}, | 
						|
	getStroke: function(){ | 
						|
		return this.strokeWidth; | 
						|
	}, | 
						|
	/* | 
						|
	setFont: function(family, weight, style, stretch){ | 
						|
		this.font = this.g.getFont(family, weight); | 
						|
	}, | 
						|
	*/ | 
						|
	setFont: function(font){ | 
						|
		this.font = font; | 
						|
	}, | 
						|
	getFont: function(){ | 
						|
		return this.font; | 
						|
	}, | 
						|
	drawShaddow: function(object){ | 
						|
		var border = object.clone(); | 
						|
		border.attr({"stroke-width": this.strokeWidth + 6,  | 
						|
					"stroke": Color.white, | 
						|
					"fill": Color.white, | 
						|
					"opacity": 1, | 
						|
					"stroke-dasharray":null}); | 
						|
		//border.toBack(); | 
						|
		object.toFront(); | 
						|
		 | 
						|
		return border; | 
						|
	}, | 
						|
	 | 
						|
	setConextObject: function(obj){ | 
						|
		this.contextObject = obj; | 
						|
	}, | 
						|
	getConextObject: function(){ | 
						|
		return this.contextObject; | 
						|
	}, | 
						|
	setContextToElement: function(object){ | 
						|
		var contextObject = this.getConextObject(); | 
						|
		object.id = contextObject.id; | 
						|
		object.data("contextObject", contextObject); | 
						|
	}, | 
						|
	onClick: function(event, instance, element){ | 
						|
	  var overlay = element; | 
						|
	  var set = overlay.data("set"); | 
						|
	  var contextObject = overlay.data("contextObject"); | 
						|
	  //console.log("["+contextObject.getProperty("type")+"], activityId: " + contextObject.getId()); | 
						|
	  if (ProcessDiagramGenerator.options && ProcessDiagramGenerator.options.on && ProcessDiagramGenerator.options.on.click) { | 
						|
	    var args = [instance, element, contextObject]; | 
						|
	    ProcessDiagramGenerator.options.on.click.apply(event, args); | 
						|
	  } | 
						|
	}, | 
						|
	onRightClick: function(event, instance, element){ | 
						|
	  var overlay = element; | 
						|
	  var set = overlay.data("set"); | 
						|
	  var contextObject = overlay.data("contextObject"); | 
						|
	  //console.log("[%s], activityId: %s (RIGHTCLICK)", contextObject.getProperty("type"), contextObject.getId()); | 
						|
 | 
						|
	  if (ProcessDiagramGenerator.options && ProcessDiagramGenerator.options.on && ProcessDiagramGenerator.options.on.rightClick) { | 
						|
	    var args = [instance, element, contextObject]; | 
						|
	    ProcessDiagramGenerator.options.on.rightClick.apply(event, args); | 
						|
	  } | 
						|
	}, | 
						|
	onHoverIn: function(event, instance, element){ | 
						|
	  var overlay = element; | 
						|
	  var set = overlay.data("set"); | 
						|
	  var contextObject = overlay.data("contextObject"); | 
						|
 | 
						|
	  var border = instance.g.getById(contextObject.id + "_border"); | 
						|
	  border.attr("opacity", 0.3); | 
						|
 | 
						|
	  // provide callback | 
						|
	  if (ProcessDiagramGenerator.options && ProcessDiagramGenerator.options.on && ProcessDiagramGenerator.options.on.over) { | 
						|
	    var args = [instance, element, contextObject]; | 
						|
	    ProcessDiagramGenerator.options.on.over.apply(event, args); | 
						|
	  } | 
						|
	 }, | 
						|
	 onHoverOut: function(event, instance, element){ | 
						|
	   var overlay = element; | 
						|
	   var set = overlay.data("set"); | 
						|
	   var contextObject = overlay.data("contextObject"); | 
						|
 | 
						|
	   var border = instance.g.getById(contextObject.id + "_border"); | 
						|
	   border.attr("opacity", 0.0); | 
						|
	   // provide callback | 
						|
	   if (ProcessDiagramGenerator.options && ProcessDiagramGenerator.options.on && ProcessDiagramGenerator.options.on.out) { | 
						|
	     var args = [instance, element, contextObject]; | 
						|
	     ProcessDiagramGenerator.options.on.out.apply(event, args); | 
						|
	   } | 
						|
	 }, | 
						|
	 addHandlers: function(set, x, y, width, height, type){ | 
						|
	   var contextObject = this.getConextObject(); | 
						|
 | 
						|
	   var cx = x+width/2, cy = y+height/2; | 
						|
	   if (type == "event") { | 
						|
	     var border = this.g.ellipse(cx, cy, width/2+4, height/2+4); | 
						|
	     var overlay = this.g.ellipse(cx, cy, width/2, height/2); | 
						|
	   } else if (type == "gateway") { | 
						|
	     // rhombus | 
						|
	     var border = this.g.path( "M" + (x - 4) + " " + (y + (height / 2)) + | 
						|
	         "L" + (x + (width / 2)) + " " + (y + height + 4) + | 
						|
	         "L" + (x + width + 4) + " " + (y + (height / 2)) + | 
						|
	         "L" + (x + (width / 2)) + " " + (y - 4) + | 
						|
	         "z" ); | 
						|
	     var overlay = this.g.path(  "M" + x + " " + (y + (height / 2)) + | 
						|
	         "L" + (x + (width / 2)) + " " + (y + height) + | 
						|
	         "L" + (x + width) + " " + (y + (height / 2)) + | 
						|
	         "L" + (x + (width / 2)) + " " + y + | 
						|
	         "z" ); | 
						|
	   } else if (type == "task") { | 
						|
	     var border = this.g.rect(x - 4, y - 4, width+9, height+9, TASK_CORNER_ROUND+4); | 
						|
	     var overlay = this.g.rect(x, y, width, height, TASK_CORNER_ROUND); | 
						|
	   } | 
						|
 | 
						|
	   border.attr({stroke: Color.get(132,112,255)/*Color.Tan1*/,"stroke-width": 4, opacity: 0.0}); | 
						|
	   border.id = contextObject.id + "_border"; | 
						|
 | 
						|
	   set.push(border); | 
						|
 | 
						|
	   overlay.attr({stroke: Color.Orange,"stroke-width": 3, fill: Color.get(0,0,0), opacity: 0.0, cursor: "hand"}); | 
						|
	   overlay.data("set",set); | 
						|
	   overlay.id = contextObject.id; | 
						|
	   overlay.data("contextObject",contextObject); | 
						|
 | 
						|
	   var instance = this; | 
						|
	   overlay.mousedown(function(event){if (event.button == 2) instance.onRightClick(event, instance, this);}); | 
						|
	   overlay.click(function(event){instance.onClick(event, instance, this);}); | 
						|
	   overlay.hover(function(event){instance.onHoverIn(event, instance, this);}, function(event){instance.onHoverOut(event, instance, this);}); | 
						|
	 }, | 
						|
	 | 
						|
	/* | 
						|
	 * Start Events: | 
						|
	 *  | 
						|
	 *	drawNoneStartEvent | 
						|
	 *	drawTimerStartEvent | 
						|
	 *	drawMessageStartEvent | 
						|
	 *	drawErrorStartEvent | 
						|
	 *	drawSignalStartEvent | 
						|
	 *	_drawStartEventImage | 
						|
	 *	_drawStartEvent | 
						|
	 */ | 
						|
	  | 
						|
	drawNoneStartEvent: function(x, y, width, height) { | 
						|
	  this.g.setStart(); | 
						|
	   | 
						|
		var isInterrupting = undefined; | 
						|
		this._drawStartEvent(x, y, width, height, isInterrupting, null); | 
						|
		 | 
						|
		var set = this.g.setFinish(); | 
						|
		this.addHandlers(set, x, y, width, height, "event"); | 
						|
	}, | 
						|
	 | 
						|
	drawTimerStartEvent: function(x, y, width, height, isInterrupting, name) { | 
						|
	  this.g.setStart(); | 
						|
	   | 
						|
		this._drawStartEvent(x, y, width, height, isInterrupting, null); | 
						|
		 | 
						|
		var cx = x + width/2 - this.getStroke()/4; | 
						|
		var cy = y + height/2 - this.getStroke()/4; | 
						|
		 | 
						|
		var w = width*.9;// - this.getStroke()*2; | 
						|
		var h = height*.9;// - this.getStroke()*2; | 
						|
		 | 
						|
		this._drawClock(cx, cy, w, h); | 
						|
		 | 
						|
		if (this.gebug) | 
						|
			var center = this.g.ellipse(cx, cy, 3, 3).attr({stroke:"none", fill: Color.green}); | 
						|
		 | 
						|
		var set = this.g.setFinish(); | 
						|
		this.addHandlers(set, x, y, width, height, "event"); | 
						|
	}, | 
						|
	 | 
						|
	drawMessageStartEvent: function(x, y, width, height, isInterrupting, name) { | 
						|
	  this.g.setStart(); | 
						|
	   | 
						|
		this._drawStartEvent(x, y, width, height, isInterrupting, null); | 
						|
		 | 
						|
		this._drawStartEventImage(x, y, width, height, MESSAGE_CATCH_IMAGE); | 
						|
		 | 
						|
		var set = this.g.setFinish(); | 
						|
    this.addHandlers(set, x, y, width, height, "event"); | 
						|
	}, | 
						|
	 | 
						|
	drawErrorStartEvent: function(x, y, width, height, name) { | 
						|
	  this.g.setStart(); | 
						|
		var isInterrupting = undefined; | 
						|
		this._drawStartEvent(x, y, width, height, isInterrupting); | 
						|
 | 
						|
		this._drawStartEventImage(x, y, width, height, ERROR_CATCH_IMAGE); | 
						|
		 | 
						|
		var set = this.g.setFinish(); | 
						|
    this.addHandlers(set, x, y, width, height, "event"); | 
						|
	}, | 
						|
	 | 
						|
	drawSignalStartEvent: function(x, y, width, height, isInterrupting, name) { | 
						|
	  this.g.setStart(); | 
						|
		this._drawStartEvent(x, y, width, height, isInterrupting, null); | 
						|
		 | 
						|
		this._drawStartEventImage(x, y, width, height, SIGNAL_CATCH_IMAGE); | 
						|
		 | 
						|
		var set = this.g.setFinish(); | 
						|
    this.addHandlers(set, x, y, width, height, "event"); | 
						|
	}, | 
						|
	 | 
						|
	drawMultipleStartEvent: function(x, y, width, height, isInterrupting, name) { | 
						|
	  this.g.setStart(); | 
						|
		 | 
						|
	  this._drawStartEvent(x, y, width, height, isInterrupting, null); | 
						|
		 | 
						|
		var cx = x + width/2 - this.getStroke()/4; | 
						|
		var cy = y + height/2 - this.getStroke()/4; | 
						|
		 | 
						|
		var w = width*1; | 
						|
		var h = height*1; | 
						|
		 | 
						|
		this._drawPentagon(cx, cy, w, h); | 
						|
		 | 
						|
		var set = this.g.setFinish(); | 
						|
    this.addHandlers(set, x, y, width, height, "event"); | 
						|
	}, | 
						|
	 | 
						|
	_drawStartEventImage: function(x, y, width, height, image){ | 
						|
		var cx = x + width/2 - this.getStroke()/2; | 
						|
		var cy = y + height/2 - this.getStroke()/2; | 
						|
		 | 
						|
		var w = width*.65;// - this.getStroke()*2; | 
						|
		var h = height*.65;// - this.getStroke()*2; | 
						|
		 | 
						|
		var img = this.g.image(image, cx-w/2, cy-h/2, w, h); | 
						|
	}, | 
						|
	_drawStartEvent: function(x, y, width, height, isInterrupting){ | 
						|
		var originalPaint = this.getPaint(); | 
						|
		if (typeof(START_EVENT_STROKE_COLOR) != "undefined") | 
						|
			this.setPaint(START_EVENT_STROKE_COLOR); | 
						|
		 | 
						|
		 | 
						|
		width -= this.strokeWidth / 2; | 
						|
		height -= this.strokeWidth / 2; | 
						|
		 | 
						|
		x = x + width/2; | 
						|
		y = y + height/2; | 
						|
		 | 
						|
		var circle = this.g.ellipse(x, y, width/2, height/2); | 
						|
		 | 
						|
		circle.attr({"stroke-width": this.strokeWidth,  | 
						|
				"stroke": this.paint,  | 
						|
				//"stroke": START_EVENT_STROKE_COLOR, | 
						|
				"fill": START_EVENT_COLOR}); | 
						|
				 | 
						|
		// white shaddow | 
						|
		this.drawShaddow(circle); | 
						|
		 | 
						|
		if (isInterrupting!=null && isInterrupting!=undefined && !isInterrupting)  | 
						|
			circle.attr({"stroke-dasharray": NON_INTERRUPTING_EVENT_STROKE}); | 
						|
 | 
						|
		this.setContextToElement(circle); | 
						|
		 | 
						|
		 | 
						|
		this.setPaint(originalPaint); | 
						|
	}, | 
						|
	 | 
						|
	/* | 
						|
	 * End Events: | 
						|
	 *  | 
						|
	 *	drawNoneEndEvent | 
						|
	 *	drawErrorEndEvent | 
						|
	 *	drawMessageEndEvent | 
						|
	 *	drawSignalEndEvent | 
						|
	 *	drawMultipleEndEvent | 
						|
	 *  _drawEndEventImage | 
						|
	 *	_drawNoneEndEvent | 
						|
	 */ | 
						|
	  | 
						|
	drawNoneEndEvent: function(x, y, width, height) { | 
						|
	  this.g.setStart(); | 
						|
	   | 
						|
		this._drawNoneEndEvent(x, y, width, height, null, "noneEndEvent"); | 
						|
		 | 
						|
		var set = this.g.setFinish(); | 
						|
    this.addHandlers(set, x, y, width, height, "event"); | 
						|
	}, | 
						|
	 | 
						|
	drawErrorEndEvent: function(x, y, width, height) { | 
						|
	  this.g.setStart(); | 
						|
		var type = "errorEndEvent"; | 
						|
		this._drawNoneEndEvent(x, y, width, height, null, type); | 
						|
		 | 
						|
		this._drawEndEventImage(x, y, width, height, ERROR_THROW_IMAGE); | 
						|
		 | 
						|
		var set = this.g.setFinish(); | 
						|
    this.addHandlers(set, x, y, width, height, "event"); | 
						|
	}, | 
						|
	 | 
						|
	drawMessageEndEvent: function(x, y, width, height, name) { | 
						|
	  this.g.setStart(); | 
						|
		var type = "errorEndEvent"; | 
						|
		this._drawNoneEndEvent(x, y, width, height, null, type); | 
						|
		 | 
						|
		this._drawEndEventImage(x, y, width, height, MESSAGE_THROW_IMAGE); | 
						|
		 | 
						|
		var set = this.g.setFinish(); | 
						|
    this.addHandlers(set, x, y, width, height, "event"); | 
						|
	}, | 
						|
	 | 
						|
	drawSignalEndEvent: function(x, y, width, height, name) { | 
						|
	  this.g.setStart(); | 
						|
		var type = "errorEndEvent"; | 
						|
		this._drawNoneEndEvent(x, y, width, height, null, type); | 
						|
		 | 
						|
		this._drawEndEventImage(x, y, width, height, SIGNAL_THROW_IMAGE); | 
						|
		 | 
						|
		var set = this.g.setFinish(); | 
						|
    this.addHandlers(set, x, y, width, height, "event"); | 
						|
	}, | 
						|
	 | 
						|
	drawMultipleEndEvent: function(x, y, width, height, name) { | 
						|
	  this.g.setStart(); | 
						|
		var type = "errorEndEvent"; | 
						|
		this._drawNoneEndEvent(x, y, width, height, null, type); | 
						|
		 | 
						|
		var cx = x + width/2;// - this.getStroke(); | 
						|
		var cy = y + height/2;// - this.getStroke(); | 
						|
		 | 
						|
		var w = width*1; | 
						|
		var h = height*1; | 
						|
		 | 
						|
		var filled = true; | 
						|
		this._drawPentagon(cx, cy, w, h, filled); | 
						|
		 | 
						|
		var set = this.g.setFinish(); | 
						|
    this.addHandlers(set, x, y, width, height, "event"); | 
						|
	}, | 
						|
	 | 
						|
	drawTerminateEndEvent: function(x, y, width, height) { | 
						|
	  this.g.setStart(); | 
						|
		var type = "errorEndEvent"; | 
						|
		this._drawNoneEndEvent(x, y, width, height, null, type); | 
						|
		 | 
						|
		var cx = x + width/2;// - this.getStroke()/2; | 
						|
		var cy = y + height/2;// - this.getStroke()/2; | 
						|
		 | 
						|
		var w = width/2*.6; | 
						|
		var h = height/2*.6; | 
						|
		 | 
						|
		var circle = this.g.ellipse(cx, cy, w, h).attr({fill: Color.black}); | 
						|
		 | 
						|
		var set = this.g.setFinish(); | 
						|
    this.addHandlers(set, x, y, width, height, "event"); | 
						|
	}, | 
						|
	 | 
						|
	_drawEndEventImage: function(x, y, width, height, image){ | 
						|
		var cx = x + width/2 - this.getStroke()/2; | 
						|
		var cy = y + height/2 - this.getStroke()/2; | 
						|
		 | 
						|
		var w = width*.65; | 
						|
		var h = height*.65; | 
						|
		 | 
						|
		var img = this.g.image(image, cx-w/2, cy-h/2, w, h); | 
						|
	}, | 
						|
	 | 
						|
	_drawNoneEndEvent: function(x, y, width, height, image, type) { | 
						|
		var originalPaint = this.getPaint(); | 
						|
		if (typeof(CATCHING_EVENT_COLOR) != "undefined") | 
						|
			this.setPaint(CATCHING_EVENT_COLOR); | 
						|
			 | 
						|
		var strokeColor = this.getPaint(); | 
						|
		var fillColor = this.getPaint(); | 
						|
		 | 
						|
		if (type == "errorEndEvent") { | 
						|
			strokeColor = ERROR_END_EVENT_STROKE_COLOR; | 
						|
			fillColor = ERROR_END_EVENT_COLOR; | 
						|
		} else if (type == "noneEndEvent") { | 
						|
			strokeColor = NONE_END_EVENT_STROKE_COLOR; | 
						|
			fillColor = NONE_END_EVENT_COLOR; | 
						|
		} else  | 
						|
			 | 
						|
		// event circles | 
						|
		width -= this.strokeWidth / 2; | 
						|
		height -= this.strokeWidth / 2; | 
						|
		 | 
						|
		x = x + width/2;// + this.strokeWidth/2; | 
						|
		y = y + width/2;// + this.strokeWidth/2; | 
						|
		 | 
						|
		// outerCircle | 
						|
		var outerCircle = this.g.ellipse(x, y, width/2, height/2); | 
						|
		 | 
						|
		// white shaddow | 
						|
		var shaddow = this.drawShaddow(outerCircle); | 
						|
		 | 
						|
		outerCircle.attr({"stroke-width": this.strokeWidth, | 
						|
						"stroke": strokeColor, | 
						|
						"fill": fillColor}); | 
						|
		 | 
						|
		var innerCircleX = x; | 
						|
		var innerCircleY = y; | 
						|
		var innerCircleWidth = width/2 - 2; | 
						|
		var innerCircleHeight = height/2 - 2; | 
						|
		var innerCircle = this.g.ellipse(innerCircleX, innerCircleY, innerCircleWidth, innerCircleHeight); | 
						|
		innerCircle.attr({"stroke-width": this.strokeWidth, | 
						|
				"stroke": strokeColor, | 
						|
				"fill": Color.white}); | 
						|
 | 
						|
		// TODO: implement it | 
						|
		//var originalPaint = this.getPaint(); | 
						|
		//this.g.setPaint(BOUNDARY_EVENT_COLOR); | 
						|
		 | 
						|
		this.setPaint(originalPaint); | 
						|
	}, | 
						|
	 | 
						|
	/* | 
						|
	 * Catching Events: | 
						|
	 *  | 
						|
	 *	drawCatchingTimerEvent | 
						|
	 *	drawCatchingErrorEvent | 
						|
	 *	drawCatchingSignalEvent | 
						|
	 *  drawCatchingMessageEvent | 
						|
	 *	drawCatchingMultipleEvent | 
						|
	 *	_drawCatchingEventImage | 
						|
	 *	_drawCatchingEvent | 
						|
	 */ | 
						|
	  | 
						|
	 | 
						|
	drawCatchingTimerEvent: function(x, y, width, height, isInterrupting, name) { | 
						|
	  this.g.setStart(); | 
						|
		this._drawCatchingEvent(x, y, width, height, isInterrupting, null); | 
						|
		 | 
						|
		var innerCircleWidth = width - 4; | 
						|
		var innerCircleHeight = height - 4; | 
						|
		 | 
						|
		var cx = x + width/2 - this.getStroke()/4; | 
						|
		var cy = y + height/2 - this.getStroke()/4; | 
						|
		 | 
						|
		var w = innerCircleWidth*.9;// - this.getStroke()*2; | 
						|
		var h = innerCircleHeight*.9;// - this.getStroke()*2; | 
						|
		 | 
						|
		this._drawClock(cx, cy, w, h); | 
						|
		 | 
						|
		var set = this.g.setFinish(); | 
						|
		this.addHandlers(set, x, y, width, height, "event"); | 
						|
	}, | 
						|
 | 
						|
	drawCatchingErrorEvent: function(x, y, width, height, isInterrupting, name) { | 
						|
	  this.g.setStart(); | 
						|
		this._drawCatchingEvent(x, y, width, height, isInterrupting, null); | 
						|
		 | 
						|
		this._drawCatchingEventImage(x, y, width, height, ERROR_CATCH_IMAGE); | 
						|
		 | 
						|
		var set = this.g.setFinish(); | 
						|
    this.addHandlers(set, x, y, width, height, "event"); | 
						|
	}, | 
						|
	 | 
						|
	drawCatchingSignalEvent: function(x, y, width, height, isInterrupting, name) { | 
						|
	  this.g.setStart(); | 
						|
		this._drawCatchingEvent(x, y, width, height, isInterrupting, null); | 
						|
		 | 
						|
		this._drawCatchingEventImage(x, y, width, height, SIGNAL_CATCH_IMAGE); | 
						|
		 | 
						|
		var set = this.g.setFinish(); | 
						|
    this.addHandlers(set, x, y, width, height, "event"); | 
						|
	}, | 
						|
	 | 
						|
	drawCatchingMessageEvent: function(x, y, width, height, isInterrupting, name) { | 
						|
	  this.g.setStart(); | 
						|
		this._drawCatchingEvent(x, y, width, height, isInterrupting, null); | 
						|
		 | 
						|
		this._drawCatchingEventImage(x, y, width, height, MESSAGE_CATCH_IMAGE); | 
						|
		 | 
						|
		var set = this.g.setFinish(); | 
						|
    this.addHandlers(set, x, y, width, height, "event"); | 
						|
	}, | 
						|
	 | 
						|
	drawCatchingMultipleEvent: function(x, y, width, height, isInterrupting, name) { | 
						|
	  this.g.setStart(); | 
						|
		this._drawCatchingEvent(x, y, width, height, isInterrupting, null); | 
						|
		 | 
						|
		var cx = x + width/2 - this.getStroke(); | 
						|
		var cy = y + height/2 - this.getStroke(); | 
						|
		 | 
						|
		var w = width*.9; | 
						|
		var h = height*.9; | 
						|
		 | 
						|
		this._drawPentagon(cx, cy, w, h); | 
						|
		 | 
						|
		var set = this.g.setFinish(); | 
						|
    this.addHandlers(set, x, y, width, height, "event"); | 
						|
	}, | 
						|
	 | 
						|
	_drawCatchingEventImage: function(x, y, width, height, image){ | 
						|
		var innerCircleWidth = width - 4; | 
						|
		var innerCircleHeight = height - 4; | 
						|
		 | 
						|
		var cx = x + width/2 - this.getStroke()/2; | 
						|
		var cy = y + height/2 - this.getStroke()/2; | 
						|
		 | 
						|
		var w = innerCircleWidth*.6;// - this.getStroke()*2; | 
						|
		var h = innerCircleHeight*.6;// - this.getStroke()*2; | 
						|
		 | 
						|
		var img = this.g.image(image, cx-w/2, cy-h/2, w, h); | 
						|
	}, | 
						|
	 | 
						|
	_drawCatchingEvent: function(x, y, width, height, isInterrupting, image) { | 
						|
		var originalPaint = this.getPaint(); | 
						|
		if (typeof(CATCHING_EVENT_COLOR) != "undefined") | 
						|
			this.setPaint(CATCHING_EVENT_COLOR); | 
						|
			 | 
						|
		// event circles | 
						|
		width -= this.strokeWidth / 2; | 
						|
		height -= this.strokeWidth / 2; | 
						|
		 | 
						|
		x = x + width/2;// + this.strokeWidth/2; | 
						|
		y = y + width/2;// + this.strokeWidth/2; | 
						|
		 | 
						|
		// outerCircle | 
						|
		var outerCircle = this.g.ellipse(x, y, width/2, height/2); | 
						|
		 | 
						|
		// white shaddow | 
						|
		var shaddow = this.drawShaddow(outerCircle); | 
						|
		 | 
						|
		//console.log("isInterrupting: " + isInterrupting, "x:" , x, "y:",y); | 
						|
		if (isInterrupting!=null && isInterrupting!=undefined && !isInterrupting)  | 
						|
			outerCircle.attr({"stroke-dasharray": NON_INTERRUPTING_EVENT_STROKE}); | 
						|
		 | 
						|
		outerCircle.attr({"stroke-width": this.strokeWidth, | 
						|
						"stroke": this.getPaint(), | 
						|
						"fill": BOUNDARY_EVENT_COLOR}); | 
						|
		 | 
						|
		var innerCircleX = x; | 
						|
		var innerCircleY = y; | 
						|
		var innerCircleRadiusX = width/2 - 4; | 
						|
		var innerCircleRadiusY = height/2 - 4; | 
						|
		var innerCircle = this.g.ellipse(innerCircleX, innerCircleY, innerCircleRadiusX, innerCircleRadiusY); | 
						|
		innerCircle.attr({"stroke-width": this.strokeWidth, | 
						|
				"stroke": this.getPaint()}); | 
						|
 | 
						|
		if (image) { | 
						|
			var imageWidth = imageHeight = innerCircleRadiusX*1.2 + this.getStroke()*2; | 
						|
			var imageX = innerCircleX-imageWidth/2 - this.strokeWidth/2; | 
						|
			var imageY = innerCircleY-imageWidth/2 - this.strokeWidth/2; | 
						|
			var img = this.g.image(image, imageX, imageY, imageWidth, imageHeight); | 
						|
		} | 
						|
		 | 
						|
		this.setPaint(originalPaint); | 
						|
		 | 
						|
		var set = this.g.set(); | 
						|
		set.push(outerCircle, innerCircle, shaddow); | 
						|
		this.setContextToElement(outerCircle); | 
						|
		 | 
						|
		// TODO: add shapes to set | 
						|
		 | 
						|
		/* | 
						|
		var st = this.g.set(); | 
						|
		st.push( | 
						|
			this.g.ellipse(innerCircleX, innerCircleY, 2, 2), | 
						|
			this.g.ellipse(imageX, imageY, 2, 2) | 
						|
		); | 
						|
		st.attr({fill: "red", "stroke-width":0}); | 
						|
		*/ | 
						|
	}, | 
						|
	 | 
						|
	/* | 
						|
	 * Catching Events: | 
						|
	 *  | 
						|
	 *	drawThrowingNoneEvent | 
						|
	 *	drawThrowingSignalEvent | 
						|
	 *	drawThrowingMessageEvent | 
						|
	 *	drawThrowingMultipleEvent | 
						|
	 */ | 
						|
	 | 
						|
	drawThrowingNoneEvent: function(x, y, width, height, name) { | 
						|
	  this.g.setStart(); | 
						|
		this._drawCatchingEvent(x, y, width, height, null, null); | 
						|
		 | 
						|
		var set = this.g.setFinish(); | 
						|
    this.addHandlers(set, x, y, width, height, "event"); | 
						|
	}, | 
						|
	 | 
						|
	drawThrowingSignalEvent: function(x, y, width, height, name) { | 
						|
	  this.g.setStart(); | 
						|
		this._drawCatchingEvent(x, y, width, height, null, null); | 
						|
		 | 
						|
		this._drawCatchingEventImage(x, y, width, height, SIGNAL_THROW_IMAGE); | 
						|
		 | 
						|
		var set = this.g.setFinish(); | 
						|
    this.addHandlers(set, x, y, width, height, "event"); | 
						|
	}, | 
						|
	 | 
						|
	drawThrowingMessageEvent: function(x, y, width, height, name) { | 
						|
	  this.g.setStart(); | 
						|
		this._drawCatchingEvent(x, y, width, height, null, null); | 
						|
		 | 
						|
		this._drawCatchingEventImage(x, y, width, height, MESSAGE_THROW_IMAGE); | 
						|
		 | 
						|
		var set = this.g.setFinish(); | 
						|
    this.addHandlers(set, x, y, width, height, "event"); | 
						|
	}, | 
						|
	 | 
						|
	drawThrowingMultipleEvent: function(x, y, width, height, name) { | 
						|
	  this.g.setStart(); | 
						|
		this._drawCatchingEvent(x, y, width, height, null, null); | 
						|
		 | 
						|
		var cx = x + width/2 - this.getStroke(); | 
						|
		var cy = y + height/2 - this.getStroke(); | 
						|
		 | 
						|
		var w = width*.9; | 
						|
		var h = height*.9; | 
						|
		 | 
						|
		var filled = true; | 
						|
		this._drawPentagon(cx, cy, w, h, filled); | 
						|
		 | 
						|
		var set = this.g.setFinish(); | 
						|
    this.addHandlers(set, x, y, width, height, "event"); | 
						|
	}, | 
						|
	 | 
						|
	/* | 
						|
	 * Draw flows: | 
						|
	 *  | 
						|
	 *  _connectFlowToActivity | 
						|
	 *	_drawFlow | 
						|
	 *	_drawDefaultSequenceFlowIndicator | 
						|
	 *	drawSequenceflow | 
						|
	 *	drawMessageflow | 
						|
	 *	drawAssociation | 
						|
	 *	_drawCircleTail | 
						|
	 *	_drawArrowHead | 
						|
	 *	_drawConditionalSequenceFlowIndicator | 
						|
	 *	drawSequenceflowWithoutArrow | 
						|
	 */ | 
						|
	  | 
						|
	_connectFlowToActivity: function(sourceActivityId, destinationActivityId, waypoints){ | 
						|
		var sourceActivity = this.g.getById(sourceActivityId); | 
						|
		var destinationActivity = this.g.getById(destinationActivityId); | 
						|
		if (sourceActivity == null || destinationActivity == null) { | 
						|
			if (sourceActivity == null) | 
						|
				console.error("source activity["+sourceActivityId+"] not found"); | 
						|
			else | 
						|
				console.error("destination activity["+destinationActivityId+"] not found"); | 
						|
			return null; | 
						|
		} | 
						|
			var bbSourceActivity = sourceActivity.getBBox() | 
						|
			var bbDestinationActivity = destinationActivity.getBBox() | 
						|
			 | 
						|
			var path = []; | 
						|
			var newWaypoints = []; | 
						|
			for(var i = 0; i < waypoints.length; i++){ | 
						|
				var pathType = "" | 
						|
				if (i==0) | 
						|
					pathType = "M"; | 
						|
				else  | 
						|
					pathType = "L"; | 
						|
					 | 
						|
				path.push([pathType, waypoints[i].x, waypoints[i].y]); | 
						|
				newWaypoints.push({x:waypoints[i].x, y:waypoints[i].y}); | 
						|
			} | 
						|
 | 
						|
			var ninjaPathSourceActivity = this.ninjaPaper.path(sourceActivity.realPath); | 
						|
			var ninjaPathDestinationActivity = this.ninjaPaper.path(destinationActivity.realPath); | 
						|
			var ninjaBBSourceActivity = ninjaPathSourceActivity.getBBox(); | 
						|
			var ninjaBBDestinationActivity = ninjaPathDestinationActivity.getBBox(); | 
						|
			 | 
						|
			// set target of the flow to the center of the taskObject | 
						|
			var newPath = path; | 
						|
			var originalSource = {x: newPath[0][1], y: newPath[0][2]}; | 
						|
			var originalTarget = {x: newPath[newPath.length-1][1], y: newPath[newPath.length-1][2]}; | 
						|
			newPath[0][1] = ninjaBBSourceActivity.x + (ninjaBBSourceActivity.x2 - ninjaBBSourceActivity.x ) / 2; | 
						|
			newPath[0][2] = ninjaBBSourceActivity.y + (ninjaBBSourceActivity.y2 - ninjaBBSourceActivity.y ) / 2; | 
						|
			newPath[newPath.length-1][1] = ninjaBBDestinationActivity.x + (ninjaBBDestinationActivity.x2 - ninjaBBDestinationActivity.x ) / 2; | 
						|
			newPath[newPath.length-1][2] = ninjaBBDestinationActivity.y + (ninjaBBDestinationActivity.y2 - ninjaBBDestinationActivity.y ) / 2; | 
						|
			 | 
						|
			var ninjaPathFlowObject = this.ninjaPaper.path(newPath); | 
						|
			var ninjaBBFlowObject = ninjaPathFlowObject.getBBox(); | 
						|
			 | 
						|
			var intersectionsSource = Raphael.pathIntersection(ninjaPathSourceActivity.realPath, ninjaPathFlowObject.realPath); | 
						|
			var intersectionsDestination = Raphael.pathIntersection(ninjaPathDestinationActivity.realPath, ninjaPathFlowObject.realPath); | 
						|
			var intersectionSource = intersectionsSource.pop(); | 
						|
			var intersectionDestination = intersectionsDestination.pop(); | 
						|
			 | 
						|
			if (intersectionSource != undefined) { | 
						|
				if (this.gebug) { | 
						|
					var diameter = 5; | 
						|
					var dotOriginal = this.g.ellipse(originalSource.x, originalSource.y, diameter, diameter).attr({"fill": Color.white, "stroke": Color.Pink}); | 
						|
					var dot = this.g.ellipse(intersectionSource.x, intersectionSource.y, diameter, diameter).attr({"fill": Color.white, "stroke": Color.Green}); | 
						|
				} | 
						|
				 | 
						|
				newWaypoints[0].x = intersectionSource.x; | 
						|
				newWaypoints[0].y = intersectionSource.y; | 
						|
			} | 
						|
			if (intersectionDestination != undefined) { | 
						|
				if (this.gebug) { | 
						|
					var diameter = 5; | 
						|
					var dotOriginal = this.g.ellipse(originalTarget.x, originalTarget.y, diameter, diameter).attr({"fill": Color.white, "stroke": Color.Red}); | 
						|
					var dot = this.g.ellipse(intersectionDestination.x, intersectionDestination.y, diameter, diameter).attr({"fill": Color.white, "stroke": Color.Blue}); | 
						|
				} | 
						|
				 | 
						|
				newWaypoints[newWaypoints.length-1].x = intersectionDestination.x; | 
						|
				newWaypoints[newWaypoints.length-1].y = intersectionDestination.y; | 
						|
			} | 
						|
			 | 
						|
			this.ninjaPaper.clear(); | 
						|
		return newWaypoints; | 
						|
	}, | 
						|
	  | 
						|
	_drawFlow: function(waypoints, conditional, isDefault, highLighted, withArrowHead, connectionType){ | 
						|
		var originalPaint = this.getPaint(); | 
						|
		var originalStroke = this.getStroke(); | 
						|
		 | 
						|
		this.setPaint(SEQUENCEFLOW_COLOR); | 
						|
		this.setStroke(SEQUENCEFLOW_STROKE); | 
						|
		 | 
						|
		if (highLighted) { | 
						|
			this.setPaint(HIGHLIGHT_COLOR); | 
						|
			this.setStroke(SEQUENCEFLOW_HIGHLIGHT_STROKE); | 
						|
		} | 
						|
 | 
						|
// TODO: generate polylineId or do something!! | 
						|
		var uuid = Raphael.createUUID(); | 
						|
		 | 
						|
		var contextObject = this.getConextObject(); | 
						|
		var newWaypoints = waypoints; | 
						|
		if (contextObject) { | 
						|
			var newWaypoints = this._connectFlowToActivity(contextObject.sourceActivityId, contextObject.destinationActivityId, waypoints); | 
						|
			 | 
						|
			if (!newWaypoints) { | 
						|
				console.error("Error draw flow from '"+contextObject.sourceActivityId+"' to '"+contextObject.destinationActivityId+"' "); | 
						|
				return; | 
						|
			} | 
						|
		} | 
						|
		var polyline = new Polyline(uuid, newWaypoints, this.getStroke()); | 
						|
		//var polyline = new Polyline(waypoints, 3); | 
						|
		 | 
						|
		polyline.element = this.g.path(polyline.path); | 
						|
		polyline.element.attr("stroke-width", this.getStroke()); | 
						|
		polyline.element.attr("stroke", this.getPaint()); | 
						|
			 | 
						|
		if (contextObject) { | 
						|
			polyline.element.id = contextObject.id; | 
						|
			polyline.element.data("contextObject", contextObject); | 
						|
		} else { | 
						|
			polyline.element.id = uuid; | 
						|
		} | 
						|
		 | 
						|
		 | 
						|
		/* | 
						|
		polyline.element.mouseover(function(){ | 
						|
			this.attr({"stroke-width": NORMAL_STROKE + 2}); | 
						|
		}).mouseout(function(){ | 
						|
			this.attr({"stroke-width": NORMAL_STROKE}); | 
						|
		}); | 
						|
		*/ | 
						|
		 | 
						|
		var last = polyline.getAnchorsCount()-1; | 
						|
		var x = polyline.getAnchor(last).x; | 
						|
		var y = polyline.getAnchor(last).y; | 
						|
		//var c = this.g.ellipse(x, y, 5, 5); | 
						|
		 | 
						|
		var lastLineIndex = polyline.getLinesCount()-1; | 
						|
		var line = polyline.getLine(lastLineIndex); | 
						|
		var firstLine = polyline.getLine(0); | 
						|
		 | 
						|
		var arrowHead = null, | 
						|
			circleTail = null, | 
						|
			defaultSequenceFlowIndicator = null, | 
						|
			conditionalSequenceFlowIndicator = null; | 
						|
 | 
						|
		if (connectionType == CONNECTION_TYPE.MESSAGE_FLOW) { | 
						|
			circleTail = this._drawCircleTail(firstLine, connectionType); | 
						|
		} | 
						|
		if(withArrowHead) | 
						|
			arrowHead = this._drawArrowHead(line, connectionType); | 
						|
		 | 
						|
		//console.log("isDefault: ", isDefault, ", isDefaultConditionAvailable: ", polyline.isDefaultConditionAvailable); | 
						|
		if (isDefault && polyline.isDefaultConditionAvailable) { | 
						|
			//var angle = polyline.getLineAngle(0); | 
						|
			//console.log("firstLine", firstLine); | 
						|
			defaultSequenceFlowIndicator = this._drawDefaultSequenceFlowIndicator(firstLine); | 
						|
		} | 
						|
		 | 
						|
		if (conditional) { | 
						|
			conditionalSequenceFlowIndicator = this._drawConditionalSequenceFlowIndicator(firstLine); | 
						|
		} | 
						|
 | 
						|
        // draw flow name | 
						|
        var flowName = contextObject.name; | 
						|
        if (flowName) { | 
						|
            var xPointArray = contextObject.xPointArray; | 
						|
            var yPointArray = contextObject.yPointArray; | 
						|
            var textX = xPointArray[0] < xPointArray[1] ? xPointArray[0] : xPointArray[1]; | 
						|
            var textY = yPointArray[0] < yPointArray[1] ? yPointArray[1] : yPointArray[0]; | 
						|
            // fix xy | 
						|
            textX += 20; | 
						|
            textY -= 10; | 
						|
            this.g.text(textX, textY, flowName).attr(LABEL_FONT); | 
						|
        } | 
						|
		 | 
						|
		var st = this.g.set(); | 
						|
		st.push(polyline.element, arrowHead, circleTail, conditionalSequenceFlowIndicator); | 
						|
		polyline.element.data("set", st); | 
						|
		polyline.element.data("withArrowHead", withArrowHead); | 
						|
		 | 
						|
		var polyCloneAttrNormal = {"stroke-width": this.getStroke() + 5, stroke: Color.get(132,112,255), opacity: 0.0, cursor: "hand"}; | 
						|
		var polyClone = st.clone().attr(polyCloneAttrNormal).hover(function () { | 
						|
				//if (polyLine.data("isSelected")) return; | 
						|
				polyClone.attr({opacity: 0.2}); | 
						|
			}, function () { | 
						|
				//if (polyLine.data("isSelected")) return; | 
						|
				polyClone.attr({opacity: 0.0}); | 
						|
			}); | 
						|
		polyClone.data("objectId", polyline.element.id); | 
						|
		polyClone.click(function(){ | 
						|
			var instance = this; | 
						|
			var objectId = instance.data("objectId"); | 
						|
			var object = this.paper.getById(objectId); | 
						|
			var contextObject = object.data("contextObject"); | 
						|
			if (contextObject) { | 
						|
				console.log("[flow], objectId: " + object.id +", flow: " + contextObject.flow); | 
						|
				ProcessDiagramGenerator.showFlowInfo(contextObject); | 
						|
			} | 
						|
		}).dblclick(function(){ | 
						|
			console.log("!!! DOUBLE CLICK !!!"); | 
						|
		}).hover(function (mouseEvent) { | 
						|
			var instance = this; | 
						|
			var objectId = instance.data("objectId"); | 
						|
			var object = this.paper.getById(objectId); | 
						|
			var contextObject = object.data("contextObject"); | 
						|
			if (contextObject) | 
						|
				ProcessDiagramGenerator.showFlowInfo(contextObject); | 
						|
		}); | 
						|
		polyClone.data("parentId", uuid); | 
						|
		 | 
						|
		if (!connectionType || connectionType == CONNECTION_TYPE.SEQUENCE_FLOW) | 
						|
			polyline.element.attr("stroke-width", this.getStroke()); | 
						|
		else if (connectionType == CONNECTION_TYPE.MESSAGE_FLOW) | 
						|
			polyline.element.attr({"stroke-dasharray": "--"}); | 
						|
		else if (connectionType == CONNECTION_TYPE.ASSOCIATION) | 
						|
			polyline.element.attr({"stroke-dasharray": ". "}); | 
						|
		 | 
						|
		this.setPaint(originalPaint); | 
						|
		this.setStroke(originalStroke); | 
						|
	}, | 
						|
	 | 
						|
	_drawDefaultSequenceFlowIndicator: function(line) { | 
						|
		//console.log("line: ", line); | 
						|
		 | 
						|
		var len = 10; c = len/2, f = 8; | 
						|
		var defaultIndicator = this.g.path("M" + (-c) + " " + 0 + "L" + (c) + " " + 0); | 
						|
		defaultIndicator.attr("stroke-width", this.getStroke()+0); | 
						|
		defaultIndicator.attr("stroke", this.getPaint()); | 
						|
		 | 
						|
		 | 
						|
		var cosAngle = Math.cos((line.angle)); | 
						|
		var sinAngle = Math.sin((line.angle)); | 
						|
		 | 
						|
		var dx = f * cosAngle; | 
						|
		var dy = f * sinAngle; | 
						|
		 | 
						|
		var x1 = line.x1 + dx + 0*c*cosAngle; | 
						|
		var y1 = line.y1 + dy + 0*c*sinAngle; | 
						|
		 | 
						|
		defaultIndicator.transform("t" + (x1) + "," + (y1) + ""); | 
						|
		defaultIndicator.transform("...r" + Raphael.deg(line.angle - 3*Math.PI / 4) + " " + 0 + " " + 0); | 
						|
		/* | 
						|
		var c0 = this.g.ellipse(0, 0, 1, 1).attr({stroke: Color.Blue}); | 
						|
		c0.transform("t" + (line.x1) + "," + (line.y1) + ""); | 
						|
		var center = this.g.ellipse(0, 0, 1, 1).attr({stroke: Color.Red}); | 
						|
		center.transform("t" + (line.x1+dx) + "," + (line.y1+dy) + ""); | 
						|
		*/ | 
						|
		 | 
						|
		return defaultIndicator; | 
						|
	}, | 
						|
	 | 
						|
	drawSequenceflow: function(waypoints, conditional, isDefault, highLighted) { | 
						|
		var withArrowHead = true; | 
						|
		this._drawFlow(waypoints, conditional, isDefault, highLighted, withArrowHead, CONNECTION_TYPE.SEQUENCE_FLOW); | 
						|
	}, | 
						|
	 | 
						|
	drawMessageflow: function(waypoints, highLighted) { | 
						|
		var withArrowHead = true; | 
						|
		var conditional=isDefault=false; | 
						|
		this._drawFlow(waypoints, conditional, isDefault, highLighted, withArrowHead, CONNECTION_TYPE.MESSAGE_FLOW); | 
						|
	}, | 
						|
	 | 
						|
	drawAssociation: function(waypoints, withArrowHead, highLighted) { | 
						|
		var withArrowHead = withArrowHead; | 
						|
		var conditional=isDefault=false; | 
						|
		this._drawFlow(waypoints, conditional, isDefault, highLighted, withArrowHead, CONNECTION_TYPE.ASSOCIATION); | 
						|
	}, | 
						|
   | 
						|
	_drawCircleTail: function(line, connectionType){ | 
						|
		var diameter = ARROW_WIDTH/2*1.5; | 
						|
		 | 
						|
		// anti smoothing | 
						|
		if (this.strokeWidth%2 == 1) | 
						|
			line.x1 += .5, line.y1 += .5; | 
						|
		 | 
						|
		var circleTail = this.g.ellipse(line.x1, line.y1, diameter, diameter); | 
						|
		circleTail.attr("fill", Color.white); | 
						|
		circleTail.attr("stroke", this.getPaint()); | 
						|
		 | 
						|
		return circleTail; | 
						|
	}, | 
						|
	 | 
						|
	_drawArrowHead: function(line, connectionType){ | 
						|
		var doubleArrowWidth = 2 * ARROW_WIDTH; | 
						|
		 | 
						|
		if (connectionType == CONNECTION_TYPE.ASSOCIATION) | 
						|
			var arrowHead = this.g.path("M-" + (ARROW_WIDTH/2+.5) + " -" + doubleArrowWidth + "L 0 0 L" + (ARROW_WIDTH/2+.5) + " -" + doubleArrowWidth); | 
						|
		else | 
						|
			var arrowHead = this.g.path("M0 0L-" + (ARROW_WIDTH/2+.5) + " -" + doubleArrowWidth + "L" + (ARROW_WIDTH/2+.5) + " -" + doubleArrowWidth + "z"); | 
						|
		 | 
						|
		//arrowHead.transform("t" + 0 + ",-" + this.getStroke() + ""); | 
						|
		 | 
						|
		// anti smoothing | 
						|
		if (this.strokeWidth%2 == 1) | 
						|
			line.x2 += .5, line.y2 += .5; | 
						|
		 | 
						|
		arrowHead.transform("t" + line.x2 + "," + line.y2 + ""); | 
						|
		arrowHead.transform("...r" + Raphael.deg(line.angle - Math.PI / 2) + " " + 0 + " " + 0); | 
						|
		 | 
						|
		if (!connectionType || connectionType == CONNECTION_TYPE.SEQUENCE_FLOW) | 
						|
			arrowHead.attr("fill", this.getPaint()); | 
						|
		else if (connectionType == CONNECTION_TYPE.MESSAGE_FLOW) | 
						|
			arrowHead.attr("fill", Color.white); | 
						|
			 | 
						|
		arrowHead.attr("stroke-width", this.getStroke()); | 
						|
		arrowHead.attr("stroke", this.getPaint()); | 
						|
		 | 
						|
		return arrowHead; | 
						|
	}, | 
						|
	 | 
						|
	/* | 
						|
	drawArrowHead2: function(srcX, srcY, targetX, targetY) { | 
						|
		var doubleArrowWidth = 2 * ARROW_WIDTH; | 
						|
		 | 
						|
		//var arrowHead = this.g.path("M-" + ARROW_WIDTH/2 + " -" + doubleArrowWidth + "L0 0" + "L" + ARROW_WIDTH/2 + " -" + doubleArrowWidth + "z"); | 
						|
		 | 
						|
		var arrowHead = this.g.path("M0 0L-" + ARROW_WIDTH/1.5 + " -" + doubleArrowWidth + "L" + ARROW_WIDTH/1.5 + " -" + doubleArrowWidth + "z"); | 
						|
		//var c = DefaultProcessDiagramCanvas.g.ellipse(0, 0, 3, 3); | 
						|
		//c.transform("t"+targetX+","+targetY+""); | 
						|
		 | 
						|
		var angle = Math.atan2(targetY - srcY, targetX - srcX); | 
						|
		 | 
						|
		arrowHead.transform("t"+targetX+","+targetY+""); | 
						|
		arrowHead.transform("...r" + Raphael.deg(angle - Math.PI / 2) + " "+0+" "+0); | 
						|
		 | 
						|
		//console.log(arrowHead.transform()); | 
						|
		//console.log("--> " + Raphael.deg(angle - Math.PI / 2)); | 
						|
		 | 
						|
		arrowHead.attr("fill", this.getPaint()); | 
						|
		arrowHead.attr("stroke", this.getPaint()); | 
						|
		 | 
						|
		/ * | 
						|
		// shaddow | 
						|
		var c0 = arrowHead.clone(); | 
						|
		c0.transform("...t-1 1"); | 
						|
		c0.attr("stroke-width", this.strokeWidth); | 
						|
		c0.attr("stroke", Color.black); | 
						|
		c0.attr("opacity", 0.15); | 
						|
		c0.toBack(); | 
						|
		* / | 
						|
	}, | 
						|
	*/ | 
						|
	 | 
						|
	_drawConditionalSequenceFlowIndicator: function(line){ | 
						|
		var horizontal = (CONDITIONAL_INDICATOR_WIDTH * 0.7); | 
						|
		var halfOfHorizontal = horizontal / 2; | 
						|
		var halfOfVertical = CONDITIONAL_INDICATOR_WIDTH / 2; | 
						|
 | 
						|
		var uuid = null; | 
						|
		var waypoints = [{x: 0, y: 0}, | 
						|
						{x: -halfOfHorizontal, y: halfOfVertical}, | 
						|
						{x: 0, y: CONDITIONAL_INDICATOR_WIDTH}, | 
						|
						{x: halfOfHorizontal, y: halfOfVertical}]; | 
						|
		/* | 
						|
		var polyline = new Polyline(uuid, waypoints, this.getStroke()); | 
						|
		polyline.element = this.g.path(polyline.path); | 
						|
		polyline.element.attr("stroke-width", this.getStroke()); | 
						|
		polyline.element.attr("stroke", this.getPaint()); | 
						|
		polyline.element.id = uuid; | 
						|
		*/ | 
						|
		var polygone = new Polygone(waypoints, this.getStroke()); | 
						|
		polygone.element = this.g.path(polygone.path); | 
						|
		polygone.element.attr("fill", Color.white); | 
						|
		 | 
						|
		polygone.transform("t" + line.x1 + "," + line.y1 + ""); | 
						|
		polygone.transform("...r" + Raphael.deg(line.angle - Math.PI / 2) + " " + 0 + " " + 0); | 
						|
		 | 
						|
		 | 
						|
		var cosAngle = Math.cos((line.angle)); | 
						|
		var sinAngle = Math.sin((line.angle)); | 
						|
		 | 
						|
		//polygone.element.attr("stroke-width", this.getStroke()); | 
						|
		//polygone.element.attr("stroke", this.getPaint()); | 
						|
		 | 
						|
		polygone.attr({"stroke-width": this.getStroke(), "stroke": this.getPaint()}); | 
						|
		 | 
						|
		return polygone.element; | 
						|
	}, | 
						|
   | 
						|
	drawSequenceflowWithoutArrow: function(waypoints, conditional, isDefault, highLighted) { | 
						|
		var withArrowHead = false; | 
						|
		this._drawFlow(waypoints, conditional, isDefault, highLighted, withArrowHead, CONNECTION_TYPE.SEQUENCE_FLOW); | 
						|
	}, | 
						|
	 | 
						|
	/* | 
						|
	 * Draw artifacts | 
						|
	 */ | 
						|
	 | 
						|
	drawPoolOrLane: function(x, y, width, height, name){ | 
						|
		// anti smoothing | 
						|
		if (this.strokeWidth%2 == 1) | 
						|
			x = Math.round(x) + .5, y = Math.round(y) + .5; | 
						|
		 | 
						|
		// shape | 
						|
		var rect = this.g.rect(x, y, width, height); | 
						|
		var attr = {"stroke-width": NORMAL_STROKE, stroke: TASK_STROKE_COLOR}; | 
						|
		rect.attr(attr); | 
						|
		 | 
						|
		// Add the name as text, vertical | 
						|
		if(name != null && name.length > 0) { | 
						|
			var attr = POOL_LANE_FONT; | 
						|
			 | 
						|
			// Include some padding | 
						|
			var availableTextSpace = height - 6; | 
						|
			 | 
						|
			// Create rotation for derived font | 
						|
			var truncated = this.fitTextToWidth(name, availableTextSpace); | 
						|
			var realWidth = this.getStringWidth(truncated, attr); | 
						|
			var realHeight = this.getStringHeight(truncated, attr); | 
						|
			 | 
						|
			//console.log("truncated:", truncated, ", height:", height, ", realHeight:", realHeight, ", availableTextSpace:", availableTextSpace, ", realWidth:", realWidth); | 
						|
			var newX = x + 2 + realHeight*1 - realHeight/2; | 
						|
			var newY = 3 + y + availableTextSpace - (availableTextSpace - realWidth) / 2 - realWidth/2; | 
						|
			var textElement = this.g.text(newX, newY, truncated).attr(attr); | 
						|
			//console.log(".getBBox(): ", t.getBBox()); | 
						|
			textElement.transform("r" + Raphael.deg(270 * Math.PI/180) + " " + newX + " " + newY); | 
						|
		} | 
						|
		 | 
						|
		// TODO: add to set | 
						|
	}, | 
						|
	 | 
						|
	_drawTask: function(name, x, y, width, height, thickBorder) { | 
						|
		var originalPaint = this.getPaint(); | 
						|
		this.setPaint(TASK_COLOR); | 
						|
		 | 
						|
		// anti smoothing | 
						|
		if (this.strokeWidth%2 == 1) | 
						|
			x = Math.round(x) + .5, y = Math.round(y) + .5; | 
						|
		 | 
						|
		// shape | 
						|
		var shape = this.g.rect(x, y, width, height, TASK_CORNER_ROUND); | 
						|
		var attr = {"stroke-width": this.strokeWidth, stroke: TASK_STROKE_COLOR, fill: this.getPaint()}; | 
						|
		shape.attr(attr); | 
						|
		//shape.attr({fill: "90-"+this.getPaint()+"-" + Color.get(250, 250, 244)}); | 
						|
		 | 
						|
		var contextObject = this.getConextObject(); | 
						|
		if (contextObject) { | 
						|
			shape.id = contextObject.id; | 
						|
			shape.data("contextObject", contextObject); | 
						|
		} | 
						|
		 | 
						|
		//var activity = this.getConextObject(); | 
						|
		//console.log("activity: " + activity.getId(), activity); | 
						|
		//Object.clone(activity); | 
						|
		 | 
						|
		/* | 
						|
		c.mouseover(function(){ | 
						|
			this.attr({"stroke-width": NORMAL_STROKE + 2}); | 
						|
		}).mouseout(function(){ | 
						|
			this.attr({"stroke-width": NORMAL_STROKE}); | 
						|
		}); | 
						|
		*/ | 
						|
		 | 
						|
		this.setPaint(originalPaint); | 
						|
 | 
						|
		// white shaddow | 
						|
		this.drawShaddow(shape); | 
						|
		 | 
						|
		 | 
						|
		if (thickBorder) { | 
						|
			shape.attr({"stroke-width": THICK_TASK_BORDER_STROKE}); | 
						|
		} else { | 
						|
			//g.draw(rect); | 
						|
		} | 
						|
		 | 
						|
		// text | 
						|
		if (name) { | 
						|
			var fontAttr = TASK_FONT; | 
						|
			 | 
						|
			// Include some padding | 
						|
			var paddingX = 5; | 
						|
			var paddingY = 5; | 
						|
			var availableTextSpace = width - paddingX*2; | 
						|
			 | 
						|
			// TODO: this.setFont | 
						|
			// var originalFont = this.getFont(); | 
						|
			// this.setFont(TASK_FONT) | 
						|
			/* | 
						|
			var truncated = this.fitTextToWidth(name, availableTextSpace); | 
						|
			var realWidth = this.getStringWidth(truncated, fontAttr); | 
						|
			var realHeight = this.getStringHeight(truncated, fontAttr); | 
						|
			 | 
						|
			//var t = this.g.text(x + width/2 + realWidth*0/2 + paddingX*0, y + height/2, truncated).attr(fontAttr); | 
						|
			*/ | 
						|
			//console.log("draw task name: " + name); | 
						|
			var boxWidth = width - (2 * TEXT_PADDING); | 
						|
			var boxHeight = height - ICON_SIZE - ICON_PADDING - ICON_PADDING - MARKER_WIDTH - 2 - 2; | 
						|
			var boxX = x + width/2 - boxWidth/2; | 
						|
			var boxY = y + height/2 - boxHeight/2 + ICON_PADDING + ICON_PADDING - 2 - 2; | 
						|
			/* | 
						|
			var boxWidth = width - (2 * ANNOTATION_TEXT_PADDING); | 
						|
			var boxHeight = height - (2 * ANNOTATION_TEXT_PADDING); | 
						|
			var boxX = x + width/2 - boxWidth/2; | 
						|
			var boxY = y + height/2 - boxHeight/2; | 
						|
			*/ | 
						|
			 | 
						|
			this.drawTaskLabel(name, boxX, boxY, boxWidth, boxHeight); | 
						|
		} | 
						|
	}, | 
						|
	 | 
						|
	drawTaskLabel: function(text, x, y, boxWidth, boxHeight){ | 
						|
		var originalFont = this.getFont(); | 
						|
		this.setFont(TASK_FONT); | 
						|
			 | 
						|
		this._drawMultilineText(text, x, y, boxWidth, boxHeight, MULTILINE_VERTICAL_ALIGN_MIDDLE, MULTILINE_HORIZONTAL_ALIGN_MIDDLE); | 
						|
		 | 
						|
		this.setFont(originalFont); | 
						|
	}, | 
						|
	 | 
						|
	drawAnnotationText: function(text, x, y, width, height){ | 
						|
		//this._drawMultilineText(text, x, y, width, height, "start"); | 
						|
		 | 
						|
		var originalPaint = this.getPaint(); | 
						|
		var originalFont = this.getFont(); | 
						|
		 | 
						|
		this.setPaint(Color.black); | 
						|
		this.setFont(TASK_FONT); | 
						|
			 | 
						|
		this._drawMultilineText(text, x, y, width, height, MULTILINE_VERTICAL_ALIGN_TOP, MULTILINE_HORIZONTAL_ALIGN_LEFT); | 
						|
		 | 
						|
		this.setPaint(originalPaint); | 
						|
		this.setFont(originalFont); | 
						|
	}, | 
						|
	 | 
						|
	drawLabel: function(text, x, y, width, height){ | 
						|
		//this._drawMultilineText(text, x, y, width, height, "start"); | 
						|
		 | 
						|
		var originalPaint = this.getPaint(); | 
						|
		var originalFont = this.getFont(); | 
						|
		 | 
						|
		this.setPaint(LABEL_COLOR); | 
						|
		//this.setFont(LABEL_FONT); | 
						|
		this.setFont(LABEL_FONT_SMOOTH); | 
						|
		 | 
						|
		// predefined box width for labels | 
						|
		// TODO: use label width as is, but not height (for stretching) | 
						|
		if (!width || !height) { | 
						|
		  width = 100; | 
						|
		  height = 0; | 
						|
		} | 
						|
		 | 
						|
		// TODO: remove it. It is debug | 
						|
		x = x - width/2; | 
						|
	   | 
						|
		this._drawMultilineText(text, x, y, width, height, MULTILINE_VERTICAL_ALIGN_TOP, MULTILINE_HORIZONTAL_ALIGN_MIDDLE); | 
						|
		 | 
						|
		this.setPaint(originalPaint); | 
						|
		this.setFont(originalFont); | 
						|
	}, | 
						|
	 | 
						|
	/* | 
						|
	drawMultilineLabel: function(text, x, y){ | 
						|
		var originalFont = this.getFont(); | 
						|
		this.setFont(LABEL_FONT_SMOOTH); | 
						|
		 | 
						|
		var boxWidth = 80; | 
						|
		x = x - boxWidth/2 | 
						|
		 | 
						|
		this._drawMultilineText(text, x, y, boxWidth, null, "middle"); | 
						|
		this.setFont(originalFont); | 
						|
	}, | 
						|
	*/ | 
						|
	 | 
						|
	getStringWidth: function(text, fontAttrs){ | 
						|
		var textElement = this.g.text(0, 0, text).attr(fontAttrs).hide(); | 
						|
		var bb = textElement.getBBox(); | 
						|
		 | 
						|
		//console.log("string width: ", t.getBBox().width); | 
						|
		return textElement.getBBox().width; | 
						|
	}, | 
						|
	getStringHeight: function(text, fontAttrs){ | 
						|
		var textElement = this.g.text(0, 0, text).attr(fontAttrs).hide(); | 
						|
		var bb = textElement.getBBox(); | 
						|
		 | 
						|
		//console.log("string height: ", t.getBBox().height); | 
						|
		return textElement.getBBox().height; | 
						|
	}, | 
						|
	fitTextToWidth: function(original, width) { | 
						|
		var text = original; | 
						|
 | 
						|
		// TODO: move attr on parameters | 
						|
		var attr = {font: "11px Arial", opacity: 0}; | 
						|
		 | 
						|
		// remove length for "..." | 
						|
		var dots = this.g.text(0, 0, "...").attr(attr).hide(); | 
						|
		var dotsBB = dots.getBBox(); | 
						|
		 | 
						|
		var maxWidth = width - dotsBB.width; | 
						|
		 | 
						|
		var textElement = this.g.text(0, 0, text).attr(attr).hide(); | 
						|
		var bb = textElement.getBBox(); | 
						|
		 | 
						|
		// it's a little bit incorrect with "..." | 
						|
		while (bb.width > maxWidth && text.length > 0) { | 
						|
			text = text.substring(0, text.length - 1); | 
						|
			textElement.attr({"text": text}); | 
						|
			bb = textElement.getBBox(); | 
						|
		} | 
						|
 | 
						|
		// remove element from paper | 
						|
		textElement.remove(); | 
						|
		 | 
						|
		if (text != original) { | 
						|
			text = text + "..."; | 
						|
		} | 
						|
 | 
						|
		return text; | 
						|
	}, | 
						|
	wrapTextToWidth: function(original, width){ | 
						|
	 | 
						|
		//return original; | 
						|
		 | 
						|
		var text = original; | 
						|
		var wrappedText = "\n"; | 
						|
		 | 
						|
		// TODO: move attr on parameters | 
						|
		var attr = {font: "11px Arial", opacity: 0}; | 
						|
		 | 
						|
		var textElement = this.g.text(0, 0, wrappedText).attr(attr).hide(); | 
						|
		var bb = textElement.getBBox(); | 
						|
		 | 
						|
		var resultText = ""; | 
						|
		var i = 0, j = 0; | 
						|
		while (text.length > 0) { | 
						|
			while (bb.width < width && text.length>0) { | 
						|
				// remove "\n" | 
						|
				wrappedText = wrappedText.substring(0,wrappedText.length-1); | 
						|
				// add new char, add "\n" | 
						|
				wrappedText = wrappedText + text.substring(0,1) + "\n"; | 
						|
				text = text.substring(1); | 
						|
				 | 
						|
				textElement.attr({"text": wrappedText}); | 
						|
				bb = textElement.getBBox(); | 
						|
				i++; | 
						|
				if (i>200) break; | 
						|
			} | 
						|
			// remove "\n" | 
						|
			wrappedText = wrappedText.substring(0, wrappedText.length - 1); | 
						|
			 | 
						|
			if (text.length == 0) { | 
						|
				resultText += wrappedText; | 
						|
				break; | 
						|
			} | 
						|
			 | 
						|
			// return last char to text | 
						|
			text = wrappedText.substring(wrappedText.length-1) + text; | 
						|
			// remove last char from wrappedText | 
						|
			wrappedText = wrappedText.substring(0, wrappedText.length-1) + "\n"; | 
						|
			 | 
						|
			textElement.attr({"text": wrappedText}); | 
						|
			bb = textElement.getBBox(); | 
						|
			 | 
						|
			//console.log(">> ", wrappedText, ", ", text); | 
						|
			resultText += wrappedText; | 
						|
			wrappedText = "\n"; | 
						|
			 | 
						|
			j++; | 
						|
			if (j>20) break; | 
						|
		} | 
						|
		// remove element from paper | 
						|
		textElement.remove(); | 
						|
		 | 
						|
		return resultText; | 
						|
	}, | 
						|
	 | 
						|
	wrapTextToWidth2: function(original, width){ | 
						|
		var text = original; | 
						|
		var wrappedText = "\n"; | 
						|
		 | 
						|
		// TODO: move attr on parameters | 
						|
		var attr = {font: "11px Arial", opacity: 0}; | 
						|
		 | 
						|
		var textElement = this.g.text(0, 0, wrappedText).attr(attr).hide(); | 
						|
		var bb = textElement.getBBox(); | 
						|
		 | 
						|
		var resultText = ""; | 
						|
		var i = 0, j = 0; | 
						|
		while (text.length > 0) { | 
						|
			while (bb.width < width && text.length>0) { | 
						|
				// remove "\n" | 
						|
				wrappedText = wrappedText.substring(0,wrappedText.length-1); | 
						|
				// add new char, add "\n" | 
						|
				wrappedText = wrappedText + text.substring(0,1) + "\n"; | 
						|
				text = text.substring(1); | 
						|
				 | 
						|
				textElement.attr({"text": wrappedText}); | 
						|
				bb = textElement.getBBox(); | 
						|
				i++; | 
						|
				if (i>200) break; | 
						|
			} | 
						|
			// remove "\n" | 
						|
			wrappedText = wrappedText.substring(0, wrappedText.length - 1); | 
						|
			 | 
						|
			if (text.length == 0) { | 
						|
				resultText += wrappedText; | 
						|
				break; | 
						|
			} | 
						|
			 | 
						|
			// return last char to text | 
						|
			text = wrappedText.substring(wrappedText.length-1) + text; | 
						|
			// remove last char from wrappedText | 
						|
			wrappedText = wrappedText.substring(0, wrappedText.length-1) + "\n"; | 
						|
			 | 
						|
			textElement.attr({"text": wrappedText}); | 
						|
			bb = textElement.getBBox(); | 
						|
			 | 
						|
			//console.log(">> ", wrappedText, ", ", text); | 
						|
			resultText += wrappedText; | 
						|
			wrappedText = "\n"; | 
						|
			 | 
						|
			j++; | 
						|
			if (j>20) break; | 
						|
		} | 
						|
		// remove element from paper | 
						|
		textElement.remove(); | 
						|
		 | 
						|
		return resultText; | 
						|
	}, | 
						|
	 | 
						|
	drawUserTask: function(name, x, y, width, height) { | 
						|
	  this.g.setStart(); | 
						|
		this._drawTask(name, x, y, width, height); | 
						|
		var img = this.g.image(USERTASK_IMAGE, x + ICON_PADDING, y + ICON_PADDING, ICON_SIZE, ICON_SIZE); | 
						|
		var set = this.g.setFinish(); | 
						|
		this.addHandlers(set, x, y, width, height, "task"); | 
						|
	}, | 
						|
	 | 
						|
	drawScriptTask: function(name, x, y, width, height) { | 
						|
	  this.g.setStart(); | 
						|
		this._drawTask(name, x, y, width, height); | 
						|
		var img = this.g.image(SCRIPTTASK_IMAGE, x + ICON_PADDING, y + ICON_PADDING, ICON_SIZE, ICON_SIZE); | 
						|
		var set = this.g.setFinish(); | 
						|
    this.addHandlers(set, x, y, width, height, "task"); | 
						|
	}, | 
						|
	 | 
						|
	drawServiceTask: function(name, x, y, width, height) { | 
						|
	  this.g.setStart(); | 
						|
		this._drawTask(name, x, y, width, height); | 
						|
		var img = this.g.image(SERVICETASK_IMAGE, x + ICON_PADDING, y + ICON_PADDING, ICON_SIZE, ICON_SIZE); | 
						|
		var set = this.g.setFinish(); | 
						|
    this.addHandlers(set, x, y, width, height, "task"); | 
						|
	}, | 
						|
	 | 
						|
	drawReceiveTask: function(name, x, y, width, height) { | 
						|
	  this.g.setStart(); | 
						|
		this._drawTask(name, x, y, width, height); | 
						|
		var img = this.g.image(RECEIVETASK_IMAGE, x + 7, y + 7, ICON_SIZE, ICON_SIZE); | 
						|
		var set = this.g.setFinish(); | 
						|
    this.addHandlers(set, x, y, width, height, "task"); | 
						|
	}, | 
						|
	 | 
						|
	drawSendTask: function(name, x, y, width, height) { | 
						|
	  this.g.setStart(); | 
						|
		this._drawTask(name, x, y, width, height); | 
						|
		var img = this.g.image(SENDTASK_IMAGE, x + 7, y + 7, ICON_SIZE, ICON_SIZE); | 
						|
		var set = this.g.setFinish(); | 
						|
    this.addHandlers(set, x, y, width, height, "task"); | 
						|
	}, | 
						|
	 | 
						|
	drawManualTask: function(name, x, y, width, height) { | 
						|
	  this.g.setStart(); | 
						|
		this._drawTask(name, x, y, width, height); | 
						|
		var img = this.g.image(MANUALTASK_IMAGE, x + 7, y + 7, ICON_SIZE, ICON_SIZE); | 
						|
		var set = this.g.setFinish(); | 
						|
    this.addHandlers(set, x, y, width, height, "task"); | 
						|
	}, | 
						|
	 | 
						|
	drawBusinessRuleTask: function(name, x, y, width, height) { | 
						|
	  this.g.setStart(); | 
						|
		this._drawTask(name, x, y, width, height); | 
						|
		var img = this.g.image(BUSINESS_RULE_TASK_IMAGE, x + 7, y + 7, ICON_SIZE, ICON_SIZE); | 
						|
		var set = this.g.setFinish(); | 
						|
    this.addHandlers(set, x, y, width, height, "task"); | 
						|
	}, | 
						|
	 | 
						|
	drawExpandedSubProcess: function(name, x, y, width, height, isTriggeredByEvent){ | 
						|
	  this.g.setStart(); | 
						|
		// anti smoothing | 
						|
		if (this.strokeWidth%2 == 1) | 
						|
			x = Math.round(x) + .5, y = Math.round(y) + .5; | 
						|
		 | 
						|
		// shape | 
						|
		var rect = this.g.rect(x, y, width, height, EXPANDED_SUBPROCESS_CORNER_ROUND); | 
						|
		 | 
						|
		// Use different stroke (dashed) | 
						|
		if(isTriggeredByEvent) { | 
						|
			rect.attr(EVENT_SUBPROCESS_ATTRS); | 
						|
		} else { | 
						|
			rect.attr(EXPANDED_SUBPROCESS_ATTRS); | 
						|
		} | 
						|
		 | 
						|
		this.setContextToElement(rect); | 
						|
		 | 
						|
		var fontAttr = EXPANDED_SUBPROCESS_FONT; | 
						|
		 | 
						|
		// Include some padding | 
						|
		var paddingX = 10; | 
						|
		var paddingY = 5; | 
						|
		var availableTextSpace = width - paddingX*2; | 
						|
		 | 
						|
		var truncated = this.fitTextToWidth(name, availableTextSpace); | 
						|
		var realWidth = this.getStringWidth(truncated, fontAttr); | 
						|
		var realHeight = this.getStringHeight(truncated, fontAttr); | 
						|
		 | 
						|
		var textElement = this.g.text(x + width/2 - realWidth*0/2 + 0*paddingX, y + realHeight/2 + paddingY, truncated).attr(fontAttr); | 
						|
		 | 
						|
		var set = this.g.setFinish(); | 
						|
		// TODO: Expanded Sub Process may has specific handlers | 
						|
		//this.addHandlers(set, x, y, width, height, "task"); | 
						|
	}, | 
						|
	 | 
						|
	drawCollapsedSubProcess: function(name, x, y, width, height, isTriggeredByEvent) { | 
						|
	  this.g.setStart(); | 
						|
	  this._drawCollapsedTask(name, x, y, width, height, false); | 
						|
	  var set = this.g.setFinish(); | 
						|
    this.addHandlers(set, x, y, width, height, "task"); | 
						|
	}, | 
						|
	 | 
						|
	drawCollapsedCallActivity: function(name, x, y, width, height) { | 
						|
	  this.g.setStart(); | 
						|
		this._drawCollapsedTask(name, x, y, width, height, true); | 
						|
		var set = this.g.setFinish(); | 
						|
    this.addHandlers(set, x, y, width, height, "task"); | 
						|
	}, | 
						|
 | 
						|
	_drawCollapsedTask: function(name, x, y, width, height, thickBorder) { | 
						|
		// The collapsed marker is now visualized separately | 
						|
		this._drawTask(name, x, y, width, height, thickBorder); | 
						|
	}, | 
						|
	 | 
						|
	drawCollapsedMarker: function(x, y, width, height){ | 
						|
		// rectangle | 
						|
		var rectangleWidth = MARKER_WIDTH; | 
						|
		var rectangleHeight = MARKER_WIDTH; | 
						|
		 | 
						|
		// anti smoothing | 
						|
		if (this.strokeWidth%2 == 1) | 
						|
			y += .5; | 
						|
		 | 
						|
		var rect = this.g.rect(x + (width - rectangleWidth) / 2, y + height - rectangleHeight - 3, rectangleWidth, rectangleHeight); | 
						|
		 | 
						|
		// plus inside rectangle | 
						|
		var cx = rect.attr("x") + rect.attr("width")/2; | 
						|
		var cy = rect.attr("y") + rect.attr("height")/2; | 
						|
		 | 
						|
		var line = this.g.path( | 
						|
			"M" + cx + " " + (cy+2) + "L" + cx + " " + (cy-2) +  | 
						|
			"M" + (cx-2) + " " + cy + "L" + (cx+2) + " " + cy | 
						|
		).attr({"stroke-width": this.strokeWidth}); | 
						|
		 | 
						|
	}, | 
						|
	 | 
						|
	drawActivityMarkers: function(x, y, width, height, multiInstanceSequential, multiInstanceParallel, collapsed){ | 
						|
		if (collapsed) { | 
						|
			if (!multiInstanceSequential && !multiInstanceParallel) { | 
						|
				this.drawCollapsedMarker(x, y, width, height); | 
						|
			} else { | 
						|
				this.drawCollapsedMarker(x - MARKER_WIDTH / 2 - 2, y, width, height); | 
						|
				if (multiInstanceSequential) { | 
						|
					console.log("is collapsed and multiInstanceSequential"); | 
						|
					this.drawMultiInstanceMarker(true, x + MARKER_WIDTH / 2 + 2, y, width, height); | 
						|
				} else if (multiInstanceParallel) { | 
						|
					console.log("is collapsed and multiInstanceParallel"); | 
						|
					this.drawMultiInstanceMarker(false, x + MARKER_WIDTH / 2 + 2, y, width, height); | 
						|
				} | 
						|
			} | 
						|
		} else { | 
						|
			if (multiInstanceSequential) { | 
						|
				console.log("is multiInstanceSequential"); | 
						|
				this.drawMultiInstanceMarker(true, x, y, width, height); | 
						|
			} else if (multiInstanceParallel) { | 
						|
				console.log("is multiInstanceParallel"); | 
						|
				this.drawMultiInstanceMarker(false, x, y, width, height); | 
						|
			} | 
						|
		} | 
						|
	}, | 
						|
	 | 
						|
	drawGateway: function(x, y, width, height) { | 
						|
		 | 
						|
		var rhombus = this.g.path(	"M" + x + " " + (y + (height / 2)) +  | 
						|
									"L" + (x + (width / 2)) + " " + (y + height) +  | 
						|
									"L" + (x + width) + " " + (y + (height / 2)) + | 
						|
									"L" + (x + (width / 2)) + " " + y + | 
						|
									"z" | 
						|
								); | 
						|
		 | 
						|
		// white shaddow | 
						|
		this.drawShaddow(rhombus); | 
						|
		 | 
						|
		rhombus.attr("stroke-width", this.strokeWidth); | 
						|
		rhombus.attr("stroke", Color.SlateGrey); | 
						|
		rhombus.attr({fill: Color.white}); | 
						|
		 | 
						|
		this.setContextToElement(rhombus); | 
						|
		 | 
						|
		return rhombus; | 
						|
	}, | 
						|
	 | 
						|
	drawParallelGateway: function(x, y, width, height) { | 
						|
	  this.g.setStart(); | 
						|
	   | 
						|
		// rhombus | 
						|
		this.drawGateway(x, y, width, height); | 
						|
 | 
						|
		// plus inside rhombus | 
						|
		var originalStroke = this.getStroke(); | 
						|
		this.setStroke(GATEWAY_TYPE_STROKE); | 
						|
		 | 
						|
		var plus = this.g.path( | 
						|
			"M" + (x + 10) + " " + (y + height / 2) + "L" + (x + width - 10) + " " + (y + height / 2) +	// horizontal | 
						|
			"M" + (x + width / 2) + " " + (y + height - 10) + "L" + (x + width / 2) + " " + (y + 10)	// vertical | 
						|
		); | 
						|
		plus.attr({"stroke-width": this.getStroke(), "stroke": this.getPaint()}); | 
						|
		 | 
						|
		this.setStroke(originalStroke); | 
						|
		 | 
						|
		var set = this.g.setFinish(); | 
						|
		this.addHandlers(set, x, y, width, height, "gateway"); | 
						|
	}, | 
						|
	 | 
						|
	drawExclusiveGateway: function(x, y, width, height) { | 
						|
	  this.g.setStart(); | 
						|
	   | 
						|
		// rhombus | 
						|
		var rhombus = this.drawGateway(x, y, width, height); | 
						|
 | 
						|
		var quarterWidth = width / 4; | 
						|
		var quarterHeight = height / 4; | 
						|
		 | 
						|
		// X inside rhombus | 
						|
		var originalStroke = this.getStroke(); | 
						|
		this.setStroke(GATEWAY_TYPE_STROKE); | 
						|
		 | 
						|
		var iks = this.g.path( | 
						|
			"M" + (x + quarterWidth + 3) + " " + (y + quarterHeight + 3) + "L" + (x + 3 * quarterWidth - 3) + " " + (y + 3 * quarterHeight - 3) +  | 
						|
			"M" + (x + quarterWidth + 3) + " " + (y + 3 * quarterHeight - 3) + "L" + (x + 3 * quarterWidth - 3) + " " + (y + quarterHeight + 3) | 
						|
		); | 
						|
		iks.attr({"stroke-width": this.getStroke(), "stroke": this.getPaint()}); | 
						|
		 | 
						|
		this.setStroke(originalStroke); | 
						|
		 | 
						|
		var set = this.g.setFinish(); | 
						|
    this.addHandlers(set, x, y, width, height, "gateway"); | 
						|
	}, | 
						|
	 | 
						|
	drawInclusiveGateway: function(x, y, width, height){ | 
						|
	  this.g.setStart(); | 
						|
	   | 
						|
		// rhombus | 
						|
		this.drawGateway(x, y, width, height); | 
						|
		 | 
						|
		var diameter = width / 4; | 
						|
		 | 
						|
		// circle inside rhombus | 
						|
		var originalStroke = this.getStroke(); | 
						|
		this.setStroke(GATEWAY_TYPE_STROKE); | 
						|
		var circle = this.g.ellipse(width/2 + x, height/2 + y, diameter, diameter); | 
						|
		circle.attr({"stroke-width": this.getStroke(), "stroke": this.getPaint()}); | 
						|
		 | 
						|
		this.setStroke(originalStroke); | 
						|
		 | 
						|
		var set = this.g.setFinish(); | 
						|
    this.addHandlers(set, x, y, width, height, "gateway"); | 
						|
	}, | 
						|
	 | 
						|
	drawEventBasedGateway: function(x, y, width, height){ | 
						|
	  this.g.setStart(); | 
						|
	   | 
						|
		// rhombus | 
						|
		this.drawGateway(x, y, width, height); | 
						|
		 | 
						|
		var diameter = width / 2; | 
						|
 | 
						|
	    // rombus inside rhombus | 
						|
	    var originalStroke = this.getStroke(); | 
						|
		this.setStroke(GATEWAY_TYPE_STROKE); | 
						|
	     | 
						|
	     | 
						|
	    // draw GeneralPath (polygon) | 
						|
	    var n=5; | 
						|
	    var angle = 2*Math.PI/n; | 
						|
	    var x1Points = []; | 
						|
	    var y1Points = []; | 
						|
		 | 
						|
		for ( var index = 0; index < n; index++ ) { | 
						|
			var v = index*angle - Math.PI/2; | 
						|
			x1Points[index] = x + parseInt(Math.round(width/2)) + parseInt(Math.round((width/4)*Math.cos(v))); | 
						|
        	y1Points[index] = y + parseInt(Math.round(height/2)) + parseInt(Math.round((height/4)*Math.sin(v))); | 
						|
		} | 
						|
		//g.drawPolygon(x1Points, y1Points, n); | 
						|
		 | 
						|
		var path = ""; | 
						|
		for ( var index = 0; index < n; index++ ) { | 
						|
			if (index == 0)  | 
						|
				path += "M"; | 
						|
			else  | 
						|
				path += "L"; | 
						|
			path += x1Points[index] + "," + y1Points[index]; | 
						|
		} | 
						|
		path += "z"; | 
						|
		var polygone = this.g.path(path); | 
						|
		polygone.attr("stroke-width", this.strokeWidth); | 
						|
		polygone.attr("stroke", this.getPaint()); | 
						|
		 | 
						|
		this.setStroke(originalStroke); | 
						|
		 | 
						|
		var set = this.g.setFinish(); | 
						|
    this.addHandlers(set, x, y, width, height, "gateway"); | 
						|
	}, | 
						|
	 | 
						|
	/* | 
						|
	*  drawMultiInstanceMarker | 
						|
	*  drawHighLight | 
						|
	*  highLightFlow | 
						|
	*/ | 
						|
	 | 
						|
	drawMultiInstanceMarker: function(sequential, x, y, width, height) { | 
						|
		var rectangleWidth = MARKER_WIDTH; | 
						|
		var rectangleHeight = MARKER_WIDTH; | 
						|
		 | 
						|
		// anti smoothing | 
						|
		if (this.strokeWidth%2 == 1) | 
						|
			x += .5;//, y += .5; | 
						|
			 | 
						|
		var lineX = x + (width - rectangleWidth) / 2; | 
						|
		var lineY = y + height - rectangleHeight - 3; | 
						|
		 | 
						|
		var originalStroke = this.getStroke(); | 
						|
		this.setStroke(MULTI_INSTANCE_STROKE); | 
						|
		 | 
						|
		if (sequential) { | 
						|
			var line = this.g.path( | 
						|
				"M" + lineX + " " + lineY + 							"L" + (lineX + rectangleWidth) + " " + lineY +  | 
						|
				"M" + lineX + " " + (lineY + rectangleHeight / 2) + 	"L" + (lineX + rectangleWidth) + " " + (lineY + rectangleHeight / 2) +  | 
						|
				"M" + lineX + " " + (lineY + rectangleHeight) + 		"L" + (lineX + rectangleWidth) + " " + (lineY + rectangleHeight) | 
						|
			).attr({"stroke-width": this.strokeWidth}); | 
						|
		} else { | 
						|
			var line = this.g.path( | 
						|
				"M" + lineX + " " + 							lineY + "L" + lineX + " " + 					(lineY + rectangleHeight) + | 
						|
				"M" + (lineX + rectangleWidth / 2) + " " + 	lineY + "L" + (lineX + rectangleWidth / 2) + " " + 	(lineY + rectangleHeight) +  | 
						|
				"M" + (lineX + rectangleWidth) + " " + 		lineY + "L" + (lineX + rectangleWidth) + " " + 		(lineY + rectangleHeight) | 
						|
			).attr({"stroke-width": this.strokeWidth}); | 
						|
		} | 
						|
		 | 
						|
		this.setStroke(originalStroke); | 
						|
	}, | 
						|
	 | 
						|
	drawHighLight: function(x, y, width, height){ | 
						|
		var originalPaint = this.getPaint(); | 
						|
		var originalStroke = this.getStroke(); | 
						|
		 | 
						|
		this.setPaint(HIGHLIGHT_COLOR); | 
						|
		this.setStroke(THICK_TASK_BORDER_STROKE); | 
						|
 | 
						|
		//var c = this.g.rect(x - width/2 - THICK_TASK_BORDER_STROKE, y - height/2 - THICK_TASK_BORDER_STROKE, width + THICK_TASK_BORDER_STROKE*2, height + THICK_TASK_BORDER_STROKE*2, 5); | 
						|
		var rect = this.g.rect(x - THICK_TASK_BORDER_STROKE, y - THICK_TASK_BORDER_STROKE, width + THICK_TASK_BORDER_STROKE*2, height + THICK_TASK_BORDER_STROKE*2, TASK_CORNER_ROUND); | 
						|
		rect.attr("stroke-width", this.strokeWidth); | 
						|
		rect.attr("stroke", this.getPaint()); | 
						|
		 | 
						|
		this.setPaint(originalPaint); | 
						|
		this.setStroke(originalStroke); | 
						|
	}, | 
						|
	 | 
						|
	highLightActivity: function(activityId){ | 
						|
		var shape = this.g.getById(activityId); | 
						|
		if (!shape) { | 
						|
			console.error("Activity " + activityId + " not found"); | 
						|
			return; | 
						|
		} | 
						|
		 | 
						|
		var contextObject = shape.data("contextObject"); | 
						|
		if (contextObject) | 
						|
			console.log("--> highLightActivity: ["+contextObject.getProperty("type")+"], activityId: " + contextObject.getId()); | 
						|
		else | 
						|
			console.log("--> highLightActivity: ", shape, shape.data("contextObject")); | 
						|
		 | 
						|
		shape.attr("stroke-width", THICK_TASK_BORDER_STROKE); | 
						|
		shape.attr("stroke", HIGHLIGHT_COLOR); | 
						|
	}, | 
						|
	 | 
						|
	highLightFlow: function(flowId){ | 
						|
		var shapeFlow = this.g.getById(flowId); | 
						|
		if (!shapeFlow) { | 
						|
			console.error("Flow " + flowId + " not found"); | 
						|
			return; | 
						|
		} | 
						|
		 | 
						|
		var contextObject = shapeFlow.data("contextObject"); | 
						|
		if (contextObject) | 
						|
			console.log("--> highLightFlow: ["+contextObject.id+"] " + contextObject.flow); | 
						|
		//console.log("--> highLightFlow: ", flow.flow, flow.data("set")); | 
						|
		 | 
						|
		var st = shapeFlow.data("set"); | 
						|
		 | 
						|
		st.attr("stroke-width", SEQUENCEFLOW_HIGHLIGHT_STROKE); | 
						|
		st.attr("stroke", HIGHLIGHT_COLOR); | 
						|
		var withArrowHead = shapeFlow.data("withArrowHead"); | 
						|
		if (withArrowHead) | 
						|
			st[1].attr("fill", HIGHLIGHT_COLOR); | 
						|
		 | 
						|
		st.forEach(function(el){ | 
						|
			//console.log("---->", el); | 
						|
			//el.attr("") | 
						|
		}); | 
						|
	}, | 
						|
	 | 
						|
 | 
						|
	_drawClock: function(cx, cy, width, height){ | 
						|
		 | 
						|
		var circle = this.g.ellipse(cx, cy, 1, 1).attr({stroke:"none", fill: Color.get(232, 239, 241)}); | 
						|
		//var c = this.g.ellipse(cx, cy, width, height).attr({stroke:"none", fill: Color.red}); | 
						|
		//x = cx - width/2; | 
						|
		//y = cy - height/2; | 
						|
	 | 
						|
		var clock = this.g.path( | 
						|
		/* outer circle */ "M15.5,2.374		C8.251,2.375,2.376,8.251,2.374,15.5		C2.376,22.748,8.251,28.623,15.5,28.627c7.249-0.004,13.124-5.879,13.125-13.127C28.624,8.251,22.749,2.375,15.5,2.374z" + | 
						|
		/* inner circle */ "M15.5,26.623	C8.909,26.615,4.385,22.09,4.375,15.5	C4.385,8.909,8.909,4.384,15.5,4.374c4.59,0.01,11.115,3.535,11.124,11.125C26.615,22.09,22.091,26.615,15.5,26.623z" + | 
						|
		/*  9 */ "M8.625,15.5c-0.001-0.552-0.448-0.999-1.001-1c-0.553,0-1,0.448-1,1c0,0.553,0.449,1,1,1C8.176,16.5,8.624,16.053,8.625,15.5z" + | 
						|
		/*  8 */ "M8.179,18.572c-0.478,0.277-0.642,0.889-0.365,1.367c0.275,0.479,0.889,0.641,1.365,0.365c0.479-0.275,0.643-0.887,0.367-1.367C9.27,18.461,8.658,18.297,8.179,18.572z" + | 
						|
		/* 10 */ "M9.18,10.696c-0.479-0.276-1.09-0.112-1.366,0.366s-0.111,1.09,0.365,1.366c0.479,0.276,1.09,0.113,1.367-0.366C9.821,11.584,9.657,10.973,9.18,10.696z" + | 
						|
		/*  2 */ "M22.822,12.428c0.478-0.275,0.643-0.888,0.366-1.366c-0.275-0.478-0.89-0.642-1.366-0.366c-0.479,0.278-0.642,0.89-0.366,1.367C21.732,12.54,22.344,12.705,22.822,12.428z" + | 
						|
		/*  7 */ "M12.062,21.455c-0.478-0.275-1.089-0.111-1.366,0.367c-0.275,0.479-0.111,1.09,0.366,1.365c0.478,0.277,1.091,0.111,1.365-0.365C12.704,22.344,12.54,21.732,12.062,21.455z" + | 
						|
		/* 11 */ "M12.062,9.545c0.479-0.276,0.642-0.888,0.366-1.366c-0.276-0.478-0.888-0.642-1.366-0.366s-0.642,0.888-0.366,1.366C10.973,9.658,11.584,9.822,12.062,9.545z" + | 
						|
		/*  4 */ "M22.823,18.572c-0.48-0.275-1.092-0.111-1.367,0.365c-0.275,0.479-0.112,1.092,0.367,1.367c0.477,0.275,1.089,0.113,1.365-0.365C23.464,19.461,23.3,18.848,22.823,18.572z" + | 
						|
		/*  2 */ "M19.938,7.813c-0.477-0.276-1.091-0.111-1.365,0.366c-0.275,0.48-0.111,1.091,0.366,1.367s1.089,0.112,1.366-0.366C20.581,8.702,20.418,8.089,19.938,7.813z" + | 
						|
		/*  3 */ "M23.378,14.5c-0.554,0.002-1.001,0.45-1.001,1c0.001,0.552,0.448,1,1.001,1c0.551,0,1-0.447,1-1C24.378,14.949,23.929,14.5,23.378,14.5z" + | 
						|
		/* arrows */ "M15.501,6.624c-0.552,0-1,0.448-1,1l-0.466,7.343l-3.004,1.96c-0.478,0.277-0.642,0.889-0.365,1.365c0.275,0.479,0.889,0.643,1.365,0.367l3.305-1.676C15.39,16.99,15.444,17,15.501,17c0.828,0,1.5-0.671,1.5-1.5l-0.5-7.876C16.501,7.072,16.053,6.624,15.501,6.624z" + | 
						|
		/*  9 */ "M15.501,22.377c-0.552,0-1,0.447-1,1s0.448,1,1,1s1-0.447,1-1S16.053,22.377,15.501,22.377z" + | 
						|
		/*  8 */ "M18.939,21.455c-0.479,0.277-0.643,0.889-0.366,1.367c0.275,0.477,0.888,0.643,1.366,0.365c0.478-0.275,0.642-0.889,0.366-1.365C20.028,21.344,19.417,21.18,18.939,21.455z" + | 
						|
		""); | 
						|
		clock.attr({fill: Color.black, stroke: "none"}); | 
						|
		//clock.transform("t " + (cx-29.75/2) + " " + (cy-29.75/2)); | 
						|
		//clock.transform("...s 0.85"); | 
						|
		 | 
						|
		//clock.transform("...s " + .85 + " " + .85); | 
						|
		clock.transform("t " + (-2.374) + " " + (-2.374)	); | 
						|
		clock.transform("...t -" + (15.5-2.374) + " -" + (15.5-2.374)	); | 
						|
		clock.transform("...s " + 1*(width/35) + " " + 1*(height/35)); | 
						|
		clock.transform("...T " + cx + " " + cy); | 
						|
		//clock.transform("t " + (cx-width/2) + " " + (cy-height/2)); | 
						|
		 | 
						|
		//console.log(".getBBox(): ", clock.getBBox()); | 
						|
		//console.log(".attr(): ", c.attrs); | 
						|
		circle.attr("rx", clock.getBBox().width/2); | 
						|
		circle.attr("ry", clock.getBBox().height/2); | 
						|
		 | 
						|
		//return circle | 
						|
	}, | 
						|
	 | 
						|
	_drawPentagon: function(cx, cy, width, height, filled){ | 
						|
		// draw GeneralPath (polygon) | 
						|
	    var n=5; | 
						|
	    var angle = 2*Math.PI/n; | 
						|
	    var waypoints = []; | 
						|
		 | 
						|
		for ( var index = 0; index < n; index++ ) { | 
						|
			var v = index*angle - Math.PI/2; | 
						|
			var point = {}; | 
						|
			point.x = -width*1.2/2 + parseInt(Math.round(width*1.2/2)) + parseInt(Math.round((width*1.2/4)*Math.cos(v))); | 
						|
        	point.y = -height*1.2/2 + parseInt(Math.round(height*1.2/2)) + parseInt(Math.round((height*1.2/4)*Math.sin(v))); | 
						|
			waypoints[index] = point; | 
						|
		} | 
						|
		 | 
						|
		var polygone = new Polygone(waypoints, this.getStroke()); | 
						|
		polygone.element = this.g.path(polygone.path); | 
						|
		if (filled) | 
						|
			polygone.element.attr("fill", Color.black); | 
						|
		else | 
						|
			polygone.element.attr("fill", Color.white); | 
						|
		 | 
						|
		polygone.element.transform("s " + 1*(width/35) + " " + 1*(height/35)); | 
						|
		polygone.element.transform("...T " + cx + " " + cy); | 
						|
	}, | 
						|
	 | 
						|
	//_drawMultilineText: function(text, x, y, boxWidth, boxHeight, textAnchor) { | 
						|
	_drawMultilineText: function(text, x, y, boxWidth, boxHeight, verticalAlign, horizontalAlign) { | 
						|
		if (!text || text == "")  | 
						|
			return; | 
						|
			 | 
						|
		// Autostretch boxHeight if boxHeight is 0 | 
						|
		if (boxHeight == 0) | 
						|
		  verticalAlign = MULTILINE_VERTICAL_ALIGN_TOP;	   | 
						|
	 | 
						|
		//var TEXT_PADDING = 3; | 
						|
		var width = boxWidth; | 
						|
		if (boxHeight) | 
						|
			var height = boxHeight; | 
						|
	 | 
						|
		var layouts = []; | 
						|
		 | 
						|
		//var font = {font: "11px Arial", opacity: 1, "fill": LABEL_COLOR}; | 
						|
		var font = this.getFont(); | 
						|
		var measurer = new LineBreakMeasurer(this.g, x, y, text, font); | 
						|
		var lineHeight = measurer.rafaelTextObject.getBBox().height; | 
						|
		//console.log("text: ", text.replace(/\n/g, "?")); | 
						|
		 | 
						|
		if (height) { | 
						|
			var availableLinesCount = parseInt(height/lineHeight); | 
						|
			//console.log("availableLinesCount: " + availableLinesCount); | 
						|
		} | 
						|
		 | 
						|
		var i = 1; | 
						|
		while (measurer.getPosition() < measurer.text.getEndIndex()) { | 
						|
			var layout = measurer.nextLayout(width); | 
						|
			//console.log("LAYOUT: " + layout + ", getPosition: " + measurer.getPosition()); | 
						|
			 | 
						|
			if (layout != null) { | 
						|
				// TODO: and check if measurer has next layout. If no then don't draw  dots | 
						|
				if (!availableLinesCount || i < availableLinesCount) { | 
						|
					layouts.push(layout); | 
						|
				} else { | 
						|
					layouts.push(this.fitTextToWidth(layout + "...", boxWidth)); | 
						|
					break; | 
						|
				} | 
						|
			} | 
						|
			i++; | 
						|
		}; | 
						|
		//console.log(layouts); | 
						|
		 | 
						|
		measurer.rafaelTextObject.attr({"text": layouts.join("\n")}); | 
						|
		 | 
						|
		if (horizontalAlign) | 
						|
			measurer.rafaelTextObject.attr({"text-anchor": horizontalAlign}); // end, middle, start | 
						|
			 | 
						|
		var bb = measurer.rafaelTextObject.getBBox(); | 
						|
		// TODO: there is somethin wrong with wertical align. May be: measurer.rafaelTextObject.attr({"y": y + height/2 - bb.height/2}) | 
						|
		measurer.rafaelTextObject.attr({"y": y + bb.height/2}); | 
						|
		//var bb = measurer.rafaelTextObject.getBBox(); | 
						|
		 | 
						|
		if (measurer.rafaelTextObject.attr("text-anchor") == MULTILINE_HORIZONTAL_ALIGN_MIDDLE ) | 
						|
			measurer.rafaelTextObject.attr("x",  x +  boxWidth/2); | 
						|
		else if (measurer.rafaelTextObject.attr("text-anchor") == MULTILINE_HORIZONTAL_ALIGN_RIGHT ) | 
						|
			measurer.rafaelTextObject.attr("x",  x +  boxWidth); | 
						|
		 | 
						|
		var boxStyle = {stroke: Color.LightSteelBlue2, "stroke-width": 1.0, "stroke-dasharray": "- "}; | 
						|
		//var box = this.g.rect(x+.5, y + .5, width, height).attr(boxStyle); | 
						|
		var textAreaCX = x + boxWidth/2; | 
						|
				var height = boxHeight; | 
						|
				if (!height) height = bb.height; | 
						|
				var textAreaCY = y + height/2; | 
						|
				var dotLeftTop = this.g.ellipse(x, y, 3, 3).attr({"stroke-width": 0, fill: Color.LightSteelBlue, stroke: "none"}).hide(); | 
						|
				var dotCenter = this.g.ellipse(textAreaCX, textAreaCY, 3, 3).attr({fill: Color.LightSteelBlue2, stroke: "none"}).hide(); | 
						|
 | 
						|
				/* | 
						|
				// real bbox | 
						|
				var bb = measurer.rafaelTextObject.getBBox(); | 
						|
				var rect = paper.rect(bb.x+.5, bb.y + .5, bb.width, bb.height).attr({"stroke-width": 1}); | 
						|
				*/ | 
						|
				var rect = this.g.rect(x, y, boxWidth, height).attr({"stroke-width": 1}).attr(boxStyle).hide(); | 
						|
				var debugSet = this.g.set(); | 
						|
				debugSet.push(dotLeftTop, dotCenter, rect); | 
						|
				//debugSet.show(); | 
						|
	}, | 
						|
	 | 
						|
	drawTextAnnotation: function(text, x, y, width, height){ | 
						|
		var lineLength = 18; | 
						|
		var path = []; | 
						|
		  path.push(["M", x + lineLength, y]); | 
						|
		  path.push(["L", x, y]); | 
						|
		  path.push(["L", x, y + height]); | 
						|
		  path.push(["L", x + lineLength, y + height]); | 
						|
		   | 
						|
		  path.push(["L", x + lineLength, y + height -1]); | 
						|
		  path.push(["L", x + 1, y + height -1]); | 
						|
		  path.push(["L", x + 1, y + 1]); | 
						|
		  path.push(["L", x + lineLength, y + 1]); | 
						|
		  path.push(["z"]); | 
						|
	 | 
						|
		var textAreaLines = this.g.path(path); | 
						|
		 | 
						|
	  var boxWidth = width - (2 * ANNOTATION_TEXT_PADDING); | 
						|
      var boxHeight = height - (2 * ANNOTATION_TEXT_PADDING); | 
						|
      var boxX = x + width/2 - boxWidth/2; | 
						|
      var boxY = y + height/2 - boxHeight/2; | 
						|
       | 
						|
      // for debug | 
						|
          var rectStyle = {stroke: Color(112, 146, 190), "stroke-width": 1.0, "stroke-dasharray": "- "}; | 
						|
          var r = this.g.rect(boxX, boxY, boxWidth, boxHeight).attr(rectStyle); | 
						|
	  // | 
						|
       | 
						|
	  this.drawAnnotationText(text, boxX, boxY, boxWidth, boxHeight); | 
						|
	}, | 
						|
	 | 
						|
	drawLabel111111111: function(text, x, y, width, height, labelAttrs){ | 
						|
		var  debug = false; | 
						|
		 | 
						|
		// text | 
						|
		if (text != null && text != undefined && text != "") { | 
						|
			var attr = LABEL_FONT; | 
						|
			 | 
						|
			//console.log("x", x, "y", y, "width", width, "height", height ); | 
						|
			 | 
						|
			wrappedText = text; | 
						|
			if (labelAttrs && labelAttrs.wrapWidth) { | 
						|
				wrappedText = this.wrapTextToWidth(wrappedText, labelAttrs.wrapWidth); | 
						|
			} | 
						|
			var realWidth = this.getStringWidth(wrappedText, attr); | 
						|
			var realHeight = this.getStringHeight(wrappedText, attr); | 
						|
			 | 
						|
			var textAreaCX = x + width/2; | 
						|
			var textAreaCY = y + 3 + height + this.getStringHeight(wrappedText, attr)/2; | 
						|
			 | 
						|
			var textX = textAreaCX; | 
						|
			var textY = textAreaCY; | 
						|
 | 
						|
			var textAttrs = {}; | 
						|
			if (labelAttrs && labelAttrs.align) { | 
						|
				switch (labelAttrs.align) { | 
						|
					case "left":  | 
						|
						textAttrs["text-anchor"] = "start";  | 
						|
						textX = textX - realWidth/2; | 
						|
					break; | 
						|
					case "center":  | 
						|
						textAttrs["text-anchor"] = "middle";  | 
						|
					break; | 
						|
					case "right":  | 
						|
						textAttrs["text-anchor"] = "end";  | 
						|
						textX = textX + realWidth/2; | 
						|
					break; | 
						|
				} | 
						|
			} | 
						|
			if (labelAttrs && labelAttrs.wrapWidth) { | 
						|
				if (true) { | 
						|
					// Draw frameborder | 
						|
					var textAreaStyle = {stroke: Color.LightSteelBlue2, "stroke-width": 1.0, "stroke-dasharray": "- "}; | 
						|
					var textAreaX = textAreaCX - realWidth/2; | 
						|
					var textAreaY = textAreaCY+.5 - realHeight/2; | 
						|
					var textArea = this.g.rect(textAreaX, textAreaY, realWidth, realHeight).attr(textAreaStyle); | 
						|
					 | 
						|
					var textAreaLines = this.g.path("M" + textAreaX + " " + textAreaY + "L" + (textAreaX+realWidth) + " " + (textAreaY+realHeight) + "M" +  + (textAreaX+realWidth) + " " + textAreaY + "L" + textAreaX + " " + (textAreaY+realHeight)); | 
						|
					textAreaLines.attr(textAreaStyle); | 
						|
					 | 
						|
					this.g.ellipse(textAreaCX, textAreaCY, 3, 3).attr({fill: Color.LightSteelBlue2, stroke: "none"}); | 
						|
				} | 
						|
			} | 
						|
			 | 
						|
			var label = this.g.text(textX, textY, wrappedText).attr(attr).attr(textAttrs); | 
						|
			//label.id = Raphael.createUUID(); | 
						|
			//console.log("label ", label.id, ", ", wrappedText); | 
						|
			 | 
						|
			if (this.fontSmoothing) { | 
						|
				label.attr({stroke: LABEL_COLOR, "stroke-width":.4}); | 
						|
			} | 
						|
			 | 
						|
			// debug | 
						|
			if (debug) { | 
						|
				var imageAreaStyle = {stroke: Color.grey61, "stroke-width": 1.0, "stroke-dasharray": "- "}; | 
						|
				var imageArea = this.g.rect(x+.5, y+.5, width, height).attr(imageAreaStyle); | 
						|
				var imageAreaLines = this.g.path("M" + x + " " + y + "L" + (x+width) + " " + (y+height) + "M" +  + (x+width) + " " + y + "L" + x + " " + (y+height)); | 
						|
				imageAreaLines.attr(imageAreaStyle); | 
						|
				var dotStyle = {fill: Color.Coral, stroke: "none"}; | 
						|
				this.g.ellipse(x, y, 3, 3).attr(dotStyle); | 
						|
				this.g.ellipse(x+width, y, 2, 2).attr(dotStyle); | 
						|
				this.g.ellipse(x+width, y+height, 2, 2).attr(dotStyle); | 
						|
				this.g.ellipse(x, y+height, 2, 2).attr(dotStyle); | 
						|
			} | 
						|
			 | 
						|
			return label; | 
						|
		} | 
						|
	}, | 
						|
	 | 
						|
	vvoid: function(){} | 
						|
};
 | 
						|
 |