1 (function(global){	// BEGIN CLOSURE
  2 
  3 var Joint = global.Joint,
  4      Element = Joint.dia.Element,
  5      point = Joint.point;
  6 
  7 /**
  8  * @name Joint.dia.erd
  9  * @namespace Holds functionality related to Entity-relationship diagrams.
 10  */
 11 var erd = Joint.dia.erd = {};
 12 
 13 /**
 14  * Predefined arrow. You are free to use this arrow as the option parameter to joint method.
 15  * Implements Chen-style cardinality notation.
 16  * @name Joint.dia.erd.arrow
 17  * @memberOf Joint.dia.erd
 18  * @example
 19  * var arrow = Joint.dia.erd.arrow;
 20  */
 21 erd.arrow = {
 22     startArrow: {type: 'none'},
 23     endArrow: {type: 'none'},
 24     attrs: {"stroke-dasharray": "none"}
 25 };
 26 
 27 erd.toMany = {
 28     startArrow: {type: 'none'},
 29     endArrow: {type: 'none'},
 30     attrs: {"stroke-dasharray": "none"},
 31     label: 'n',
 32     labelAttrs: { position: -10, offset: -10 }
 33 };
 34 
 35 erd.manyTo = {
 36     startArrow: {type: 'none'},
 37     endArrow: {type: 'none'},
 38     attrs: {"stroke-dasharray": "none"},
 39     label: 'n',
 40     labelAttrs: { position: 10, offset: -10 }
 41 };
 42 
 43 erd.toOne = {
 44     startArrow: {type: 'none'},
 45     endArrow: {type: 'none'},
 46     attrs: {"stroke-dasharray": "none"},
 47     label: '1',
 48     labelAttrs: { position: -10, offset: -10 }
 49 };
 50 
 51 erd.oneTo = {
 52     startArrow: {type: 'none'},
 53     endArrow: {type: 'none'},
 54     attrs: {"stroke-dasharray": "none"},
 55     label: '1',
 56     labelAttrs: { position: 10, offset: -10 }
 57 };
 58 
 59 erd.oneToMany = {
 60     startArrow: {type: 'none'},
 61     endArrow: {type: 'none'},
 62     attrs: {"stroke-dasharray": "none"},
 63     label: ['1', 'n'],
 64     labelAttrs: [ { position: 10, offset: -10 }, { position: -10, offset: -10 } ]
 65 };
 66 
 67 erd.manyToOne = {
 68     startArrow: {type: 'none'},
 69     endArrow: {type: 'none'},
 70     attrs: {"stroke-dasharray": "none"},
 71     label: ['n', '1'],
 72     labelAttrs: [ { position: 10, offset: -10 }, { position: -10, offset: -10 } ]
 73 };
 74 
 75 
 76 /**
 77  * ERD Entity and Weak Entity.
 78  * @methodOf Joint.dia.erd
 79  */
 80 erd.Entity = Element.extend({
 81     object: 'Entity',
 82     module: 'erd',
 83     init: function(properties) {
 84         var p = Joint.DeepSupplement(this.properties, properties, {
 85             attrs: { fill: 'lightgreen', stroke: '#008e09', 'stroke-width': 2 },
 86             label: '',
 87             labelAttrs: { 'font-weight': 'bold' },
 88             shadow: true,
 89             weak: false,        // Weak Entity?
 90             padding: 5
 91         });
 92         this.setWrapper(this.paper.rect(p.rect.x, p.rect.y, p.rect.width, p.rect.height).attr(p.attrs));
 93 
 94         if (p.weak) {
 95             this.addInner(this.paper.rect(p.rect.x + p.padding, p.rect.y + p.padding, p.rect.width - 2*p.padding, p.rect.height - 2*p.padding).attr(p.attrs));
 96         }
 97         this.addInner(this.getLabelElement());
 98     },
 99     getLabelElement: function() {
100 	var p = this.properties,
101 	    bb = this.wrapper.getBBox(),
102 	    t = this.paper.text(bb.x + bb.width/2, bb.y + bb.height/2, p.label).attr(p.labelAttrs || {}),
103 	    tbb = t.getBBox();
104 	t.translate(bb.x - tbb.x + p.labelOffsetX,
105 		    bb.y - tbb.y + p.labelOffsetY);
106 	return t;
107     }
108 });
109 
110 /**
111  * ERD Relationship.
112  * @methodOf Joint.dia.erd
113  */
114 erd.Relationship = Element.extend({
115     object: 'Relationship',
116     module: 'erd',
117     init: function(properties) {
118         var p = Joint.DeepSupplement(this.properties, properties, {
119             attrs: { rotation: 45, fill: 'lightblue', stroke: '#000d5b', 'stroke-width': 2 },
120             label: '',
121             labelAttrs: { 'font-weight': 'bold' }
122         });
123         this.setWrapper(this.paper.rect(p.rect.x, p.rect.y, p.rect.width, p.rect.height).attr(p.attrs));
124         this.addInner(this.getLabelElement());
125     },
126     getLabelElement: function() {
127 	var p = this.properties,
128 	    bb = this.wrapper.getBBox(),
129 	    t = this.paper.text(bb.x + bb.width/2, bb.y + bb.height/2, p.label).attr(p.labelAttrs || {}),
130 	    tbb = t.getBBox();
131 	t.translate(bb.x - tbb.x + p.labelOffsetX,
132 		    bb.y - tbb.y + p.labelOffsetY);
133 	return t;
134     }
135 });
136 
137 /**
138  * ERD Attribute, Key Attribute, Multivalued Attribute and Derived Attribute.
139  * @methodOf Joint.dia.erd
140  */
141 erd.Attribute = Element.extend({
142     object: 'Attribute',
143     module: 'erd',
144     init: function(properties) {
145         var p = Joint.DeepSupplement(this.properties, properties, {
146             attrs: { fill: 'red', opacity: (properties.primaryKey ? 0.8 : 0.5), 
147                      stroke: '#5b0001', 'stroke-width': 2, 
148                      'stroke-dasharray': (properties.derived ? '.' : 'none') },
149             label: '',
150             labelAttrs: { 'font-weight': 'bold' },
151             multivalued: false,
152             derived: false,
153             padding: 5
154         });
155         this.setWrapper(this.paper.ellipse(p.ellipse.x, p.ellipse.y, p.ellipse.rx, p.ellipse.ry).attr(p.attrs));
156         if (p.multivalued) {
157             this.addInner(this.paper.ellipse(p.ellipse.x, p.ellipse.y, p.ellipse.rx - p.padding, p.ellipse.ry - p.padding).attr(p.attrs));
158         }
159         this.addInner(this.getLabelElement());
160     },
161     getLabelElement: function() {
162 	var p = this.properties,
163 	    bb = this.wrapper.getBBox(),
164 	    t = this.paper.text(bb.x + bb.width/2, bb.y + bb.height/2, p.label).attr(p.labelAttrs || {}),
165 	    tbb = t.getBBox();
166 	t.translate(bb.x - tbb.x + p.labelOffsetX,
167 		    bb.y - tbb.y + p.labelOffsetY);
168 	return t;
169     }
170 });
171 
172 })(this);	// END CLOSURE
173