import { assign } from 'min-dash'; import inherits from 'inherits'; import Refs from 'object-refs'; var parentRefs = new Refs({ name: 'children', enumerable: true, collection: true }, { name: 'parent' }), labelRefs = new Refs({ name: 'labels', enumerable: true, collection: true }, { name: 'labelTarget' }), attacherRefs = new Refs({ name: 'attachers', collection: true }, { name: 'host' }), outgoingRefs = new Refs({ name: 'outgoing', collection: true }, { name: 'source' }), incomingRefs = new Refs({ name: 'incoming', collection: true }, { name: 'target' }); /** * @namespace djs.model */ /** * @memberOf djs.model */ /** * The basic graphical representation * * @class * * @abstract */ export function Base() { /** * The object that backs up the shape * * @name Base#businessObject * @type Object */ Object.defineProperty(this, 'businessObject', { writable: true }); /** * Single label support, will mapped to multi label array * * @name Base#label * @type Object */ Object.defineProperty(this, 'label', { get: function() { return this.labels[0]; }, set: function(newLabel) { var label = this.label, labels = this.labels; if (!newLabel && label) { labels.remove(label); } else { labels.add(newLabel, 0); } } }); /** * The parent shape * * @name Base#parent * @type Shape */ parentRefs.bind(this, 'parent'); /** * The list of labels * * @name Base#labels * @type Label */ labelRefs.bind(this, 'labels'); /** * The list of outgoing connections * * @name Base#outgoing * @type Array */ outgoingRefs.bind(this, 'outgoing'); /** * The list of incoming connections * * @name Base#incoming * @type Array */ incomingRefs.bind(this, 'incoming'); } /** * A graphical object * * @class * @constructor * * @extends Base */ export function Shape() { Base.call(this); /** * The list of children * * @name Shape#children * @type Array */ parentRefs.bind(this, 'children'); /** * @name Shape#host * @type Shape */ attacherRefs.bind(this, 'host'); /** * @name Shape#attachers * @type Shape */ attacherRefs.bind(this, 'attachers'); } inherits(Shape, Base); /** * A root graphical object * * @class * @constructor * * @extends Shape */ export function Root() { Shape.call(this); } inherits(Root, Shape); /** * A label for an element * * @class * @constructor * * @extends Shape */ export function Label() { Shape.call(this); /** * The labeled element * * @name Label#labelTarget * @type Base */ labelRefs.bind(this, 'labelTarget'); } inherits(Label, Shape); /** * A connection between two elements * * @class * @constructor * * @extends Base */ export function Connection() { Base.call(this); /** * The element this connection originates from * * @name Connection#source * @type Base */ outgoingRefs.bind(this, 'source'); /** * The element this connection points to * * @name Connection#target * @type Base */ incomingRefs.bind(this, 'target'); } inherits(Connection, Base); var types = { connection: Connection, shape: Shape, label: Label, root: Root }; /** * Creates a new model element of the specified type * * @method create * * @example * * var shape1 = Model.create('shape', { x: 10, y: 10, width: 100, height: 100 }); * var shape2 = Model.create('shape', { x: 210, y: 210, width: 100, height: 100 }); * * var connection = Model.create('connection', { waypoints: [ { x: 110, y: 55 }, {x: 210, y: 55 } ] }); * * @param {String} type lower-cased model name * @param {Object} attrs attributes to initialize the new model instance with * * @return {Base} the new model instance */ export function create(type, attrs) { var Type = types[type]; if (!Type) { throw new Error('unknown type: <' + type + '>'); } return assign(new Type(), attrs); }