/** * 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(){} };