UNPKG

@progress/kendo-ui

Version:

This package is part of the [Kendo UI for jQuery](http://www.telerik.com/kendo-ui) suite.

5,407 lines 206 kB
module.exports =
/******/ (function(modules) { // webpackBootstrap
/******/ 	// The module cache
/******/ 	var installedModules = {};

/******/ 	// The require function
/******/ 	function __webpack_require__(moduleId) {

/******/ 		// Check if module is in cache
/******/ 		if(installedModules[moduleId])
/******/ 			return installedModules[moduleId].exports;

/******/ 		// Create a new module (and put it into the cache)
/******/ 		var module = installedModules[moduleId] = {
/******/ 			exports: {},
/******/ 			id: moduleId,
/******/ 			loaded: false
/******/ 		};

/******/ 		// Execute the module function
/******/ 		modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);

/******/ 		// Flag the module as loaded
/******/ 		module.loaded = true;

/******/ 		// Return the exports of the module
/******/ 		return module.exports;
/******/ 	}


/******/ 	// expose the modules object (__webpack_modules__)
/******/ 	__webpack_require__.m = modules;

/******/ 	// expose the module cache
/******/ 	__webpack_require__.c = installedModules;

/******/ 	// __webpack_public_path__
/******/ 	__webpack_require__.p = "";

/******/ 	// Load entry module and return exports
/******/ 	return __webpack_require__(0);
/******/ })
/************************************************************************/
/******/ ({

/***/ 0:
/***/ (function(module, exports, __webpack_require__) {

	module.exports = __webpack_require__(867);


/***/ }),

/***/ 3:
/***/ (function(module, exports) {

	module.exports = function() { throw new Error("define cannot be used indirect"); };


/***/ }),

/***/ 856:
/***/ (function(module, exports) {

	module.exports = require("../../kendo.data");

/***/ }),

/***/ 857:
/***/ (function(module, exports) {

	module.exports = require("../../kendo.dataviz.core");

/***/ }),

/***/ 858:
/***/ (function(module, exports) {

	module.exports = require("../../kendo.dataviz.themes");

/***/ }),

/***/ 867:
/***/ (function(module, exports, __webpack_require__) {

	var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;(function (f, define) {
	    !(__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__(856), __webpack_require__(869), __webpack_require__(870),
	           __webpack_require__(871),
	           __webpack_require__(872),
	           __webpack_require__(868),
	           __webpack_require__(857),
	           __webpack_require__(858),
	           __webpack_require__(873),
	           __webpack_require__(874),
	           __webpack_require__(875) ], __WEBPACK_AMD_DEFINE_FACTORY__ = (f), __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? (__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
	})(function () {

	    (function ($, undefined) {
	        // Imports ================================================================
	        var dataviz = kendo.dataviz,
	            draw = kendo.drawing,
	            geom = kendo.geometry,
	            diagram = dataviz.diagram,
	            Widget = kendo.ui.Widget,
	            Class = kendo.Class,
	            proxy = $.proxy,
	            deepExtend = kendo.deepExtend,
	            outerWidth = kendo._outerWidth,
	            outerHeight = kendo._outerHeight,
	            extend = $.extend,
	            HierarchicalDataSource = kendo.data.HierarchicalDataSource,
	            Canvas = diagram.Canvas,
	            Group = diagram.Group,
	            Rectangle = diagram.Rectangle,
	            Circle = diagram.Circle,
	            CompositeTransform = diagram.CompositeTransform,
	            Rect = diagram.Rect,
	            Path = diagram.Path,
	            DeleteShapeUnit = diagram.DeleteShapeUnit,
	            DeleteConnectionUnit = diagram.DeleteConnectionUnit,
	            TextBlock = diagram.TextBlock,
	            Image = diagram.Image,
	            Point = diagram.Point,
	            Intersect = diagram.Intersect,
	            ConnectionEditAdorner = diagram.ConnectionEditAdorner,
	            UndoRedoService = diagram.UndoRedoService,
	            ToolService = diagram.ToolService,
	            Selector = diagram.Selector,
	            ResizingAdorner = diagram.ResizingAdorner,
	            ConnectorsAdorner = diagram.ConnectorsAdorner,
	            Cursors = diagram.Cursors,
	            Utils = diagram.Utils,
	            Observable = kendo.Observable,
	            ToBackUnit = diagram.ToBackUnit,
	            ToFrontUnit = diagram.ToFrontUnit,
	            PolylineRouter = diagram.PolylineRouter,
	            CascadingRouter = diagram.CascadingRouter,
	            isUndefined = Utils.isUndefined,
	            isDefined = Utils.isDefined,
	            defined = draw.util.defined,
	            isArray = $.isArray,
	            isFunction = kendo.isFunction,
	            isString = Utils.isString,
	            isPlainObject = $.isPlainObject,

	            math = Math;

	        // Constants ==============================================================
	        var NS = ".kendoDiagram",
	            CASCADING = "cascading",
	            ITEMBOUNDSCHANGE = "itemBoundsChange",
	            CHANGE = "change",
	            CLICK = "click",
	            DRAG = "drag",
	            DRAG_END = "dragEnd",
	            DRAG_START = "dragStart",
	            MOUSE_ENTER = "mouseEnter",
	            MOUSE_LEAVE = "mouseLeave",
	            ERROR = "error",
	            AUTO = "Auto",
	            TOP = "Top",
	            RIGHT = "Right",
	            LEFT = "Left",
	            BOTTOM = "Bottom",
	            MAXINT = 9007199254740992,
	            SELECT = "select",
	            ITEMROTATE = "itemRotate",
	            PAN = "pan",
	            ZOOM_START = "zoomStart",
	            ZOOM_END = "zoomEnd",
	            NONE = "none",
	            DEFAULT_CANVAS_WIDTH = 600,
	            DEFAULT_CANVAS_HEIGHT = 600,
	            DEFAULT_SHAPE_TYPE = "rectangle",
	            DEFAULT_SHAPE_WIDTH = 100,
	            DEFAULT_SHAPE_HEIGHT = 100,
	            DEFAULT_SHAPE_MINWIDTH = 20,
	            DEFAULT_SHAPE_MINHEIGHT = 20,
	            DEFAULT_SHAPE_POSITION = 0,
	            DEFAULT_CONNECTION_BACKGROUND = "Yellow",
	            MAX_VALUE = Number.MAX_VALUE,
	            MIN_VALUE = -Number.MAX_VALUE,
	            ABSOLUTE = "absolute",
	            TRANSFORMED = "transformed",
	            ROTATED = "rotated",
	            TRANSPARENT = "transparent",
	            WIDTH = "width",
	            HEIGHT = "height",
	            X = "x",
	            Y = "y",
	            MOUSEWHEEL_NS = "DOMMouseScroll" + NS + " mousewheel" + NS,
	            MOBILE_ZOOM_RATE = 0.05,
	            MOBILE_PAN_DISTANCE = 5,
	            BUTTON_TEMPLATE = '<a class="k-button k-button-icontext #=className#" href="\\#"><span class="#=iconClass# #=imageClass#"></span>#=text#</a>',
	            CONNECTION_CONTENT_OFFSET = 5;

	        diagram.DefaultConnectors = [{
	            name: TOP
	        }, {
	            name: BOTTOM
	        }, {
	            name: LEFT
	        }, {
	            name: RIGHT
	        }, {
	            name: AUTO,
	            position: function (shape) {
	                return shape.getPosition("center");
	            }
	        }];

	        var defaultButtons = {
	            cancel: {
	                text: "Cancel",
	                imageClass: "k-i-cancel",
	                className: "k-diagram-cancel",
	                iconClass: "k-icon"
	            },
	            update: {
	                text: "Update",
	                imageClass: "k-i-checkmark",
	                className: "k-diagram-update",
	                iconClass: "k-icon"
	            }
	        };

	        diagram.shapeDefaults = function(extra) {
	            var defaults = {
	                type: DEFAULT_SHAPE_TYPE,
	                path: "",
	                autoSize: true,
	                visual: null,
	                x: DEFAULT_SHAPE_POSITION,
	                y: DEFAULT_SHAPE_POSITION,
	                minWidth: DEFAULT_SHAPE_MINWIDTH,
	                minHeight: DEFAULT_SHAPE_MINHEIGHT,
	                width: DEFAULT_SHAPE_WIDTH,
	                height: DEFAULT_SHAPE_HEIGHT,
	                hover: {},
	                editable: {
	                    connect: true,
	                    tools: []
	                },
	                connectors: diagram.DefaultConnectors,
	                rotation: {
	                    angle: 0
	                }
	            };

	            Utils.simpleExtend(defaults, extra);

	            return defaults;
	        };

	        function mwDelta(e) {
	            var origEvent = e.originalEvent,
	                delta = 0;

	            if (origEvent.wheelDelta) {
	                delta = -origEvent.wheelDelta / 40;
	                delta = delta > 0 ? math.ceil(delta) : math.floor(delta);
	            } else if (origEvent.detail) {
	                delta = origEvent.detail;
	            }

	            return delta;
	        }

	        function isAutoConnector(connector) {
	            return connector.options.name.toLowerCase() === AUTO.toLowerCase();
	        }

	        function closestConnector(point, connectors) {
	            var minimumDistance = MAXINT, resCtr, connector;
	            for (var i = 0; i < connectors.length; i++) {
	                connector = connectors[i];
	                if (!isAutoConnector(connector)) {
	                    var dist = point.distanceTo(connector.position());
	                    if (dist < minimumDistance) {
	                        minimumDistance = dist;
	                        resCtr = connector;
	                    }
	                }
	            }
	            return resCtr;
	        }

	        function indicesOfItems(group, visuals) {
	            var i, indices = [], visual;
	            var children = group.drawingContainer().children;
	            var length = children.length;
	            for (i = 0; i < visuals.length; i++) {
	                visual = visuals[i];
	                for (var j = 0; j < length; j++) {
	                    if (children[j] == visual.drawingContainer()) {
	                        indices.push(j);
	                        break;
	                    }
	                }
	            }
	            return indices;
	        }

	        var DiagramElement = Observable.extend({
	            init: function (options) {
	                var that = this;
	                that.dataItem = (options || {}).dataItem;
	                Observable.fn.init.call(that);
	                that.options = deepExtend({ id: diagram.randomId() }, that.options, options);
	                that.isSelected = false;
	                that.visual = new Group({
	                    id: that.options.id,
	                    autoSize: that.options.autoSize
	                });
	                that.id = that.options.id;
	                that._template();
	            },

	            options: {
	                hover: {},
	                cursor: Cursors.grip,
	                content: {
	                    align: "center middle"
	                },
	                selectable: true,
	                serializable: true,
	                enable: true
	            },

	            _getCursor: function (point) {
	                if (this.adorner) {
	                    return this.adorner._getCursor(point);
	                }
	                return this.options.cursor;
	            },

	            visible: function (value) {
	                if (isUndefined(value)) {
	                    return this.visual.visible();
	                } else {
	                    this.visual.visible(value);
	                }
	            },

	            bounds: function () {
	            },

	            refresh: function () {
	                this.visual.redraw();
	            },

	            position: function (point) {
	                this.options.x = point.x;
	                this.options.y = point.y;
	                this.visual.position(point);
	            },

	            toString: function () {
	                return this.options.id;
	            },

	            serialize: function () {
	                // the options json object describes the shape perfectly. So this object can serve as shape serialization.
	                var json = deepExtend({}, {options: this.options});
	                if (this.dataItem) {
	                    json.dataItem = this.dataItem.toString();
	                }
	                return json;
	            },

	            _content: function (content) {
	                if (content !== undefined) {
	                    var options = this.options;

	                    if (diagram.Utils.isString(content)) {
	                        options.content.text = content;
	                    } else {
	                        deepExtend(options.content, content);
	                    }

	                    var contentOptions = options.content;
	                    var contentVisual = this._contentVisual;

	                    if (!contentVisual) {
	                        this._createContentVisual(contentOptions);
	                    } else {
	                        this._updateContentVisual(contentOptions);
	                    }
	                }

	                return this.options.content.text;
	            },

	            _createContentVisual: function(options) {
	                if (options.text) {
	                    this._contentVisual = new TextBlock(options);
	                    this._contentVisual._includeInBBox = false;
	                    this.visual.append(this._contentVisual);
	                }
	            },

	            _updateContentVisual: function(options) {
	                this._contentVisual.redraw(options);
	            },

	            _hitTest: function (point) {
	                var bounds = this.bounds();
	                return this.visible() && bounds.contains(point) && this.options.enable;
	            },

	            _template: function () {
	                var that = this;
	                if (that.options.content.template) {
	                    var data = that.dataItem || {},
	                        elementTemplate = kendo.template(that.options.content.template, {
	                            paramName: "dataItem"
	                        });

	                    that.options.content.text = elementTemplate(data);
	                }
	            },

	            _canSelect: function () {
	                return this.options.selectable !== false;
	            },

	            toJSON: function() {
	                return {
	                    id: this.options.id
	                };
	            }
	        });

	        var Connector = Class.extend({
	            init: function (shape, options) {
	                this.options = deepExtend({}, this.options, options);
	                this.connections = [];
	                this.shape = shape;
	            },
	            options: {
	                width: 7,
	                height: 7,
	                fill: {
	                    color: DEFAULT_CONNECTION_BACKGROUND
	                },
	                hover: {}
	            },
	            position: function () {
	                if (this.options.position) {
	                    return this.options.position(this.shape);
	                } else {
	                    return this.shape.getPosition(this.options.name);
	                }
	            },
	            toJSON: function () {
	                return {
	                    shapeId: this.shape.toString(),
	                    connector: this.options.name
	                };
	            }
	        });

	        Connector.parse = function (diagram, str) {
	            var tempStr = str.split(":"),
	                id = tempStr[0],
	                name = tempStr[1] || AUTO;

	            for (var i = 0; i < diagram.shapes.length; i++) {
	                var shape = diagram.shapes[i];
	                if (shape.options.id == id) {
	                    return shape.getConnector(name.trim());
	                }
	            }
	        };

	        var Shape = DiagramElement.extend({
	            init: function (options, diagram) {
	                var that = this;
	                DiagramElement.fn.init.call(that, options);
	                this.diagram = diagram;
	                this.updateOptionsFromModel();
	                options = that.options;
	                that.connectors = [];
	                that.type = options.type;
	                that.createShapeVisual();
	                that.updateBounds();
	                that.content(that.content());

	                that._createConnectors();
	            },

	            options: diagram.shapeDefaults(),

	            _setOptionsFromModel: function(model) {
	                var modelOptions = filterShapeDataItem(model || this.dataItem);
	                this.options = deepExtend({}, this.options, modelOptions);

	                this.redrawVisual();
	            },

	            updateOptionsFromModel: function(model, field) {
	                if (this.diagram && this.diagram._isEditable) {
	                    var modelOptions = filterShapeDataItem(model || this.dataItem);

	                    if (model && field) {
	                        if (!dataviz.inArray(field, ["x", "y", "width", "height"])) {
	                            if (this.options.visual) {
	                                this._redrawVisual();
	                            } else if (modelOptions.type) {
	                                this.options = deepExtend({}, this.options, modelOptions);
	                                this._redrawVisual();
	                            }

	                            if (this.options.content) {
	                                this._template();
	                                this.content(this.options.content);
	                            }
	                        } else {
	                            var bounds = this.bounds();
	                            bounds[field] = model[field];
	                            this.bounds(bounds);
	                        }
	                    } else {
	                        this.options = deepExtend({}, this.options, modelOptions);
	                    }
	                }
	            },

	            _redrawVisual: function() {
	                this.visual.clear();
	                this._contentVisual = null;
	                this.options.dataItem = this.dataItem;
	                this.createShapeVisual();
	                this.updateBounds();
	            },

	            redrawVisual: function() {
	                this._redrawVisual();
	                if (this.options.content) {
	                    this._template();
	                    this.content(this.options.content);
	                }
	            },

	            updateModel: function(syncChanges) {
	                var diagram = this.diagram;
	                if (diagram && diagram._isEditable) {
	                    var bounds = this._bounds;
	                    var model = this.dataItem;

	                    if (model) {
	                        diagram._suspendModelRefresh();
	                        if (defined(model.x) && bounds.x !== model.x) {
	                            model.set("x", bounds.x);
	                        }

	                        if (defined(model.y) && bounds.y !== model.y) {
	                            model.set("y", bounds.y);
	                        }

	                        if (defined(model.width) && bounds.width !== model.width) {
	                            model.set("width", bounds.width);
	                        }

	                        if (defined(model.height) && bounds.height !== model.height) {
	                            model.set("height", bounds.height);
	                        }

	                        this.dataItem = model;
	                        diagram._resumeModelRefresh();

	                        if (syncChanges) {
	                            diagram._syncShapeChanges();
	                        }
	                    }
	                }
	            },

	            updateBounds: function() {
	                var bounds = this.visual._measure(true);
	                var options = this.options;
	                this.bounds(new Rect(options.x, options.y, bounds.width, bounds.height));
	                this._rotate();
	                this._alignContent();
	            },

	            content: function(content) {
	                var result = this._content(content);

	                this._alignContent();

	                return result;
	            },

	            _alignContent: function() {
	                var contentOptions = this.options.content || {};
	                var contentVisual = this._contentVisual;
	                if (contentVisual && contentOptions.align) {
	                    var containerRect = this.visual._measure();
	                    var aligner = new diagram.RectAlign(containerRect);
	                    var contentBounds = contentVisual.drawingElement.bbox(null);

	                    var contentRect = new Rect(0, 0, contentBounds.width(), contentBounds.height());
	                    var alignedBounds = aligner.align(contentRect, contentOptions.align);

	                    contentVisual.position(alignedBounds.topLeft());
	                }
	            },

	            _createConnectors: function() {
	                var options = this.options,
	                    length = options.connectors.length,
	                    connectorDefaults = options.connectorDefaults,
	                    connector, i;

	                for (i = 0; i < length; i++) {
	                    connector = new Connector(
	                        this, deepExtend({},
	                            connectorDefaults,
	                            options.connectors[i]
	                        )
	                    );
	                    this.connectors.push(connector);
	                }
	            },

	            bounds: function (value) {
	                var bounds;

	                if (value) {
	                    if (isString(value)) {
	                        switch (value) {
	                            case TRANSFORMED :
	                                bounds = this._transformedBounds();
	                                break;
	                            case ABSOLUTE :
	                                bounds = this._transformedBounds();
	                                var pan = this.diagram._pan;
	                                bounds.x += pan.x;
	                                bounds.y += pan.y;
	                                break;
	                            case ROTATED :
	                                bounds = this._rotatedBounds();
	                                break;
	                            default:
	                                bounds = this._bounds;
	                        }
	                    } else {
	                        this._setBounds(value);
	                        this._triggerBoundsChange();
	                        if (!(this.diagram && this.diagram._layouting)) {
	                            this.refreshConnections();
	                        }
	                    }
	                } else {
	                    bounds = this._bounds;
	                }

	                return bounds;
	            },

	            _setBounds: function(rect) {
	                var options = this.options;
	                var topLeft = rect.topLeft();
	                var x = options.x = topLeft.x;
	                var y = options.y = topLeft.y;
	                var width = options.width = math.max(rect.width, options.minWidth);
	                var height = options.height = math.max(rect.height, options.minHeight);

	                this._bounds = new Rect(x, y, width, height);

	                this.visual.redraw({
	                    x: x,
	                    y: y,
	                    width: width,
	                    height: height
	                });
	            },

	            position: function (point) {
	                if (point) {
	                    this.bounds(new Rect(point.x, point.y, this._bounds.width, this._bounds.height));
	                } else {
	                    return this._bounds.topLeft();
	                }
	            },
	            /**
	             * Returns a clone of this shape.
	             * @returns {Shape}
	             */
	            clone: function () {
	                var json = this.serialize();

	                json.options.id = diagram.randomId();

	                if (this.diagram && this.diagram._isEditable && defined(this.dataItem)) {
	                    json.options.dataItem = cloneDataItem(this.dataItem);
	                }

	                return new Shape(json.options);
	            },

	            select: function (value) {
	                var diagram = this.diagram, selected, deselected;
	                if (isUndefined(value)) {
	                    value = true;
	                }

	                if (this._canSelect()) {
	                    if (this.isSelected != value) {
	                        selected = [];
	                        deselected = [];
	                        this.isSelected = value;
	                        if (this.isSelected) {
	                            diagram._selectedItems.push(this);
	                            selected.push(this);
	                        } else {
	                            Utils.remove(diagram._selectedItems, this);
	                            deselected.push(this);
	                        }

	                        if (!diagram._internalSelection) {
	                            diagram._selectionChanged(selected, deselected);
	                        }

	                        return true;
	                    }
	                }
	            },

	            rotate: function (angle, center, undoable) { // we assume the center is always the center of the shape.
	                var rotate = this.visual.rotate();
	                if (angle !== undefined) {
	                    if (undoable !== false && this.diagram && this.diagram.undoRedoService && angle !== rotate.angle) {
	                        this.diagram.undoRedoService.add(
	                            new diagram.RotateUnit(this.diagram._resizingAdorner, [this], [rotate.angle]), false);
	                    }

	                    var b = this.bounds(),
	                        sc = new Point(b.width / 2, b.height / 2),
	                        deltaAngle,
	                        newPosition;

	                    if (center) {
	                        deltaAngle = angle - rotate.angle;
	                        newPosition = b.center().rotate(center, 360 - deltaAngle).minus(sc);
	                        this._rotationOffset = this._rotationOffset.plus(newPosition.minus(b.topLeft()));
	                        this.position(newPosition);
	                    }

	                    this.visual.rotate(angle, sc);
	                    this.options.rotation.angle = angle;

	                    if (this.diagram && this.diagram._connectorsAdorner) {
	                        this.diagram._connectorsAdorner.refresh();
	                    }

	                    this.refreshConnections();

	                    if (this.diagram) {
	                        this.diagram.trigger(ITEMROTATE, { item: this });
	                    }
	                }

	                return rotate;
	            },

	            connections: function (type) { // in, out, undefined = both
	                var result = [], i, j, con, cons, ctr;

	                for (i = 0; i < this.connectors.length; i++) {
	                    ctr = this.connectors[i];
	                    cons = ctr.connections;
	                    for (j = 0, cons; j < cons.length; j++) {
	                        con = cons[j];
	                        if (type == "out") {
	                            var source = con.source();
	                            if (source.shape && source.shape == this) {
	                                result.push(con);
	                            }
	                        } else if (type == "in") {
	                            var target = con.target();
	                            if (target.shape && target.shape == this) {
	                                result.push(con);
	                            }
	                        } else {
	                            result.push(con);
	                        }
	                    }
	                }

	                return result;
	            },

	            refreshConnections: function () {
	                $.each(this.connections(), function () {
	                    this.refresh();
	                });
	            },
	            /**
	             * Gets a connector of this shape either by the connector's supposed name or
	             * via a Point in which case the closest connector will be returned.
	             * @param nameOrPoint The name of a Connector or a Point.
	             * @returns {Connector}
	             */
	            getConnector: function (nameOrPoint) {
	                var i, ctr;
	                if (isString(nameOrPoint)) {
	                    nameOrPoint = nameOrPoint.toLocaleLowerCase();
	                    for (i = 0; i < this.connectors.length; i++) {
	                        ctr = this.connectors[i];
	                        if (ctr.options.name.toLocaleLowerCase() == nameOrPoint) {
	                            return ctr;
	                        }
	                    }
	                } else if (nameOrPoint instanceof Point) {
	                    return closestConnector(nameOrPoint, this.connectors);
	                } else {
	                    return this.connectors.length ? this.connectors[0] : null;
	                }
	            },

	            getPosition: function (side) {
	                var b = this.bounds(),
	                    fnName = side.charAt(0).toLowerCase() + side.slice(1);

	                if (isFunction(b[fnName])) {
	                    return this._transformPoint(b[fnName]());
	                }

	                return b.center();
	            },

	            redraw: function (options) {
	                if (options) {
	                    var shapeOptions = this.options;
	                    var boundsChange;

	                    this.shapeVisual.redraw(this._visualOptions(options));

	                    if (this._diffNumericOptions(options, [WIDTH, HEIGHT, X, Y])) {
	                        this.bounds(new Rect(shapeOptions.x, shapeOptions.y, shapeOptions.width, shapeOptions.height));
	                        boundsChange = true;
	                    }

	                    if (options.connectors) {
	                        shapeOptions.connectors = options.connectors;
	                        this._updateConnectors();
	                    }

	                    shapeOptions = deepExtend(shapeOptions, options);

	                    if  (options.rotation || boundsChange) {
	                        this._rotate();
	                    }

	                    if (shapeOptions.content) {
	                        this.content(shapeOptions.content);
	                    }
	                }
	            },

	            _updateConnectors: function() {
	                var connections = this.connections();
	                this.connectors = [];
	                this._createConnectors();
	                var connection;
	                var source;
	                var target;

	                for (var idx = 0; idx < connections.length; idx++) {
	                    connection = connections[idx];
	                    source = connection.source();
	                    target = connection.target();
	                    if (source.shape && source.shape === this) {
	                        connection.source(this.getConnector(source.options.name) || null);
	                    } else if (target.shape && target.shape === this) {
	                        connection.target(this.getConnector(target.options.name) || null);
	                    }
	                    connection.updateModel();
	                }
	            },

	            _diffNumericOptions: diagram.diffNumericOptions,

	            _visualOptions: function(options) {
	                return {
	                    data: options.path,
	                    source: options.source,
	                    hover: options.hover,
	                    fill: options.fill,
	                    stroke: options.stroke
	                };
	            },

	            _triggerBoundsChange: function () {
	                if (this.diagram) {
	                    this.diagram.trigger(ITEMBOUNDSCHANGE, {item: this, bounds: this._bounds.clone()}); // the trigger modifies the arguments internally.
	                }
	            },

	            _transformPoint: function (point) {
	                var rotate = this.rotate(),
	                    bounds = this.bounds(),
	                    tl = bounds.topLeft();

	                if (rotate.angle) {
	                    point.rotate(rotate.center().plus(tl), 360 - rotate.angle);
	                }

	                return point;
	            },

	            _transformedBounds: function () {
	                var bounds = this.bounds(),
	                    tl = bounds.topLeft(),
	                    br = bounds.bottomRight();

	                return Rect.fromPoints(this.diagram.modelToView(tl), this.diagram.modelToView(br));
	            },

	            _rotatedBounds: function () {
	                var bounds = this.bounds().rotatedBounds(this.rotate().angle),
	                    tl = bounds.topLeft(),
	                    br = bounds.bottomRight();

	                return Rect.fromPoints(tl, br);
	            },

	            _rotate: function () {
	                var rotation = this.options.rotation;

	                if (rotation && rotation.angle) {
	                    this.rotate(rotation.angle);
	                }

	                this._rotationOffset = new Point();
	            },

	            _hover: function (value) {
	                var options = this.options,
	                    hover = options.hover,
	                    stroke = options.stroke,
	                    fill = options.fill;

	                if (value && isDefined(hover.stroke)) {
	                    stroke = deepExtend({}, stroke, hover.stroke);
	                }

	                if (value && isDefined(hover.fill)) {
	                    fill = hover.fill;
	                }

	                this.shapeVisual.redraw({
	                    stroke: stroke,
	                    fill: fill
	                });

	                if (options.editable && options.editable.connect) {
	                    this.diagram._showConnectors(this, value);
	                }
	            },

	            _hitTest: function (value) {
	                if (this.visible()) {
	                    var bounds = this.bounds(), rotatedPoint,
	                        angle = this.rotate().angle;

	                    if (value.isEmpty && !value.isEmpty()) { // rect selection
	                        return Intersect.rects(value, bounds, angle ? angle : 0);
	                    } else { // point
	                        rotatedPoint = value.clone().rotate(bounds.center(), angle); // cloning is important because rotate modifies the point inline.
	                        if (bounds.contains(rotatedPoint)) {
	                            return this;
	                        }
	                    }
	                }
	            },

	            toJSON: function() {
	                return {
	                    shapeId: this.options.id
	                };
	            },

	            createShapeVisual: function() {
	                var options = this.options;
	                var visualOptions = this._visualOptions(options);
	                var visualTemplate = options.visual;
	                var type = (options.type + "").toLocaleLowerCase();
	                var shapeVisual;

	                visualOptions.width = options.width;
	                visualOptions.height = options.height;

	                if (isFunction(visualTemplate)) { // custom template
	                    shapeVisual = visualTemplate.call(this, options);
	                } else if (visualOptions.data) {
	                    shapeVisual = new Path(visualOptions);
	                    translateToOrigin(shapeVisual);
	                } else if (type == "rectangle"){
	                    shapeVisual = new Rectangle(visualOptions);
	                } else if (type == "circle") {
	                    shapeVisual = new Circle(visualOptions);
	                } else if (type == "text") {
	                    shapeVisual = new TextBlock(visualOptions);
	                } else if (type == "image") {
	                    shapeVisual = new Image(visualOptions);
	                } else {
	                    shapeVisual = new Path(visualOptions);
	                }

	                this.shapeVisual = shapeVisual;
	                this.visual.append(this.shapeVisual);
	            }
	        });

	        /**
	         * The visual link between two Shapes through the intermediate of Connectors.
	         */
	        var Connection = DiagramElement.extend({
	            init: function (from, to, options) {
	                var that = this;
	                DiagramElement.fn.init.call(that, options);
	                this.updateOptionsFromModel();
	                this._initRouter();
	                that.path = new diagram.Polyline(that.options);
	                that.path.fill(TRANSPARENT);
	                that.visual.append(that.path);
	                that._sourcePoint = that._targetPoint = new Point();
	                that._setSource(from);
	                that._setTarget(to);
	                that.content(that.options.content);
	                that.definers = [];
	                if (defined(options) && options.points) {
	                    that.points(options.points);
	                }
	            },

	            options: {
	                hover: {
	                    stroke: {}
	                },
	                startCap: NONE,
	                endCap: NONE,
	                points: [],
	                selectable: true,
	                fromConnector: AUTO,
	                toConnector: AUTO
	            },

	            _setOptionsFromModel: function(model) {
	                this.updateOptionsFromModel(model || this.dataItem);
	            },

	            updateOptionsFromModel: function(model) {
	                if (this.diagram && this.diagram._isEditable) {
	                    var dataMap = this.diagram._dataMap;
	                    var options = filterConnectionDataItem(model || this.dataItem);

	                    if (model) {
	                        if (defined(options.from)) {
	                            var from = dataMap[options.from];
	                            if (from && defined(options.fromConnector)) {
	                               from = from.getConnector(options.fromConnector);
	                            }
	                            this.source(from);
	                        } else if (defined(options.fromX) && defined(options.fromY)) {
	                            this.source(new Point(options.fromX, options.fromY));
	                        }

	                        if (defined(options.to)) {
	                            var to = dataMap[options.to];
	                            if (to && defined(options.toConnector)) {
	                                to = to.getConnector(options.toConnector);
	                            }
	                            this.target(to);
	                        } else if (defined(options.toX) && defined(options.toY)) {
	                            this.target(new Point(options.toX, options.toY));
	                        }

	                        if (defined(options.type) && this.type() !== options.type) {
	                            this.points([]);
	                            this.type(options.type);
	                        }

	                        this.dataItem = model;

	                        this._template();
	                        this.redraw(this.options);
	                    } else {
	                        this.options = deepExtend({}, options, this.options);
	                    }
	                }
	            },

	            updateModel: function(syncChanges) {
	                if (this.diagram && this.diagram._isEditable) {
	                    if (this.diagram.connectionsDataSource) {
	                        var model = this.diagram.connectionsDataSource.getByUid(this.dataItem.uid);

	                        if (model) {
	                            this.diagram._suspendModelRefresh();
	                            if (defined(this.options.fromX) && this.options.fromX !== null) {
	                                clearField("from", model);
	                                clearField("fromConnector", model);
	                                model.set("fromX", this.options.fromX);
	                                model.set("fromY", this.options.fromY);
	                            } else  {
	                                model.set("from", this.options.from);
	                                if (defined(model.fromConnector)) {
	                                    model.set("fromConnector", this.sourceConnector ? this.sourceConnector.options.name : null);
	                                }
	                                clearField("fromX", model);
	                                clearField("fromY", model);
	                            }

	                            if (defined(this.options.toX) && this.options.toX !== null) {
	                                clearField("to", model);
	                                clearField("toConnector", model);
	                                model.set("toX", this.options.toX);
	                                model.set("toY", this.options.toY);
	                            } else {
	                                model.set("to", this.options.to);
	                                if (defined(model.toConnector)) {
	                                    model.set("toConnector", this.targetConnector ? this.targetConnector.options.name : null);
	                                }
	                                clearField("toX", model);
	                                clearField("toY", model);
	                            }

	                            if (defined(this.options.type) && defined(model.type)) {
	                                model.set("type", this.options.type);
	                            }

	                            this.dataItem = model;
	                            this.diagram._resumeModelRefresh();

	                            if (syncChanges) {
	                                this.diagram._syncConnectionChanges();
	                            }
	                        }
	                    }
	                }
	            },

	            /**
	             * Gets the Point where the source of the connection resides.
	             * If the endpoint in Auto-connector the location of the resolved connector will be returned.
	             * If the endpoint is floating the location of the endpoint is returned.
	             */
	            sourcePoint: function () {
	                return this._resolvedSourceConnector ? this._resolvedSourceConnector.position() : this._sourcePoint;
	            },

	            _setSource: function(source) {
	                var shapeSource = source instanceof Shape;
	                var defaultConnector = this.options.fromConnector || AUTO;
	                var dataItem;
	                if (shapeSource && !source.getConnector(defaultConnector)) {
	                    return;
	                }

	                if (source !== undefined) {
	                    this.from = source;
	                }

	                this._removeFromSourceConnector();

	                if (source === null) { // detach
	                    if (this.sourceConnector) {
	                        this._sourcePoint = (this._resolvedSourceConnector || this.sourceConnector).position();
	                        this._clearSourceConnector();
	                        this._setFromOptions(null, this._sourcePoint);
	                    }
	                } else if (source instanceof Connector) {
	                    dataItem = source.shape.dataItem;
	                    if (dataItem) {
	                        this._setFromOptions(dataItem.id);
	                    }
	                    this.sourceConnector = source;
	                    this.sourceConnector.connections.push(this);
	                } else if (source instanceof Point) {
	                    this._setFromOptions(null, source);
	                    this._sourcePoint = source;
	                    if (this.sourceConnector) {
	                        this._clearSourceConnector();
	                    }

	                } else if (shapeSource) {
	                    dataItem = source.dataItem;
	                    if (dataItem) {
	                        this._setFromOptions(dataItem.id);
	                    }

	                    this.sourceConnector = source.getConnector(defaultConnector);
	                    this.sourceConnector.connections.push(this);
	                }
	            },

	            source: function (source, undoable) {
	                if (isDefined(source)) {
	                    if (undoable && this.diagram) {
	                        this.diagram.undoRedoService.addCompositeItem(new diagram.ConnectionEditUnit(this, source));
	                    }
	                    this._setSource(source);
	                    this.refresh();
	                }
	                return this.sourceConnector ? this.sourceConnector : this._sourcePoint;
	            },

	            _setFromOptions: function(from, fromPoint) {
	                this.options.from = from;
	                if (fromPoint)  {
	                    this.options.fromX = fromPoint.x;
	                    this.options.fromY = fromPoint.y;
	                } else {
	                    this.options.fromX = null;
	                    this.options.fromY = null;
	                }
	            },

	            /**
	             * Gets or sets the PathDefiner of the sourcePoint.
	             * The left part of this definer is always null since it defines the source tangent.
	             * @param value
	             * @returns {*}
	             */
	            sourceDefiner: function (value) {
	                if (value) {
	                    if (value instanceof diagram.PathDefiner) {
	                        value.left = null;
	                        this._sourceDefiner = value;
	                        this.source(value.point); // refresh implicit here
	                    } else {
	                        throw "The sourceDefiner needs to be a PathDefiner.";
	                    }
	                } else {
	                    if (!this._sourceDefiner) {
	                        this._sourceDefiner = new diagram.PathDefiner(this.sourcePoint(), null, null);
	                    }
	                    return this._sourceDefiner;
	                }
	            },

	            /**
	             * Gets  the Point where the target of the connection resides.
	             */
	            targetPoint: function () {
	                return this._resolvedTargetConnector ? this._resolvedTargetConnector.position() : this._targetPoint;
	            },

	            _setTarget: function(target) {
	                var shapeTarget = target instanceof Shape;
	                var defaultConnector = this.options.toConnector || AUTO;
	                var dataItem;

	                if (shapeTarget && !target.getConnector(defaultConnector)) {
	                    return;
	                }

	                if (target !== undefined) {
	                    this.to = target;
	                }

	                this._removeFromTargetConnector();

	                if (target === null) { // detach
	                    if (this.targetConnector) {
	                        this._targetPoint = (this._resolvedTargetConnector || this.targetConnector).position();
	                        this._clearTargetConnector();
	                        this._setToOptions(null, this._targetPoint);
	                    }
	                } else if (target instanceof Connector) {
	                    dataItem = target.shape.dataItem;
	                    if (dataItem) {
	                        this._setToOptions(dataItem.id);
	                    }
	                    this.targetConnector = target;
	                    this.targetConnector.connections.push(this);
	                } else if (target instanceof Point) {
	                    this._setToOptions(null, target);
	                    this._targetPoint = target;
	                    if (this.targetConnector) {
	                        this._clearTargetConnector();
	                    }
	                } else if (shapeTarget) {
	                    dataItem = target.dataItem;
	                    if (dataItem) {
	                        this._setToOptions(dataItem.id);
	                    }
	                    this.targetConnector = target.getConnector(defaultConnector);
	                    this.targetConnector.connections.push(this);
	                }
	            },

	            target: function (target, undoable) {
	                if (isDefined(target)) {
	                    if (undoable && this.diagram) {
	                        this.diagram.undoRedoService.addCompositeItem(new diagram.ConnectionEditUnit(this, undefined, target));
	                    }
	                    this._setTarget(target);

	                    this.refresh();
	                }
	                return this.targetConnector ? this.targetConnector : this._targetPoint;
	            },

	            _setToOptions: function(to, toPoint) {
	                this.options.to = to;
	                if (toPoint)  {
	                    this.options.toX = toPoint.x;
	                    this.options.toY = toPoint.y;
	                } else {
	                    this.options.toX = null;
	                    this.options.toY = null;
	                }
	            },

	            /**
	             * Gets or sets the PathDefiner of the targetPoint.
	             * The right part of this definer is always null since it defines the target tangent.
	             * @param value
	             * @returns {*}
	             */
	            targetDefiner: function (value) {
	                if (value) {
	                    if (value instanceof diagram.PathDefiner) {
	                        value.right = null;
	                        this._targetDefiner = value;
	                        this.target(value.point); // refresh implicit here
	                    } else {
	                        throw "The sourceDefiner needs to be a PathDefiner.";
	                    }
	                } else {
	                    if (!this._targetDefiner) {
	                        this._targetDefiner = new diagram.PathDefiner(this.targetPoint(), null, null);
	                    }
	                    return this._targetDefiner;
	                }
	            },

	            _updateConnectors: function() {
	                this._updateConnector(this.source(), "source");
	                this._updateConnector(this.target(), "target");
	            },

	            _updateConnector: function(instance, name) {
	                var that = this;
	                var diagram = that.diagram;
	                if (instance instanceof Connector && !diagram.getShapeById(instance.shape.id)) {
	                    var dataItem = instance.shape.dataItem;
	                    var connectorName = instance.options.name;
	                    var setNewTarget = function() {
	                        var shape = diagram._dataMap[dataItem.id];
	                        instance = shape.getConnector(connectorName);
	                        that[name](instance, false);
	                        that.updateModel();
	                    };
	                    if (diagram._dataMap[dataItem.id]) {
	                       setNewTarget();
	                    } else {
	                        var inactiveItem = diagram._inactiveShapeItems.getByUid(dataItem.uid);
	                        if (inactiveItem) {
	                            diagram._deferredConnectionUpdates.push(inactiveItem.onActivate(setNewTarget));
	                        }
	                    }
	                } else {
	                    that[name](instance, false);
	                }
	            },

	            content: function(content) {
	                var result = this._content(content);
	                if (defined(content)) {
	                    this._alignContent();
	                }
	                return result;
	            },

	            _createContentVisual: function(options) {
	                var visual;
	                if (isFunction(options.visual)) {
	                    visual = options.visual.call(this, options);
	                } else if (options.text) {
	                    visual = new TextBlock(options);
	                }

	                if (visual) {
	                    this._contentVisual = visual;
	                    visual._includeInBBox = false;
	                    this.visual.append(visual);
	                }

	                return visual;
	            },

	            _updateContentVisual: function(options) {
	                if (isFunction(options.visual)) {
	                    this.visual.remove(this._contentVisual);
	                    this._createContentVisual(options);
	                } else {
	                    this._contentVisual.redraw(options);
	                }
	            },

	            _alignContent: function() {
	                if (this._contentVisual) {
	                    var offset = CONNECTION_CONTENT_OFFSET;
	                    var points = this.allPoints();
	                    var endIdx = math.floor(points.length / 2);
	                    var startIdx = endIdx - 1;

	                    while(startIdx > 0 && points[startIdx].equals(points[endIdx])) {
	                        startIdx--;
	                        endIdx++;
	                    }

	                    var endPoint = points[endIdx];
	                    var startPoint = points[startIdx];

	                    var boundingBox = this._contentVisual._measure();
	                    var width = boundingBox.width;
	                    var height = boundingBox.height;
	                    var alignToPath = points.length % 2 === 0;
	                    var distance = startPoint.distanceTo(endPoint);

	                    if (alignToPath && points.length > 2 && distance > 0 &&
	                        ((startPoint.y === endPoint.y && distance < width) || (startPoint.x === endPoint.x && distance < height))) {
	                        alignToPath = false;
	                        offset = 0;
	                    }

	                    var point;

	                    if (alignToPath) {
	                        var angle  = draw.util.deg(math.atan2(endPoint.y - startPoint.y, endPoint.x - startPoint.x));
	                        point = new Point((endPoint.x - startPoint.x) / 2 + startPoint.x, (endPoint.y - startPoint.y) / 2 + startPoint.y);

	                        if (math.abs(angle) === 90) {
	                            point.x += offset;
	                            point.y-= height / 2;
	                        } else if (angle % 180 === 0) {
	                            point.x -= width / 2;
	                            point.y -= height + offset;
	                        } else if (angle < -90 || (0 < angle && angle < 90)) {
	                            point.y-= height;
	                        } else if (angle < 0 || angle > 90) {
	                            point.x -= width;
	                            point.y -= height;
	                        }
	                    } else {
	                        var midIdx = math.floor(points.length / 2);
	                        point = points[midIdx].clone();
	                        startPoint = points[midIdx - 1];
	                        endPoint = points[midIdx + 1];

	                        var offsetX = startPoint.x <= point.x && endPoint.x <= point.x ? offset : -boundingBox.width - offset;
	                        var offsetY = startPoint.y <= point.y && endPoint.y <= point.y ? offset : -boundingBox.height - offset;

	                        point.x += offsetX;
	                        point.y += offsetY;
	                    }

	                    this._contentVisual.position(point);
	                }
	            },

	            /**
	             * Selects or unselects this connections.
	             * @param value True to select, false to unselect.
	             */
	            select: function (value) {
	                var diagram = this.diagram, selected, deselected;
	                if (this._canSelect()) {
	                    if (this.isSelected !== value) {
	                        this.isSelected = value;
	                        selected = [];
	                        deselected = [];
	                        if (this.isSelected) {
	                            this.adorner = new ConnectionEditAdorner(this, this.options.selection);
	                            diagram._adorn(this.adorner, true);
	                            diagram._selectedItems.push(this);
	                            selected.push(this);
	                        } else {
	                            if (this.adorner) {
	                                diagram._adorn(this.adorner, false);
	                                Utils.remove(diagram._selectedItems, this);
	                                this.adorner = undefined;
	                                deselected.push(this);
	                            }
	                        }

	                        if (this.adorner) {
	                            this.adorner.refresh();
	                        }

	                        if (!diagram._internalSelection) {
	                            diagram._selectionChanged(selected, deselected);
	                        }
	                        return true;
	                    }
	                }
	            },
	            /**
	             * Gets or sets the bounds of this connection.
	             * @param value A Rect object.
	             * @remark This is automatically set in the refresh().
	             * @returns {Rect}
	             */
	            bounds: function (value) {
	                if (value && !isString(value)) {
	                    this._bounds = value;
	                } else {
	                    return this._bounds;
	                }
	            },
	            /**
	             * Gets or sets the connection type (see ConnectionType enumeration).
	             * @param value A ConnectionType value.
	             * @returns {ConnectionType}
	             */
	            type: function (value) {
	                var options = this.options;
	                if (value) {
	                    if (value !== options.type) {
	                        options.type = value;
	                        this._initRouter();
	                        this.refresh();
	                    }
	                } else {
	                    return options.type;
	                }
	            },

	            _initRouter: function() {
	                var type = (this.options.type || "").toLowerCase();
	                if (type == CASCADING) {
	                    this._router = new CascadingRouter(this);
	                } else {
	                    this._router = new PolylineRouter(this);
	                }
	            },
	            /**
	             * Gets or sets the collection of *intermediate* points.
	             * The 'allPoints()' property will return all the points.
	             * The 'definers' property returns the definers of the intermediate points.
	             * The 'sourceDefiner' and 'targetDefiner' return the definers of the endpoints.
	             * @param value
	             */
	            points: function (value) {
	                if (value) {
	                    this.definers = [];
	                    for (var i = 0; i < value.length; i++) {
	                        var definition = value[i];
	                        if (definition instanceof diagram.Point) {
	                            this.definers.push(new diagram.PathDefiner(definition));
	                        } else if (definition.hasOwnProperty("x") && definition.hasOwnProperty("y")) { // e.g. Clipboard does not preserve the Point definition and tunred into an Object
	                            this.definers.push(new diagram.PathDefiner(new Point(definition.x, definition.y)));
	                        } else {
	                            throw "A Connection point needs to be a Point or an object with x and y properties.";
	                        }
	                    }

	                } else {
	                    var pts = [];
	                    if (isDefined(this.definers)) {
	                        for (var k = 0; k < this.definers.length; k++) {
	                            pts.push(this.definers[k].point);
	                        }
	                    }
	                    return pts;
	                }
	            },
	            /**
	             * Gets all the points of this connection. This is the combination of the sourcePoint, the points and the targetPoint.
	             * @returns {Array}
	             */
	            allPoints: function () {
	                var pts = [this.sourcePoint()];
	                if (this.definers) {
	                    for (var k = 0; k < this.definers.length; k++) {
	                        pts.push(this.definers[k].point);
	                    }
	                }
	                pts.push(this.targetPoint());
	                return pts;
	            },

	            refresh: function () {
	                this._resolveConnectors();
	                this._refreshPath();
	                this._alignContent();

	                if (this.adorner) {
	                    this.adorner.refresh();
	                }
	            },

	            _resolveConnectors: function () {
	                var connection = this,
	                    sourcePoint, targetPoint,
	                    sourceConnectors, targetConnectors,
	                    source = connection.source(),
	                    target = connection.target();

	                if (source instanceof Point) {
	                    sourcePoint = source;
	                } else if (source instanceof Connector) {
	                    if (isAutoConnector(source)) {
	                        sourceConnectors = source.shape.connectors;
	                    } else {
	                        sourceConnectors = [source];
	                    }
	                }

	                if (target instanceof Point) {
	                    targetPoint = target;
	                } else if (target instanceof Connector) {
	                    if (isAutoConnector(target)) {
	                        targetConnectors = target.shape.connectors;
	                    } else {
	                        targetConnectors = [target];
	                    }
	                }

	                if (sourcePoint) {
	                    if (targetConnectors) {
	                        connection._resolvedTargetConnector = closestConnector(sourcePoint, targetConnectors);
	                    }
	                } else if (sourceConnectors) {
	                    if (targetPoint) {
	                        connection._resolvedSourceConnector = closestConnector(targetPoint, sourceConnectors);
	                    } else if (targetConnectors) {
	                        this._resolveAutoConnectors(sourceConnectors, targetConnectors);
	                    }
	                }
	            },

	            _resolveAutoConnectors: function(sourceConnectors, targetConnectors) {
	                var minNonConflict = MAXINT;
	                var minDist = MAXINT;
	                var minNonConflictSource, minNonConflictTarget;
	                var sourcePoint, targetPoint;
	                var minSource, minTarget;
	                var sourceConnector, targetConnector;
	                var sourceIdx, targetIdx;
	                var dist;

	                for (sourceIdx = 0; sourceIdx < sourceConnectors.length; sourceIdx++) {
	                    sourceConnector = sourceConnectors[sourceIdx];
	                    if (!isAutoConnector(sourceConnector)) {
	                        sourcePoint = sourceConnector.position();

	                        for (targetIdx = 0; targetIdx < targetConnectors.length; targetIdx++) {
	                            targetConnector = targetConnectors[targetIdx];
	                            if (!isAutoConnector(targetConnector)) {
	                                targetPoint = targetConnector.position();
	                                dist = math.round(sourcePoint.distanceTo(targetPoint));

	                                if (dist < minNonConflict && this.diagram && this._testRoutePoints(sourcePoint, targetPoint, sourceConnector, targetConnector)) {
	                                    minNonConflict = dist;
	                                    minNonConflictSource = sourceConnector;
	                                    minNonConflictTarget = targetConnector;
	                                }

	                                if (dist < minDist) {
	                                    minSource = sourceConnector;
	                                    minTarget = targetConnector;
	                                    minDist = dist;
	                                }
	                            }
	                        }
	                    }
	                }

	                if (minNonConflictSource) {
	                    minSource = minNonConflictSource;
	                    minTarget = minNonConflictTarget;
	                }

	                this._resolvedSourceConnector = minSource;
	                this._resolvedTargetConnector = minTarget;
	            },

	            _testRoutePoints: function(sourcePoint, targetPoint, sourceConnector, targetConnector) {
	                var router = this._router;
	                var passRoute = true;
	                if (router instanceof CascadingRouter) {
	                    var points = router.routePoints(sourcePoint, targetPoint, sourceConnector, targetConnector),
	                        start, end,
	                         rect, exclude;

	                    exclude = this._getRouteExclude(sourcePoint, targetPoint, sourceConnector.shape, targetConnector.shape);
	                    points.unshift(sourcePoint);
	                    points.push(targetPoint);


	                    for (var idx = 1; idx < points.length; idx++) {
	                        start = points[idx - 1];
	                        end = points[idx];
	                        rect = new Rect(math.min(start.x, end.x), math.min(start.y, end.y),
	                                        math.abs(start.x - end.x), math.abs(start.y - end.y));
	                        if (rect.width > 0) {
	                            rect.x++;
	                            rect.width-=2;
	                        }
	                        if (rect.height > 0) {
	                            rect.y++;
	                            rect.height-=2;
	                        }

	                        if (!rect.isEmpty() && this.diagram._shapesQuadTree.hitTestRect(rect, exclude)) {
	                            passRoute = false;
	                            break;
	                        }
	                    }
	                }
	                return passRoute;
	            },

	            _getRouteExclude: function(sourcePoint, targetPoint, sourceShape, targetShape) {
	                var exclude = [];
	                if (this._isPointInsideShape(sourcePoint, sourceShape)){
	                    exclude.push(sourceShape);
	                }
	                if (this._isPointInsideShape(targetPoint, targetShape)){
	                    exclude.push(targetShape);
	                }
	                return exclude;
	            },

	            _isPointInsideShape: function (point, shape) {
	                var bounds = shape.bounds(), rotatedPoint,
	                    angle = shape.rotate().angle,
	                    pointX, pointY,
	                    boundsX = bounds.x,
	                    boundsY = bounds.y;

	                rotatedPoint = point.clone().rotate(bounds.center(), angle);
	                pointX = rotatedPoint.x;
	                pointY = rotatedPoint.y;
	                return pointX > boundsX && pointX < (boundsX + bounds.width) && pointY > boundsY && pointY < (boundsY + bounds.height);
	            },

	            redraw: function (options) {
	                if (options) {
	                    this.options = deepExtend({}, this.options, options);

	                    var points = this.options.points;

	                    if (defined(points) && points.length > 0) {
	                        this.points(points);
	                        this._refreshPath();
	                    }

	                    if ((options && options.content) || options.text) {
	                        this.content(options.content);
	                    }

	                    this.path.redraw({
	                        fill: options.fill,
	                        stroke: options.stroke,
	                        startCap: options.startCap,
	                        endCap: options.endCap
	                    });
	                }
	            },
	            /**
	             * Returns a clone of this connection.
	             * @returns {Connection}
	             */
	            clone: function () {
	                var json = this.serialize();

	                if (this.diagram && this.diagram._isEditable && defined(this.dataItem)) {
	                    json.options.dataItem = cloneDataItem(this.dataItem);
	                }

	                return new Connection(this.from, this.to, json.options);
	            },
	            /**
	             * Returns a serialized connection in json format. Consist of the options and the dataItem.
	             * @returns {Connection}
	             */
	            serialize: function () {
	                var from = this.from.toJSON ? this.from.toJSON : this.from.toString(),
	                    to = this.to.toJSON ? this.to.toJSON : this.to.toString();

	                var json = deepExtend({}, {
	                    options: this.options,
	                    from: from,
	                    to: to
	                });

	                if (defined(this.dataItem)) {
	                    json.dataItem = this.dataItem.toString();
	                }

	                json.options.points = this.points();
	                return json;
	            },

	            /**
	             * Returns whether the given Point or Rect hits this connection.
	             * @param value
	             * @returns {Connection}
	             * @private
	             */
	            _hitTest: function (value) {
	                if (this.visible()) {
	                    var p = new Point(value.x, value.y), from = this.sourcePoint(), to = this.targetPoint();
	                    if (value.isEmpty && !value.isEmpty() && value.contains(from) && value.contains(to)) {
	                        return this;
	                    }
	                    if (this._router.hitTest(p)) {
	                        return this;
	                    }
	                }
	            },

	            _hover: function (value) {
	                var color = (this.options.stroke || {}).color;

	                if (value && isDefined(this.options.hover.stroke.color)) {
	                    color = this.options.hover.stroke.color;
	                }

	                this.path.redraw({
	                    stroke: {
	                        color: color
	                    }
	                });
	            },

	            _refreshPath: function () {
	                if (!defined(this.path)) {
	                    return;
	                }
	                this._drawPath();
	                this.bounds(this._router.getBounds());
	            },

	            _drawPath: function () {
	                if (this._router) {
	                    this._router.route(); // sets the intermediate points
	                }
	                var source = this.sourcePoint();
	                var target = this.targetPoint();
	                var points = this.points();

	                this.path.redraw({
	                    points: [source].concat(points, [target])
	                });
	            },

	            _clearSourceConnector: function () {
	                this.sourceConnector = undefined;
	                this._resolvedSourceConnector = undefined;
	            },

	            _clearTargetConnector: function () {
	                this.targetConnector = undefined;
	                this._resolvedTargetConnector = undefined;
	            },

	            _removeFromSourceConnector: function() {
	                if (this.sourceConnector) {
	                    Utils.remove(this.sourceConnector.connections, this);
	                }
	            },

	            _removeFromTargetConnector: function() {
	                if (this.targetConnector) {
	                    Utils.remove(this.targetConnector.connections, this);
	                }
	            },

	            toJSON: function() {
	                var connection = this;
	                var from, to, point;
	                if (connection.from && connection.from.toJSON) {
	                    from = connection.from.toJSON();
	                } else {
	                    point = connection._sourcePoint;
	                    from = {
	                        x: point.x,
	                        y: point.y
	                    };
	                }

	                if (connection.to && connection.to.toJSON) {
	                    to = connection.to.toJSON();
	                } else {
	                    point = connection._targetPoint;
	                    to = {
	                        x: point.x,
	                        y: point.y
	                    };
	                }

	                return {
	                    from : from,
	                    to: to
	                };
	            }
	        });

	        var Diagram = Widget.extend({
	            init: function (element, userOptions) {
	                var that = this;

	                kendo.destroy(element);
	                Widget.fn.init.call(that, element, userOptions);

	                that._initTheme();

	                that._initElements();
	                that._extendLayoutOptions(that.options);
	                that._initDefaults(userOptions);
	                that._interactionDefaults();

	                that._initCanvas();

	                that.mainLayer = new Group({
	                    id: "main-layer"
	                });
	                that.canvas.append(that.mainLayer);

	                that._shapesQuadTree = new ShapesQuadTree(that);

	                that._pan = new Point();
	                that._adorners = [];
	                that.adornerLayer = new Group({
	                    id: "adorner-layer"
	                });
	                that.canvas.append(that.adornerLayer);

	                that._createHandlers();

	                that._initialize();

	                that._resizingAdorner = new ResizingAdorner(that, { editable: that.options.editable });
	                that._connectorsAdorner = new ConnectorsAdorner(that);

	                that._adorn(that._resizingAdorner, true);
	                that._adorn(that._connectorsAdorner, true);

	                that.selector = new Selector(that);
	                // TODO: We may consider using real Clipboard API once is supported by the standard.
	                that._clipboard = [];

	                that.pauseMouseHandlers = false;

	                that._fetchFreshData();

	                that._createGlobalToolBar();

	                that._createOptionElements();

	                that.zoom(that.options.zoom);

	                that.canvas.draw();
	            },

	            options: {
	                name: "Diagram",
	                theme: "default",
	                layout: "",
	                zoomRate: 0.1,
	                zoom: 1,
	                zoomMin: 0,
	                zoomMax: 2,
	                dataSource: {},
	                draggable: true,
	                template: "",
	                autoBind: true,
	                editable: {
	                    rotate: {},
	                    resize: {},
	                    text: true,
	                    tools: [],
	                    drag: {
	                        snap: {
	                            size: 10,
	                            angle: 10
	                        }
	                    },
	                    remove: true
	                },
	                pannable: {},
	                selectable: {
	                    key: "none"
	                },
	                tooltip: { enabled: true, format: "{0}" },
	                copy: {
	                    enabled: true,
	                    offsetX: 20,
	                    offsetY: 20
	                },
	                shapeDefaults: diagram.shapeDefaults({ undoable: true }),
	                connectionDefaults: {
	                    editable: {
	                        tools: []
	                    },
	                    type: CASCADING
	                },
	                shapes: [],
	                connections: []
	            },

	            events: [
	                ZOOM_END,
	                ZOOM_START,
	                PAN, SELECT,
	                ITEMROTATE,
	                ITEMBOUNDSCHANGE,
	                CHANGE,
	                CLICK,
	                MOUSE_ENTER,
	                MOUSE_LEAVE,
	                "toolBarClick",
	                "save",
	                "cancel",
	                "edit",
	                "remove",
	                "add",
	                "dataBound",
	                DRAG_START,
	                DRAG,
	                DRAG_END
	            ],

	            items: function() {
	                return $();
	            },

	            _createGlobalToolBar: function() {
	                var editable = this.options.editable;
	                if (editable) {
	                    var tools = editable.tools;
	                    if (this._isEditable && tools !== false && (!tools || tools.length === 0)) {
	                        tools = ["createShape", "undo", "redo", "rotateClockwise", "rotateAnticlockwise"];
	                    }

	                    if (tools && tools.length) {
	                        this.toolBar = new DiagramToolBar(this, {
	                            tools: tools || {},
	                            click: proxy(this._toolBarClick, this),
	                            modal: false
	                        });

	                        this.toolBar.element.css({
	                            textAlign: "left"
	                        });

	                        this.element.prepend(this.toolBar.element);
	                        this._resize();
	                    }
	                }
	            },

	            createShape: function() {
	                if ((this.editor && this.editor.end()) || !this.editor) {
	                    var dataSource = this.dataSource;
	                    var view = dataSource.view() || [];
	                    var index = view.length;
	                    var model = createModel(dataSource, {});
	                    var shape = this._createShape(model, {});

	                    if (!this.trigger("add", { shape: shape })) {
	                        dataSource.insert(index, model);
	                        var inactiveItem = this._inactiveShapeItems.getByUid(model.uid);
	                        inactiveItem.element = shape;
	                        this.edit(shape);
	                    }
	                }
	            },

	            _createShape: function(dataItem, options) {
	                options = deepExtend({}, this.options.shapeDefaults, options);
	                options.dataItem = dataItem;
	                var shape = new Shape(options, this);
	                return shape;
	            },

	            createConnection: function() {
	                if (((this.editor && this.editor.end()) || !this.editor)) {
	                    var connectionsDataSource = this.connectionsDataSource;
	                    var view = connectionsDataSource.view() || [];
	                    var index = view.length;
	                    var model = createModel(connectionsDataSource, {});
	                    var connection = this._createConnection(model);
	                    if (!this.trigger("add", { connection: connection })) {
	                        this._connectionsDataMap[model.uid] = connection;
	                        connectionsDataSource.insert(index, model);
	                        this.addConnection(connection, false);
	                        this.edit(connection);
	                    }
	                }
	            },

	            _createConnection: function(dataItem, source, target) {
	                var options = deepExtend({}, this.options.connectionDefaults);
	                options.dataItem = dataItem;

	                var connection = new Connection(source || new Point(), target || new Point(), options);

	                return connection;
	            },

	            editModel: function(dataItem, editorType) {
	                this.cancelEdit();
	                var editors, template;
	                var editable = this.options.editable;

	                if (editorType == "shape") {
	                    editors = editable.shapeEditors;
	                    template = editable.shapeTemplate;
	                } else if (editorType == "connection") {
	                    var connectionSelectorHandler = proxy(connectionSelector, this);
	                    editors = deepExtend({}, { from: connectionSelectorHandler, to: connectionSelectorHandler }, editable.connectionEditors);
	                    template = editable.connectionTemplate;
	                } else {
	                    return;
	                }

	                this.editor = new PopupEditor(this.element, {
	                    update: proxy(this._update, this),
	                    cancel: proxy(this._cancel, this),
	                    model: dataItem,
	                    type: editorType,
	                    target: this,
	                    editors: editors,
	                    template: template
	                });

	                this.trigger("edit", this._editArgs());
	            },

	            edit: function(item) {
	                if (item.dataItem) {
	                    var editorType = item instanceof Shape ? "shape" : "connection";
	                    this.editModel(item.dataItem, editorType);
	                }
	            },

	            cancelEdit: function() {
	                if (this.editor) {
	                    this._getEditDataSource().cancelChanges(this.editor.model);

	                    this._destroyEditor();
	                }
	            },

	            saveEdit: function() {
	                if (this.editor && this.editor.end() &&
	                    !this.trigger("save", this._editArgs())) {
	                    this._getEditDataSource().sync();
	                }
	            },

	            _update: function() {
	                if (this.editor && this.editor.end() &&
	                    !this.trigger("save", this._editArgs())) {
	                    this._getEditDataSource().sync();
	                    this._destroyEditor();
	                }
	            },

	            _cancel: function() {
	                if (this.editor && !this.trigger("cancel", this._editArgs())) {
	                    var model = this.editor.model;
	                    this._getEditDataSource().cancelChanges(model);
	                    var element = this._connectionsDataMap[model.uid] || this._dataMap[model.id];
	                    if (element) {
	                        element._setOptionsFromModel(model);
	                    }
	                    this._destroyEditor();
	                }
	            },

	            _getEditDataSource: function() {
	                return this.editor.options.type === "shape" ? this.dataSource : this.connectionsDataSource;
	            },

	            _editArgs: function() {
	                var result = { container: this.editor.wrapper };
	                result[this.editor.options.type] = this.editor.model;
	                return result;
	            },

	            _destroyEditor: function() {
	                if (this.editor) {
	                    this.editor.close();
	                    this.editor = null;
	                }
	            },

	            _initElements: function() {
	                this.wrapper = this.element.empty()
	                    .css("position", "relative")
	                    .attr("tabindex", 0)
	                    .addClass("k-widget k-diagram");

	                this.scrollable = $("<div />").appendTo(this.element);
	            },

	            _initDefaults: function(userOptions) {
	                var options = this.options;
	                var editable = options.editable;
	                var shapeDefaults = options.shapeDefaults;
	                var connectionDefaults = options.connectionDefaults;
	                var userShapeDefaults = (userOptions || {}).shapeDefaults;
	                if (editable === false) {
	                    shapeDefaults.editable = false;
	                    connectionDefaults.editable = false;
	                } else {
	                    copyDefaultOptions(editable, shapeDefaults.editable, ["drag", "remove", "connect"]);
	                    copyDefaultOptions(editable, connectionDefaults.editable, ["drag", "remove"]);
	                }

	                if (userShapeDefaults && userShapeDefaults.connectors) {
	                    options.shapeDefaults.connectors = userShapeDefaults.connectors;
	                }
	            },

	            _interactionDefaults: function() {
	                var options = this.options;
	                var selectable = options.selectable;
	                var pannable = options.pannable;
	                var mobile = kendo.support.mobileOS;

	                if (selectable && !defined(selectable.multiple)) {
	                    options.selectable = deepExtend({
	                        multiple: mobile ? false : true
	                    }, options.selectable);
	                }

	                if (pannable && !defined(pannable.key)) {
	                    options.pannable = deepExtend({
	                        key: mobile ? "none" : "ctrl"
	                    }, options.pannable);
	                }
	            },

	            _initCanvas: function() {
	                var canvasContainer = $("<div class='k-layer'></div>").appendTo(this.scrollable)[0];
	                var viewPort = this.viewport();
	                this.canvas = new Canvas(canvasContainer, {
	                    width: viewPort.width || DEFAULT_CANVAS_WIDTH,
	                    height: viewPort.height || DEFAULT_CANVAS_HEIGHT
	                });
	            },

	            _createHandlers: function () {
	                var that = this;
	                var element = that.element;

	                element.on(MOUSEWHEEL_NS, proxy(that._wheel, that))
	                .on("keydown" + NS, proxy(that._keydown, that));

	                that._userEvents = new kendo.UserEvents(this.scrollable, {
	                    multiTouch: true,
	                    fastTap: true,
	                    tap: proxy(that._tap, that),
	                    start: proxy(that._dragStart, that),
	                    move: proxy(that._drag, that),
	                    end: proxy(that._dragEnd, that),
	                    gesturestart: proxy(that._gestureStart, that),
	                    gesturechange: proxy(that._gestureChange, that),
	                    gestureend: proxy(that._gestureEnd, that),
	                    doubleTap: proxy(that._doubleTap, that),
	                    supportDoubleTap: true
	                });

	                that.toolService = new ToolService(that);

	                this.scrollable
	                    .on("mouseover" + NS, proxy(that._mouseover, that))
	                    .on("mouseout" + NS, proxy(that._mouseout, that))
	                    .on("mousemove" + NS, proxy(that._mouseMove, that))
	                    .on("mousedown" + NS, proxy(that._mouseDown, that))
	                    .on("mouseup" + NS, proxy(that._mouseUp, that));

	                this._syncHandler = proxy(that._syncChanges, that);

	                that._resizeHandler = proxy(that.resize, that, false);
	                kendo.onResize(that._resizeHandler);

	                this.bind(ZOOM_START, proxy(that._destroyToolBar, that));
	                this.bind(PAN, proxy(that._destroyToolBar, that));
	            },

	            _dragStart: function (e) {
	                this._pauseMouseHandlers = true;
	                var point = this._eventPositions(e, true);

	                var event = e.event;
	                if (this.toolService.start(point, this._meta(event))) {
	                    this._destroyToolBar();
	                    event.preventDefault();
	                }
	            },

	            _drag: function (e) {
	                var p = this._eventPositions(e);
	                var event = e.event;
	                if (this.toolService.move(p, this._meta(event))) {
	                    event.preventDefault();
	                }
	            },

	            _dragEnd: function (e) {
	                this._pauseMouseHandlers = false;
	                var p = this._eventPositions(e);
	                var event = e.event;
	                if (this.toolService.end(p, this._meta(event))) {
	                    this._createToolBar();
	                    event.preventDefault();
	                }
	            },

	            _mouseMove: function (e) {
	                if (!this._pauseMouseHandlers) {
	                    var p = this._eventPositions(e);
	                    this.toolService._updateHoveredItem(p);
	                    this.toolService._updateCursor(p);
	                }
	            },

	            _mouseDown: function () {
	                this._pauseMouseHandlers = true;
	            },

	            _mouseUp: function () {
	                this._pauseMouseHandlers = false;
	            },

	            _tap: function(e) {
	                var toolService = this.toolService;
	                var selectable = this.options.selectable;
	                var point = this._eventPositions(e);
	                var focused = this.focus();

	                toolService._updateHoveredItem(point);

	                if (toolService.hoveredItem) {
	                    var item = toolService.hoveredItem;

	                    this.trigger("click", {
	                        item: item,
	                        point: point
	                    });

	                    if (selectable && item.options.selectable !== false) {
	                        var multiple = selectable.multiple !== false;
	                        var ctrlPressed = kendo.support.mobileOS || this._meta(e.event).ctrlKey;

	                        if (item.isSelected) {
	                            if (ctrlPressed) {
	                                this._destroyToolBar();
	                                item.select(false);
	                            } else {
	                                this._createToolBar(focused);
	                            }
	                        } else {
	                            this._destroyToolBar();
	                            this.select(item, {
	                                addToSelection: multiple && ctrlPressed
	                            });
	                            this._createToolBar(focused);
	                        }
	                    }
	                } else if (selectable) {
	                    this._destroyToolBar();
	                    this.deselect();
	                }
	            },

	            _keydown: function (e) {
	                if (this.toolService.keyDown(e.keyCode, this._meta(e))) {
	                    e.preventDefault();
	                }
	            },

	            _wheel: function (e) {
	                var delta = mwDelta(e),
	                    p = this._eventPositions(e),
	                    meta = deepExtend(this._meta(e), { delta: delta });

	                if (this.toolService.wheel(p, meta)) {
	                    e.preventDefault();
	                }
	            },

	            _meta: function (e) {
	                return { ctrlKey: e.ctrlKey, metaKey: e.metaKey, altKey: e.altKey, shiftKey: e.shiftKey, type: e.type };
	            },

	            _eventPositions: function (e, start) {
	                var point;
	                if (e.touch) {
	                    var field = start ? "startLocation" : "location";
	                    point = new Point(e.x[field], e.y[field]);
	                } else {
	                    var event = e.originalEvent;
	                    point = new Point(event.pageX, event.pageY);
	                }

	                return this.documentToModel(point);
	            },

	            _gestureStart: function(e) {
	                this._destroyToolBar();
	                this.scroller.disable();
	                var initialCenter = this.documentToModel(new Point(e.center.x, e.center.y));
	                var eventArgs = {
	                    point: initialCenter,
	                    zoom: this.zoom()
	                };

	                if (this.trigger(ZOOM_START, eventArgs)) {
	                    return;
	                }

	                this._gesture = e;
	                this._initialCenter = initialCenter;
	            },

	            _gestureChange: function(e) {
	                var previousGesture = this._gesture;
	                var initialCenter = this._initialCenter;
	                var center = this.documentToView(new Point(e.center.x, e.center.y));
	                var scaleDelta = e.distance / previousGesture.distance;
	                var zoom = this._zoom;
	                var updateZoom = false;

	                if (math.abs(scaleDelta - 1) >= MOBILE_ZOOM_RATE) {
	                    this._zoom = zoom = this._getValidZoom(zoom * scaleDelta);
	                    this.options.zoom = zoom;
	                    this._gesture = e;
	                    updateZoom = true;
	                }

	                var zoomedPoint = initialCenter.times(zoom);
	                var pan = center.minus(zoomedPoint);
	                if (updateZoom || this._pan.distanceTo(pan) >= MOBILE_PAN_DISTANCE) {
	                    this._panTransform(pan);
	                    this._updateAdorners();
	                }

	                e.preventDefault();
	            },

	            _doubleTap: function(e) {
	                var diagram = this;
	                var pointPosition = this._eventPositions(e);
	                var options = diagram.options;
	                var zoomRate = options.zoomRate;
	                var zoom = diagram.zoom() + zoomRate;
	                var meta = this._meta(e);
	                var zoomOptions = { point: pointPosition, meta: meta, zoom: zoom };


	                if (diagram.trigger(ZOOM_START, zoomOptions)) {
	                    return;
	                }

	                zoom = kendo.dataviz.round(Math.max(options.zoomMin, Math.min(options.zoomMax, zoom)), 2);
	                zoomOptions.zoom = zoom;

	                diagram.zoom(zoom, zoomOptions);
	                diagram.trigger(ZOOM_END, zoomOptions);
	            },

	            _gestureEnd: function() {
	                if (this.options.pannable !== false)  {
	                    this.scroller.enable();
	                }
	                this.trigger(ZOOM_END, {
	                    point: this._initialCenter,
	                    zoom: this.zoom()
	                });
	            },

	            _resize: function() {
	                var viewport = this.viewport();
	                if (this.canvas) {
	                    this.canvas.size(viewport);
	                }

	                if (this.scrollable && this.toolBar) {
	                    this.scrollable.height(viewport.height);
	                }
	            },

	            _mouseover: function(e) {
	                var node = e.target._kendoNode;
	                if (node && node.srcElement._hover) {
	                    node.srcElement._hover(true, node.srcElement);
	                }
	            },

	            _mouseout: function(e) {
	                var node = e.target._kendoNode;
	                if (node && node.srcElement._hover) {
	                    node.srcElement._hover(false, node.srcElement);
	                }
	            },

	            _initTheme: function() {
	                var that = this;
	                var themeName = ((that.options || {}).theme || "").toLowerCase();
	                var themes = dataviz.ui.themes || {};
	                var themeOptions;

	                if(dataviz.SASS_THEMES.indexOf(themeName) != -1) {
	                    themeOptions = dataviz.autoTheme().diagram;
	                }
	                else {
	                    themeOptions = (themes[themeName] || {}).diagram;
	                }

	                that.options = deepExtend({}, themeOptions, that.options);
	                if (that.options.editable === true) {
	                    deepExtend(that.options, {
	                        editable: (themeOptions || {}).editable
	                    });
	                }
	            },

	            _createOptionElements: function() {
	                var options = this.options;
	                var shapesLength = options.shapes.length;

	                if (shapesLength) {
	                    this._createShapes();
	                }

	                if (options.connections.length) {
	                    this._createConnections();
	                }

	                if (shapesLength && options.layout) {
	                    this.layout(options.layout);
	                }
	            },

	            _createShapes: function() {
	                var that = this,
	                    options = that.options,
	                    shapes = options.shapes,
	                    shape, i;

	                for (i = 0; i < shapes.length; i++) {
	                    shape = shapes[i];
	                    that.addShape(shape);
	                }
	            },

	            _createConnections: function() {
	                var diagram = this,
	                    options = diagram.options,
	                    defaults = options.connectionDefaults,
	                    connections = options.connections,
	                    conn, source, target, i;

	                for(i = 0; i < connections.length; i++) {
	                    conn = connections[i];
	                    source = diagram._findConnectionTarget(conn.from);
	                    target = diagram._findConnectionTarget(conn.to);

	                    diagram.connect(source, target, deepExtend({}, defaults, conn));
	                }
	            },

	            _findConnectionTarget: function(options) {
	                options = options || {};
	                var diagram = this;
	                var shapeId = isString(options) ? options : options.shapeId || options.id;
	                var target;
	                if (shapeId) {
	                    target = diagram.getShapeById(shapeId);
	                    if (options.connector) {
	                        target = target.getConnector(options.connector);
	                    }
	                } else {
	                    target = new Point(options.x || 0, options.y || 0);
	                }

	                return target;
	            },

	            destroy: function () {
	                var that = this;
	                Widget.fn.destroy.call(that);

	                if (this._userEvents) {
	                    this._userEvents.destroy();
	                }

	                kendo.unbindResize(that._resizeHandler);

	                that.clear();
	                that.element.off(NS);
	                that.scroller.wrapper.off(NS);
	                that.canvas.destroy(true);
	                that.canvas = undefined;

	                that._destroyEditor();
	                that.destroyScroller();
	                that._destroyGlobalToolBar();
	                that._destroyToolBar();
	            },

	            destroyScroller: function () {
	                var scroller = this.scroller;

	                if (!scroller) {
	                    return;
	                }

	                scroller.destroy();
	                scroller.element.remove();
	                this.scroller = null;
	            },

	            save: function () {
	                var json = {
	                    shapes: [],
	                    connections: []
	                };
	                var i, connection, shape;

	                for (i = 0; i < this.shapes.length; i++) {
	                    shape = this.shapes[i];
	                    if (shape.options.serializable) {
	                        json.shapes.push(shape.options);
	                    }
	                }

	                for (i = 0; i < this.connections.length; i++) {
	                    connection = this.connections[i];

	                    json.connections.push(deepExtend({}, connection.options, connection.toJSON()));
	                }

	                return json;
	            },

	            focus: function() {
	                if (!this.element.is(kendo._activeElement())) {
	                    var element = this.element,
	                        scrollContainer = element[0],
	                        containers = [],
	                        offsets = [],
	                        documentElement = document.documentElement,
	                        i;

	                    do {
	                        scrollContainer = scrollContainer.parentNode;

	                        if (scrollContainer.scrollHeight > scrollContainer.clientHeight) {
	                            containers.push(scrollContainer);
	                            offsets.push(scrollContainer.scrollTop);
	                        }
	                    } while (scrollContainer != documentElement);

	                    element.focus();

	                    for (i = 0; i < containers.length; i++) {
	                        containers[i].scrollTop = offsets[i];
	                    }
	                    return true;
	                }
	            },

	            load: function(options) {
	                this.clear();

	                this.setOptions(options);
	                this._createShapes();
	                this._createConnections();
	            },

	            setOptions: function(options) {
	                deepExtend(this.options, options);
	            },

	            clear: function () {
	                var that = this;

	                that.select(false);
	                that.mainLayer.clear();
	                that._shapesQuadTree.clear();
	                that._initialize();
	            },
	            /**
	             * Connects two items.
	             * @param source Shape, Connector, Point.
	             * @param target Shape, Connector, Point.
	             * @param options Connection options that will be passed to the newly created connection.
	             * @returns The newly created connection.
	             */
	            connect: function (source, target, options) {
	                var connection;
	                if (this.connectionsDataSource && this._isEditable) {
	                    var dataItem = this.connectionsDataSource.add({});
	                    connection = this._connectionsDataMap[dataItem.uid];
	                    connection.source(source);
	                    connection.target(target);
	                    connection.redraw(options);
	                    connection.updateModel();
	                } else {
	                    connection = new Connection(source, target,
	                        deepExtend({ }, this.options.connectionDefaults, options));

	                    this.addConnection(connection);
	                }

	                return connection;
	            },
	            /**
	             * Determines whether the the two items are connected.
	             * @param source Shape, Connector, Point.
	             * @param target Shape, Connector, Point.
	             * @returns true if the two items are connected.
	             */
	            connected: function (source, target) {
	                for (var i = 0; i < this.connections.length; i++) {
	                    var c = this.connections[i];
	                    if (c.from == source && c.to == target) {
	                        return true;
	                    }
	                }

	                return false;
	            },
	            /**
	             * Adds connection to the diagram.
	             * @param connection Connection.
	             * @param undoable Boolean.
	             * @returns The newly created connection.
	             */
	            addConnection: function (connection, undoable) {
	                if (undoable !== false) {
	                    this.undoRedoService.add(
	                        new diagram.AddConnectionUnit(connection, this), false);
	                }

	                connection.diagram = this;
	                connection._setOptionsFromModel();
	                connection.refresh();
	                this.mainLayer.append(connection.visual);
	                this.connections.push(connection);

	                this.trigger(CHANGE, {
	                    added: [connection],
	                    removed: []
	                });

	                return connection;
	            },

	            _addConnection: function (connection, undoable) {
	                var connectionsDataSource = this.connectionsDataSource;
	                var dataItem;
	                if (connectionsDataSource && this._isEditable) {
	                    dataItem = createModel(connectionsDataSource, cloneDataItem(connection.dataItem));
	                    connection.dataItem = dataItem;
	                    connection.updateModel();

	                    if (!this.trigger("add", { connection: connection })) {
	                        this._connectionsDataMap[dataItem.uid] = connection;

	                        connectionsDataSource.add(dataItem);
	                        this.addConnection(connection, undoable);
	                        connection._updateConnectors();

	                        return connection;
	                    }
	                } else if (!this.trigger("add", { connection: connection })) {
	                    this.addConnection(connection, undoable);
	                    connection._updateConnectors();
	                    return connection;
	                }
	            },

	            /**
	             * Adds shape to the diagram.
	             * @param item Shape, Point. If point is passed it will be created new Shape and positioned at that point.
	             * @param options. The options to be passed to the newly created Shape.
	             * @returns The newly created shape.
	             */
	            addShape: function(item, undoable) {
	                var shape,
	                    shapeDefaults = this.options.shapeDefaults;

	                if (item instanceof Shape) {
	                    shape = item;
	                } else if (!(item instanceof kendo.Class)) {
	                    shapeDefaults = deepExtend({}, shapeDefaults, item || {});
	                    shape = new Shape(shapeDefaults, this);
	                } else {
	                    return;
	                }

	                if (undoable !== false) {
	                    this.undoRedoService.add(new diagram.AddShapeUnit(shape, this), false);
	                }

	                this.shapes.push(shape);
	                if (shape.diagram !== this) {
	                    this._shapesQuadTree.insert(shape);
	                    shape.diagram = this;
	                }
	                this.mainLayer.append(shape.visual);

	                this.trigger(CHANGE, {
	                    added: [shape],
	                    removed: []
	                });

	                return shape;
	            },

	            _addShape: function(shape, undoable) {
	                var that = this;
	                var dataSource = that.dataSource;
	                var dataItem;
	                if (dataSource && this._isEditable) {
	                    dataItem = createModel(dataSource, cloneDataItem(shape.dataItem));
	                    shape.dataItem = dataItem;
	                    shape.updateModel();

	                    if (!this.trigger("add", { shape: shape })) {
	                        this.dataSource.add(dataItem);
	                        var inactiveItem = this._inactiveShapeItems.getByUid(dataItem.uid);
	                        inactiveItem.element = shape;
	                        inactiveItem.undoable = undoable;
	                        return shape;
	                    }
	                } else if (!this.trigger("add", { shape: shape })) {
	                    return this.addShape(shape, undoable);
	                }
	            },
	            /**
	             * Removes items (or single item) from the diagram.
	             * @param items DiagramElement, Array of Items.
	             * @param undoable.
	             */

	           remove: function(items, undoable) {
	                items = isArray(items) ? items.slice(0) : [items];
	                var elements = splitDiagramElements(items);
	                var shapes = elements.shapes;
	                var connections = elements.connections;
	                var i;

	                if (!defined(undoable)) {
	                    undoable = true;
	                }

	                if (undoable) {
	                    this.undoRedoService.begin();
	                }

	                this._suspendModelRefresh();
	                for (i = shapes.length - 1; i >= 0; i--) {
	                   this._removeItem(shapes[i], undoable, connections);
	                }

	                for (i = connections.length - 1; i >= 0; i--) {
	                    this._removeItem(connections[i], undoable);
	                }

	                this._resumeModelRefresh();

	                if (undoable) {
	                    this.undoRedoService.commit(false);
	                }

	                this.trigger(CHANGE, {
	                    added: [],
	                    removed: items
	                });
	            },

	            _removeShapeDataItem: function(item) {
	                if (this._isEditable) {
	                    this.dataSource.remove(item.dataItem);
	                    delete this._dataMap[item.dataItem.id];
	                }
	            },

	            _removeConnectionDataItem: function(item) {
	                if (this._isEditable) {
	                    this.connectionsDataSource.remove(item.dataItem);
	                    delete this._connectionsDataMap[item.dataItem.uid];
	                }
	            },

	            _triggerRemove: function(items){
	                var toRemove = [];
	                var item, args, editable;

	                for (var idx = 0; idx < items.length; idx++) {
	                    item = items[idx];
	                    editable = item.options.editable;
	                    if (item instanceof Shape) {
	                        args = { shape: item };
	                    } else {
	                        args = { connection: item };
	                    }
	                    if (editable && editable.remove !== false && !this.trigger("remove", args)) {
	                        toRemove.push(item);
	                    }
	                }
	                return toRemove;
	            },

	            /**
	             * Executes the next undoable action on top of the undo stack if any.
	             */
	            undo: function () {
	                this.undoRedoService.undo();
	            },
	            /**
	             * Executes the previous undoable action on top of the redo stack if any.
	             */
	            redo: function () {
	                this.undoRedoService.redo();
	            },
	            /**
	             * Selects items on the basis of the given input or returns the current selection if none.
	             * @param itemsOrRect DiagramElement, Array of elements, "All", false or Rect. A value 'false' will deselect everything.
	             * @param options
	             * @returns {Array}
	             */
	            select: function (item, options) {
	                if (isDefined(item)) {
	                    options = deepExtend({ addToSelection: false }, options);

	                    var addToSelection = options.addToSelection,
	                        items = [],
	                        selected = [],
	                        i, element;

	                    if (!addToSelection) {
	                        this.deselect();
	                    }

	                    this._internalSelection = true;

	                    if (item instanceof Array) {
	                        items = item;
	                    } else if (item instanceof DiagramElement) {
	                        items = [ item ];
	                    }

	                    for (i = 0; i < items.length; i++) {
	                        element = items[i];
	                        if (element.select(true)) {
	                            selected.push(element);
	                        }
	                    }

	                    this._selectionChanged(selected, []);

	                    this._internalSelection = false;
	                } else {
	                    return this._selectedItems;
	                }
	            },

	            selectAll: function() {
	                this.select(this.shapes.concat(this.connections));
	            },

	            selectArea: function(rect) {
	                var i, items, item;
	                this._internalSelection = true;
	                var selected = [];
	                if (rect instanceof Rect) {
	                    items = this.shapes.concat(this.connections);
	                    for (i = 0; i < items.length; i++) {
	                        item = items[i];
	                        if ((!rect || item._hitTest(rect)) && item.options.enable) {
	                            if (item.select(true)) {
	                                selected.push(item);
	                            }
	                        }
	                    }
	                }

	                this._selectionChanged(selected, []);
	                this._internalSelection = false;
	            },

	            deselect: function(item) {
	                this._internalSelection = true;
	                var deselected = [],
	                    items = [],
	                    element, i;

	                if (item instanceof Array) {
	                    items = item;
	                } else if (item instanceof DiagramElement) {
	                    items.push(item);
	                } else if (!isDefined(item)) {
	                    items = this._selectedItems.slice(0);
	                }

	                for (i = 0; i < items.length; i++) {
	                    element = items[i];
	                    if (element.select(false)) {
	                        deselected.push(element);
	                    }
	                }

	                this._selectionChanged([], deselected);
	                this._internalSelection = false;
	            },
	            /**
	             * Brings to front the passed items.
	             * @param items DiagramElement, Array of Items.
	             * @param undoable. By default the action is undoable.
	             */
	            toFront: function (items, undoable) {
	                if (!items) {
	                    items = this._selectedItems.slice();
	                }

	                var result = this._getDiagramItems(items), indices;
	                if (!defined(undoable) || undoable) {
	                    indices = indicesOfItems(this.mainLayer, result.visuals);
	                    var unit = new ToFrontUnit(this, items, indices);
	                    this.undoRedoService.add(unit);
	                } else {
	                    this.mainLayer.toFront(result.visuals);
	                    this._fixOrdering(result, true);
	                }
	            },
	            /**
	             * Sends to back the passed items.
	             * @param items DiagramElement, Array of Items.
	             * @param undoable. By default the action is undoable.
	             */
	            toBack: function (items, undoable) {
	                if (!items) {
	                    items = this._selectedItems.slice();
	                }

	                var result = this._getDiagramItems(items), indices;
	                if (!defined(undoable) || undoable) {
	                    indices = indicesOfItems(this.mainLayer, result.visuals);
	                    var unit = new ToBackUnit(this, items, indices);
	                    this.undoRedoService.add(unit);
	                } else {
	                    this.mainLayer.toBack(result.visuals);
	                    this._fixOrdering(result, false);
	                }
	            },
	            /**
	             * Bring into view the passed item(s) or rectangle.
	             * @param items DiagramElement, Array of Items, Rect.
	             * @param options. align - controls the position of the calculated rectangle relative to the viewport.
	             * "Center middle" will position the items in the center. animate - controls if the pan should be animated.
	             */
	            bringIntoView: function (item, options) { // jQuery|Item|Array|Rect
	                var viewport = this.viewport();
	                var aligner = new diagram.RectAlign(viewport);
	                var current, rect, original, newPan;

	                if (viewport.width === 0 || viewport.height === 0) {
	                    return;
	                }

	                options = deepExtend({animate: false, align: "center middle"}, options);
	                if (options.align == "none") {
	                    options.align = "center middle";
	                }

	                if (item instanceof DiagramElement) {
	                    rect = item.bounds(TRANSFORMED);
	                } else if (isArray(item)) {
	                    rect = this.boundingBox(item);
	                } else if (item instanceof Rect) {
	                    rect = item.clone();
	                }

	                original = rect.clone();

	                rect.zoom(this._zoom);

	                if (rect.width > viewport.width || rect.height > viewport.height) {
	                    this._zoom = this._getValidZoom(math.min(viewport.width / original.width, viewport.height / original.height));
	                    rect = original.clone().zoom(this._zoom);
	                }

	                this._zoomMainLayer();

	                current = rect.clone();
	                aligner.align(rect, options.align);

	                newPan = rect.topLeft().minus(current.topLeft());
	                this.pan(newPan.times(-1), options.animate);
	            },

	            alignShapes: function (direction) {
	                if (isUndefined(direction)) {
	                    direction = "Left";
	                }
	                var items = this.select(),
	                    val,
	                    item,
	                    i;

	                if (items.length === 0) {
	                    return;
	                }

	                switch (direction.toLowerCase()) {
	                    case "left":
	                    case "top":
	                        val = MAX_VALUE;
	                        break;
	                    case "right":
	                    case "bottom":
	                        val = MIN_VALUE;
	                        break;
	                }

	                for (i = 0; i < items.length; i++) {
	                    item = items[i];
	                    if (item instanceof Shape) {
	                        switch (direction.toLowerCase()) {
	                            case "left":
	                                val = math.min(val, item.options.x);
	                                break;
	                            case "top":
	                                val = math.min(val, item.options.y);
	                                break;
	                            case "right":
	                                val = math.max(val, item.options.x);
	                                break;
	                            case "bottom":
	                                val = math.max(val, item.options.y);
	                                break;
	                        }
	                    }
	                }
	                var undoStates = [];
	                var shapes = [];
	                for (i = 0; i < items.length; i++) {
	                    item = items[i];
	                    if (item instanceof Shape) {
	                        shapes.push(item);
	                        undoStates.push(item.bounds());
	                        switch (direction.toLowerCase()) {
	                            case "left":
	                            case "right":
	                                item.position(new Point(val, item.options.y));
	                                break;
	                            case "top":
	                            case "bottom":
	                                item.position(new Point(item.options.x, val));
	                                break;
	                        }
	                    }
	                }
	                var unit = new diagram.TransformUnit(shapes, undoStates);
	                this.undoRedoService.add(unit, false);
	            },

	            zoom: function (zoom, options) {
	                if (zoom) {
	                    var staticPoint = options ? options.point : new diagram.Point(0, 0);
	                    // var meta = options ? options.meta : 0;
	                    zoom = this._zoom = this._getValidZoom(zoom);

	                    if (!isUndefined(staticPoint)) {//Viewpoint vector is constant
	                        staticPoint = new diagram.Point(math.round(staticPoint.x), math.round(staticPoint.y));
	                        var zoomedPoint = staticPoint.times(zoom);
	                        var viewportVector = this.modelToView(staticPoint);
	                        var raw = viewportVector.minus(zoomedPoint);//pan + zoomed point = viewpoint vector
	                        this._storePan(new diagram.Point(math.round(raw.x), math.round(raw.y)));
	                    }

	                    if (options) {
	                        options.zoom = zoom;
	                    }

	                    this._panTransform();

	                    this.canvas.surface.hideTooltip();

	                    this._updateAdorners();
	                }

	                return this._zoom;
	            },

	            _getPan: function(pan) {
	                var canvas = this.canvas;
	                if (!canvas.translate) {
	                    pan = pan.plus(this._pan);
	                }
	                return pan;
	            },

	            pan: function (pan, animate) {
	                if (pan instanceof Point) {
	                    var that = this;
	                    var scroller = that.scroller;
	                    pan = that._getPan(pan);
	                    pan = pan.times(-1);

	                    if (animate) {
	                        scroller.animatedScrollTo(pan.x, pan.y, function() {
	                            that._updateAdorners();
	                        });
	                    } else {
	                        scroller.scrollTo(pan.x, pan.y);
	                        that._updateAdorners();
	                    }
	                } else {
	                    return this._pan.times(-1);
	                }
	            },

	            viewport: function () {
	                var element = this.element;
	                var width = element.width();
	                var height = element.height();

	                if (this.toolBar) {
	                    height -= outerHeight(this.toolBar.element);
	                }

	                return new Rect(0, 0, width, height);
	            },
	            copy: function () {
	                if (this.options.copy.enabled) {
	                    this._clipboard = [];
	                    this._copyOffset = 1;
	                    for (var i = 0; i < this._selectedItems.length; i++) {
	                        var item = this._selectedItems[i];
	                        this._clipboard.push(item);
	                    }
	                }
	            },
	            cut: function () {
	                if (this.options.copy.enabled) {
	                    this._clipboard = [];
	                    this._copyOffset = 0;
	                    for (var i = 0; i < this._selectedItems.length; i++) {
	                        var item = this._selectedItems[i];
	                        this._clipboard.push(item);
	                    }
	                    this.remove(this._clipboard, true);
	                }
	            },

	            paste: function () {
	                if (this._clipboard.length > 0) {
	                    var item, copied, i;
	                    var mapping = {};
	                    var elements = splitDiagramElements(this._clipboard);
	                    var connections = elements.connections;
	                    var shapes = elements.shapes;
	                    var offset = {
	                        x: this._copyOffset * this.options.copy.offsetX,
	                        y: this._copyOffset * this.options.copy.offsetY
	                    };
	                    this.deselect();
	                    // first the shapes
	                    for (i = 0; i < shapes.length; i++) {
	                        item = shapes[i];
	                        copied = item.clone();
	                        mapping[item.id] = copied;
	                        copied.position(new Point(item.options.x + offset.x, item.options.y + offset.y));
	                        copied.diagram = this;
	                        copied = this._addShape(copied);
	                        if (copied) {
	                            copied.select();
	                        }
	                    }
	                    // then the connections
	                    for (i = 0; i < connections.length; i++) {
	                        item = connections[i];
	                        copied = this._addConnection(item.clone());
	                        if (copied) {
	                            this._updateCopiedConnection(copied, item, "source", mapping, offset);
	                            this._updateCopiedConnection(copied, item, "target", mapping, offset);

	                            copied.select(true);
	                            copied.updateModel();
	                        }
	                    }

	                    this._syncChanges();

	                    this._copyOffset += 1;
	                }
	            },

	            _updateCopiedConnection: function(connection, sourceConnection, connectorName, mapping, offset) {
	                var onActivate, inactiveItem, targetShape;
	                var target = sourceConnection[connectorName]();
	                var diagram = this;
	                if (target instanceof Connector && mapping[target.shape.id]) {
	                    targetShape = mapping[target.shape.id];
	                    if (diagram.getShapeById(targetShape.id)) {
	                        connection[connectorName](targetShape.getConnector(target.options.name));
	                    } else {
	                        inactiveItem = diagram._inactiveShapeItems.getByUid(targetShape.dataItem.uid);
	                        if (inactiveItem) {
	                            onActivate = function(item) {
	                                targetShape = diagram._dataMap[item.id];
	                                connection[connectorName](targetShape.getConnector(target.options.name));
	                                connection.updateModel();
	                            };
	                            diagram._deferredConnectionUpdates.push(inactiveItem.onActivate(onActivate));
	                        }
	                    }
	                } else {
	                    connection[connectorName](new Point(sourceConnection[connectorName + "Point"]().x + offset.x, sourceConnection[connectorName + "Point"]().y + offset.y));
	                }
	            },
	            /**
	             * Gets the bounding rectangle of the given items.
	             * @param items DiagramElement, Array of elements.
	             * @param origin Boolean. Pass 'true' if you need to get the bounding box of the shapes without their rotation offset.
	             * @returns {Rect}
	             */
	            boundingBox: function (items, origin) {
	                var rect = Rect.empty(), temp,
	                    di = isDefined(items) ? this._getDiagramItems(items) : {shapes: this.shapes};
	                if (di.shapes.length > 0) {
	                    var item = di.shapes[0];
	                    rect = item.bounds(ROTATED);
	                    for (var i = 1; i < di.shapes.length; i++) {
	                        item = di.shapes[i];
	                        temp = item.bounds(ROTATED);
	                        if (origin === true) {
	                            temp.x -= item._rotationOffset.x;
	                            temp.y -= item._rotationOffset.y;
	                        }
	                        rect = rect.union(temp);
	                    }
	                }
	                return rect;
	            },

	            _containerOffset: function() {
	                var containerOffset = this.element.offset();
	                if (this.toolBar) {
	                    containerOffset.top += outerHeight(this.toolBar.element);
	                }
	                return containerOffset;
	            },

	            documentToView: function(point) {
	                var containerOffset = this._containerOffset();

	                return new Point(point.x - containerOffset.left, point.y - containerOffset.top);
	            },
	            viewToDocument: function(point) {
	                var containerOffset = this._containerOffset();

	                return new Point(point.x + containerOffset.left, point.y + containerOffset.top);
	            },
	            viewToModel: function(point) {
	                return this._transformWithMatrix(point, this._matrixInvert);
	            },
	            modelToView: function(point) {
	                return this._transformWithMatrix(point, this._matrix);
	            },
	            modelToLayer: function(point) {
	                return this._transformWithMatrix(point, this._layerMatrix);
	            },
	            layerToModel: function(point) {
	                return this._transformWithMatrix(point, this._layerMatrixInvert);
	            },
	            documentToModel: function(point) {
	                var viewPoint = this.documentToView(point);
	                if (!this.canvas.translate) {
	                    viewPoint.x = viewPoint.x + this.scroller.scrollLeft;
	                    viewPoint.y = viewPoint.y + this.scroller.scrollTop;
	                }
	                return this.viewToModel(viewPoint);
	            },
	            modelToDocument: function(point) {
	                return this.viewToDocument(this.modelToView(point));
	            },
	            _transformWithMatrix: function(point, matrix) {
	                var result = point;
	                if (point instanceof Point) {
	                    if (matrix) {
	                        result = matrix.apply(point);
	                    }
	                }
	                else {
	                    var tl = this._transformWithMatrix(point.topLeft(), matrix),
	                        br = this._transformWithMatrix(point.bottomRight(), matrix);
	                    result = Rect.fromPoints(tl, br);
	                }
	                return result;
	            },

	            setDataSource: function(dataSource) {
	                this.options.dataSource = dataSource;
	                this._dataSource();
	                if (this.options.autoBind) {
	                    this.dataSource.fetch();
	                }
	            },

	            setConnectionsDataSource: function(dataSource) {
	                this.options.connectionsDataSource = dataSource;
	                this._connectionDataSource();
	                if (this.options.autoBind) {
	                    this.connectionsDataSource.fetch();
	                }
	            },

	            /**
	             * Performs a diagram layout of the given type.
	             * @param layoutType The layout algorithm to be applied (TreeLayout, LayeredLayout, SpringLayout).
	             * @param options Layout-specific options.
	             */
	            layout: function (options) {
	                this._layouting = true;
	                // TODO: raise layout event?
	                var type;
	                if(isUndefined(options)) {
	                    options = this.options.layout;
	                }
	                if (isUndefined(options) || isUndefined(options.type)) {
	                    type = "Tree";
	                }
	                else {
	                    type = options.type;
	                }
	                var l;
	                switch (type.toLowerCase()) {
	                    case "tree":
	                        l = new diagram.TreeLayout(this);
	                        break;

	                    case "layered":
	                        l = new diagram.LayeredLayout(this);
	                        break;

	                    case "forcedirected":
	                    case "force":
	                    case "spring":
	                    case "springembedder":
	                        l = new diagram.SpringLayout(this);
	                        break;
	                    default:
	                        throw "Layout algorithm '" + type + "' is not supported.";
	                }
	                var initialState = new diagram.LayoutState(this);
	                var finalState = l.layout(options);
	                if (finalState) {
	                    var unit = new diagram.LayoutUndoUnit(initialState, finalState, options ? options.animate : null);
	                    this.undoRedoService.add(unit);
	                }
	                this._layouting = false;
	                this._redrawConnections();
	            },
	            /**
	             * Gets a shape on the basis of its identifier.
	             * @param id (string) the identifier of a shape.
	             * @returns {Shape}
	             */
	            getShapeById: function (id) {
	                var found;
	                found = Utils.first(this.shapes, function (s) {
	                    return s.visual.id === id;
	                });
	                if (found) {
	                    return found;
	                }
	                found = Utils.first(this.connections, function (c) {
	                    return c.visual.id === id;
	                });
	                return found;
	            },

	            getShapeByModelId: function (id) {
	                var shape;
	                if (this._isEditable) {
	                    shape = this._dataMap[id];
	                } else {
	                    shape = Utils.first(this.shapes, function(shape) {
	                        return (shape.dataItem || {}).id === id;
	                    });
	                }
	                return shape;
	            },

	            getShapeByModelUid: function(uid) {
	                var shape;
	                if (this._isEditable) {
	                    shape = Utils.first(this.shapes, function(shape) {
	                        return (shape.dataItem || {}).uid === uid;
	                    });
	                } else {
	                    shape = this._dataMap[uid];
	                }
	                return shape;
	            },

	            getConnectionByModelId: function(id) {
	                var connection;
	                if (this.connectionsDataSource) {
	                    connection = Utils.first(this.connections, function(connection) {
	                        return (connection.dataItem || {}).id === id;
	                    });
	                }
	                return connection;
	            },

	            getConnectionByModelUid: function(uid) {
	                var connection;
	                if (this.connectionsDataSource) {
	                    connection = this._connectionsDataMap[uid];
	                }
	                return connection;
	            },

	            _extendLayoutOptions: function(options) {
	                if(options.layout) {
	                    options.layout = deepExtend({}, diagram.LayoutBase.fn.defaultOptions || {}, options.layout);
	                }
	            },

	            _selectionChanged: function (selected, deselected) {
	                if (selected.length || deselected.length) {
	                    this.trigger(SELECT, { selected: selected, deselected: deselected });
	                }
	            },
	            _getValidZoom: function (zoom) {
	                return math.min(math.max(zoom, this.options.zoomMin), this.options.zoomMax);
	            },
	            _panTransform: function (pos) {
	                var diagram = this,
	                    pan = pos || diagram._pan;

	                if (diagram.canvas.translate) {
	                    diagram.scroller.scrollTo(pan.x, pan.y);
	                    diagram._zoomMainLayer();
	                } else {
	                    diagram._storePan(pan);
	                    diagram._transformMainLayer();
	                }
	            },

	            _finishPan: function () {
	                this.trigger(PAN, {total: this._pan, delta: Number.NaN});
	            },
	            _storePan: function (pan) {
	                this._pan = pan;
	                this._storeViewMatrix();
	            },
	            _zoomMainLayer: function () {
	                var zoom = this._zoom;

	                var transform = new CompositeTransform(0, 0, zoom, zoom);
	                transform.render(this.mainLayer);
	                this._storeLayerMatrix(transform);
	                this._storeViewMatrix();
	            },
	            _transformMainLayer: function () {
	                var pan = this._pan,
	                    zoom = this._zoom;

	                var transform = new CompositeTransform(pan.x, pan.y, zoom, zoom);
	                transform.render(this.mainLayer);
	                this._storeLayerMatrix(transform);
	                this._storeViewMatrix();
	            },
	            _storeLayerMatrix: function(canvasTransform) {
	                this._layerMatrix = canvasTransform.toMatrix();
	                this._layerMatrixInvert = canvasTransform.invert().toMatrix();
	            },
	            _storeViewMatrix: function() {
	                var pan = this._pan,
	                    zoom = this._zoom;

	                var transform = new CompositeTransform(pan.x, pan.y, zoom, zoom);
	                this._matrix = transform.toMatrix();
	                this._matrixInvert = transform.invert().toMatrix();
	            },
	            _toIndex: function (items, indices) {
	                var result = this._getDiagramItems(items);
	                this.mainLayer.toIndex(result.visuals, indices);
	                this._fixOrdering(result, false);
	            },
	            _fixOrdering: function (result, toFront) {
	                var shapePos = toFront ? this.shapes.length - 1 : 0,
	                    conPos = toFront ? this.connections.length - 1 : 0,
	                    i, item;
	                for (i = 0; i < result.shapes.length; i++) {
	                    item = result.shapes[i];
	                    Utils.remove(this.shapes, item);
	                    Utils.insert(this.shapes, item, shapePos);
	                }
	                for (i = 0; i < result.cons.length; i++) {
	                    item = result.cons[i];
	                    Utils.remove(this.connections, item);
	                    Utils.insert(this.connections, item, conPos);
	                }
	            },
	            _getDiagramItems: function (items) {
	                var i, result = {}, args = items;
	                result.visuals = [];
	                result.shapes = [];
	                result.cons = [];

	                if (!items) {
	                    args = this._selectedItems.slice();
	                } else if (!isArray(items)) {
	                    args = [items];
	                }

	                for (i = 0; i < args.length; i++) {
	                    var item = args[i];
	                    if (item instanceof Shape) {
	                        result.shapes.push(item);
	                        result.visuals.push(item.visual);
	                    } else if (item instanceof Connection) {
	                        result.cons.push(item);
	                        result.visuals.push(item.visual);
	                    }
	                }

	                return result;
	            },

	            _removeItem: function (item, undoable, removedConnections) {
	                item.select(false);
	                if (item instanceof Shape) {
	                    this._removeShapeDataItem(item);
	                    this._removeShape(item, undoable, removedConnections);
	                } else if (item instanceof Connection) {
	                    this._removeConnectionDataItem(item);
	                    this._removeConnection(item, undoable);
	                }

	                this.mainLayer.remove(item.visual);
	            },

	            _removeShape: function (shape, undoable, removedConnections) {
	                var i, connection, connector,
	                    sources = [], targets = [];
	                this.toolService._removeHover();

	                if (undoable) {
	                    this.undoRedoService.addCompositeItem(new DeleteShapeUnit(shape));
	                }
	                Utils.remove(this.shapes, shape);
	                this._shapesQuadTree.remove(shape);

	                for (i = 0; i < shape.connectors.length; i++) {
	                    connector = shape.connectors[i];
	                    for (var j = 0; j < connector.connections.length; j++) {
	                        connection = connector.connections[j];
	                        if (!removedConnections || !dataviz.inArray(connection, removedConnections)) {
	                            if (connection.sourceConnector == connector) {
	                                sources.push(connection);
	                            } else if (connection.targetConnector == connector) {
	                                targets.push(connection);
	                            }
	                        }
	                    }
	                }

	                for (i = 0; i < sources.length; i++) {
	                    sources[i].source(null, undoable);
	                    sources[i].updateModel();
	                }
	                for (i = 0; i < targets.length; i++) {
	                    targets[i].target(null, undoable);
	                    targets[i].updateModel();
	                }
	            },

	            _removeConnection: function (connection, undoable) {
	                if (connection.sourceConnector) {
	                    Utils.remove(connection.sourceConnector.connections, connection);
	                }
	                if (connection.targetConnector) {
	                    Utils.remove(connection.targetConnector.connections, connection);
	                }
	                if (undoable) {
	                    this.undoRedoService.addCompositeItem(new DeleteConnectionUnit(connection));
	                }

	                Utils.remove(this.connections, connection);
	            },

	            _removeDataItems: function(items, recursive) {
	                var item, children, shape, idx;
	                items = isArray(items) ? items : [items];

	                while (items.length) {
	                    item = items.shift();
	                    shape = this._dataMap[item.uid];
	                    if (shape) {
	                        this._removeShapeConnections(shape);
	                        this._removeItem(shape, false);
	                        delete this._dataMap[item.uid];
	                        if (recursive && item.hasChildren && item.loaded()) {
	                            children = item.children.data();
	                            for (idx = 0; idx < children.length; idx++) {
	                                items.push(children[idx]);
	                            }
	                        }
	                    }
	                }
	            },

	            _removeShapeConnections: function(shape) {
	                var connections = shape.connections();
	                var idx;

	                if (connections) {
	                    for (idx = 0; idx < connections.length; idx++) {
	                        this._removeItem(connections[idx], false);
	                    }
	                }
	            },

	            _addDataItem: function(dataItem, undoable) {
	                if (!defined(dataItem)) {
	                    return;
	                }

	                var shape = this._dataMap[dataItem.id];
	                if (shape) {
	                    return shape;
	                }

	                var options = deepExtend({}, this.options.shapeDefaults);
	                options.dataItem = dataItem;
	                shape = new Shape(options, this);
	                this.addShape(shape, undoable !== false);
	                this._dataMap[dataItem.id] = shape;
	                return shape;
	            },

	            _addDataItemByUid: function(dataItem) {
	                if (!defined(dataItem)) {
	                    return;
	                }

	                var shape = this._dataMap[dataItem.uid];
	                if (shape) {
	                    return shape;
	                }

	                var options = deepExtend({}, this.options.shapeDefaults);
	                options.dataItem = dataItem;
	                shape = new Shape(options, this);
	                this.addShape(shape);
	                this._dataMap[dataItem.uid] = shape;
	                return shape;
	            },

	            _addDataItems: function(items, parent) {
	                var item, idx, shape, parentShape, connection;
	                for (idx = 0; idx < items.length; idx++) {
	                    item = items[idx];
	                    shape = this._addDataItemByUid(item);
	                    parentShape = this._addDataItemByUid(parent);
	                    if (parentShape && !this.connected(parentShape, shape)) { // check if connected to not duplicate connections.
	                        connection = this.connect(parentShape, shape);
	                    }
	                }
	            },

	            _refreshSource: function (e) {
	                var that = this,
	                    node = e.node,
	                    action = e.action,
	                    items = e.items,
	                    options = that.options,
	                    idx,
	                    dataBound;

	                if (e.field) {
	                    for (idx = 0; idx < items.length; idx++) {
	                        if (this._dataMap[items[idx].uid]) {
	                            this._dataMap[items[idx].uid].redrawVisual();
	                        }
	                    }
	                    return;
	                }

	                if (action == "remove") {
	                    this._removeDataItems(e.items, true);
	                } else {

	                    if ((!action || action === "itemloaded") && !this._bindingRoots) {
	                        this._bindingRoots = true;
	                        dataBound = true;
	                    }

	                    if (!action && !node) {
	                        that.clear();
	                    }

	                    this._addDataItems(items, node);

	                    for (idx = 0; idx < items.length; idx++) {
	                        items[idx].load();
	                    }
	                }

	                if (options.layout && (dataBound || action == "remove" || action == "add")) {
	                    that.layout(options.layout);
	                }

	                if (dataBound) {
	                    this.trigger("dataBound");
	                    this._bindingRoots = false;
	                }
	            },

	            _addItem: function (item) {
	                if (item instanceof Shape) {
	                    this.addShape(item);
	                } else if (item instanceof Connection) {
	                    this.addConnection(item);
	                }
	            },

	            _createToolBar: function(preventClosing) {
	                var diagram = this.toolService.diagram;

	                if (!this.singleToolBar && diagram.select().length === 1) {
	                    var element = diagram.select()[0];
	                    if (element && element.options.editable !== false) {
	                        var editable = element.options.editable;
	                        var tools = editable.tools;
	                        if (this._isEditable && tools.length === 0) {
	                            if (element instanceof Shape) {
	                                tools = ["edit", "rotateClockwise", "rotateAnticlockwise"];
	                            } else if (element instanceof Connection) {
	                                tools = ["edit"];
	                            }

	                            if (editable && editable.remove !== false) {
	                                tools.push("delete");
	                            }
	                        }

	                        if (tools && tools.length) {
	                            var padding = 20;
	                            var point;
	                            this.singleToolBar = new DiagramToolBar(diagram, {
	                                tools: tools,
	                                click: proxy(this._toolBarClick, this),
	                                modal: true,
	                                popupZIndex: parseInt(diagram.element.closest(".k-window").css("zIndex"), 10) + 10
	                            });
	                            var popupWidth = outerWidth(this.singleToolBar._popup.element);
	                            var popupHeight = outerHeight(this.singleToolBar._popup.element);
	                            if (element instanceof Shape) {
	                                var shapeBounds = this.modelToView(element.bounds(ROTATED));
	                                point = new Point(shapeBounds.x, shapeBounds.y).minus(new Point(
	                                    (popupWidth - shapeBounds.width) / 2,
	                                    popupHeight + padding));
	                            } else if (element instanceof Connection) {
	                                var connectionBounds = this.modelToView(element.bounds());

	                                point = new Point(connectionBounds.x, connectionBounds.y)
	                                    .minus(new Point(
	                                        (popupWidth - connectionBounds.width - 20) / 2,
	                                        popupHeight + padding
	                                    ));
	                            }

	                            if (point) {
	                                if (!this.canvas.translate) {
	                                    point = point.minus(new Point(this.scroller.scrollLeft, this.scroller.scrollTop));
	                                }
	                                point = this.viewToDocument(point);
	                                point = new Point(math.max(point.x, 0), math.max(point.y, 0));
	                                this.singleToolBar.showAt(point);
	                                if (preventClosing) {
	                                    this.singleToolBar._popup.one("close", preventDefault);
	                                }
	                            } else {
	                                this._destroyToolBar();
	                            }
	                        }
	                    }
	                }
	            },

	            _toolBarClick: function(e) {
	                this.trigger("toolBarClick", e);
	                this._destroyToolBar();
	            },

	            _normalizePointZoom: function (point) {
	                return point.times(1 / this.zoom());
	            },

	            _initialize: function () {
	                this.shapes = [];
	                this._selectedItems = [];
	                this.connections = [];
	                this._dataMap = {};
	                this._connectionsDataMap = {};
	                this._inactiveShapeItems = new InactiveItemsCollection();
	                this._deferredConnectionUpdates = [];
	                this.undoRedoService = new UndoRedoService({
	                    undone: this._syncHandler,
	                    redone: this._syncHandler
	                });
	                this.id = diagram.randomId();
	            },

	            _fetchFreshData: function () {
	                var that = this;
	                that._dataSource();

	                if (that._isEditable) {
	                    that._connectionDataSource();
	                }

	                if (that.options.autoBind) {
	                    if (that._isEditable) {
	                        this._loadingShapes = true;
	                        this._loadingConnections = true;
	                        that.dataSource.fetch();
	                        that.connectionsDataSource.fetch();
	                    } else {
	                        that.dataSource.fetch();
	                    }
	                }
	            },

	            _dataSource: function() {
	                if (defined(this.options.connectionsDataSource)) {
	                    this._isEditable = true;
	                    var dsOptions = this.options.dataSource || {};
	                    var ds = isArray(dsOptions) ? { data: dsOptions } : dsOptions;

	                    if (this.dataSource && this._shapesRefreshHandler) {
	                        this.dataSource
	                            .unbind("change", this._shapesRefreshHandler)
	                            .unbind("requestStart", this._shapesRequestStartHandler)
	                            .unbind("error", this._shapesErrorHandler);
	                    } else {
	                        this._shapesRefreshHandler = proxy(this._refreshShapes, this);
	                        this._shapesRequestStartHandler = proxy(this._shapesRequestStart, this);
	                        this._shapesErrorHandler = proxy(this._error, this);
	                    }

	                    this.dataSource = kendo.data.DataSource.create(ds)
	                        .bind("change", this._shapesRefreshHandler)
	                        .bind("requestStart", this._shapesRequestStartHandler)
	                        .bind("error", this._shapesErrorHandler);
	                } else {
	                    this._treeDataSource();
	                    this._isEditable = false;
	                }
	            },

	            _connectionDataSource: function() {
	                var dsOptions = this.options.connectionsDataSource;
	                if (dsOptions) {
	                    var ds = isArray(dsOptions) ? { data: dsOptions } : dsOptions;

	                    if (this.connectionsDataSource && this._connectionsRefreshHandler) {
	                        this.connectionsDataSource
	                            .unbind("change", this._connectionsRefreshHandler)
	                            .unbind("requestStart", this._connectionsRequestStartHandler)
	                            .unbind("error", this._connectionsErrorHandler);
	                    } else {
	                        this._connectionsRefreshHandler = proxy(this._refreshConnections, this);
	                        this._connectionsRequestStartHandler = proxy(this._connectionsRequestStart, this);
	                        this._connectionsErrorHandler = proxy(this._connectionsError, this);
	                    }

	                    this.connectionsDataSource = kendo.data.DataSource.create(ds)
	                        .bind("change", this._connectionsRefreshHandler)
	                        .bind("requestStart", this._connectionsRequestStartHandler)
	                        .bind("error", this._connectionsErrorHandler);
	                }
	            },

	            _shapesRequestStart: function(e) {
	                if (e.type == "read") {
	                    this._loadingShapes = true;
	                }
	            },

	            _connectionsRequestStart: function(e) {
	                if (e.type == "read") {
	                    this._loadingConnections = true;
	                }
	            },

	            _error: function () {
	                this._loadingShapes = false;
	            },

	            _connectionsError: function() {
	                this._loadingConnections = false;
	            },

	            _refreshShapes: function(e) {
	                if (e.action === "remove") {
	                    if (this._shouldRefresh()) {
	                        this._removeShapes(e.items);
	                    }
	                } else if (e.action === "itemchange") {
	                    if (this._shouldRefresh()) {
	                        this._updateShapes(e.items, e.field);
	                    }
	                } else if (e.action === "add") {
	                    this._inactiveShapeItems.add(e.items);
	                } else if (e.action === "sync") {
	                    this._syncShapes(e.items);
	                } else {
	                    this.refresh();
	                }
	            },

	            _shouldRefresh: function() {
	                return !this._suspended;
	            },

	            _suspendModelRefresh: function() {
	                this._suspended = (this._suspended || 0) + 1;
	            },

	            _resumeModelRefresh: function() {
	                this._suspended = math.max((this._suspended || 0) - 1, 0);
	            },

	            refresh: function() {
	                this._loadingShapes = false;
	                if (!this._loadingConnections) {
	                    this._rebindShapesAndConnections();
	                }
	            },

	            _rebindShapesAndConnections: function() {
	                this.clear();
	                this._addShapes(this.dataSource.view());
	                if (this.connectionsDataSource) {
	                    this._addConnections(this.connectionsDataSource.view(), false);
	                }

	                if (this.options.layout) {
	                    this.layout(this.options.layout);
	                } else {
	                    this._redrawConnections();
	                }
	                this.trigger("dataBound");
	            },

	            refreshConnections: function() {
	                this._loadingConnections = false;
	                if (!this._loadingShapes) {
	                    this._rebindShapesAndConnections();
	                }
	            },

	            _redrawConnections: function() {
	                var connections = this.connections;
	                for (var idx = 0; idx < connections.length; idx++) {
	                    connections[idx].refresh();
	                }
	            },

	            _removeShapes: function(items) {
	                var dataMap = this._dataMap;
	                var item, i;
	                for (i = 0; i < items.length; i++) {
	                    item = items[i];
	                    if (dataMap[item.id]) {
	                        this.remove(dataMap[item.id], false);
	                        dataMap[item.id] = null;
	                    }
	                }
	            },

	            _syncShapes: function() {
	                var diagram = this;
	                var inactiveItems = diagram._inactiveShapeItems;
	                inactiveItems.forEach(function(inactiveItem) {
	                    var dataItem = inactiveItem.dataItem;
	                    var shape = inactiveItem.element;
	                    if (!dataItem.isNew()) {
	                        if (shape) {
	                            shape._setOptionsFromModel();
	                            diagram.addShape(shape, inactiveItem.undoable);
	                            diagram._dataMap[dataItem.id] = shape;
	                        } else {
	                            diagram._addDataItem(dataItem);
	                        }
	                        inactiveItem.activate();
	                        inactiveItems.remove(dataItem);
	                    }
	                });
	            },

	            _updateShapes: function(items, field) {
	                for (var i = 0; i < items.length; i++) {
	                    var dataItem = items[i];

	                    var shape = this._dataMap[dataItem.id];
	                    if (shape) {
	                        shape.updateOptionsFromModel(dataItem, field);
	                    }
	                }
	            },

	            _addShapes: function(dataItems) {
	                for (var i = 0; i < dataItems.length; i++) {
	                    this._addDataItem(dataItems[i], false);
	                }
	            },

	            _refreshConnections: function(e) {
	                if (e.action === "remove") {
	                    if (this._shouldRefresh()) {
	                        this._removeConnections(e.items);
	                    }
	                } else if (e.action === "add") {
	                    this._addConnections(e.items);
	                } else if (e.action === "sync") {
	                    //TO DO: include logic to update the connections with different values returned from the server.
	                } else if (e.action === "itemchange") {
	                    if (this._shouldRefresh()) {
	                        this._updateConnections(e.items);
	                    }
	                } else {
	                    this.refreshConnections();
	                }
	            },

	            _removeConnections: function(items) {
	                for (var i = 0; i < items.length; i++) {
	                    this.remove(this._connectionsDataMap[items[i].uid], false);
	                    this._connectionsDataMap[items[i].uid] = null;
	                }
	            },

	            _updateConnections: function(items) {
	                for (var i = 0; i < items.length; i++) {
	                    var dataItem = items[i];

	                    var connection = this._connectionsDataMap[dataItem.uid];
	                    connection.updateOptionsFromModel(dataItem);
	                }
	            },

	            _addConnections: function(connections, undoable) {
	                var length = connections.length;

	                for (var i = 0; i < length; i++) {
	                    var dataItem = connections[i];
	                    this._addConnectionDataItem(dataItem, undoable);
	                }
	            },

	            _addConnectionDataItem: function(dataItem, undoable) {
	                if (!this._connectionsDataMap[dataItem.uid]) {
	                    var from = this._validateConnector(dataItem.from);
	                    if (!defined(from) || from === null) {
	                        from = new Point(dataItem.fromX, dataItem.fromY);
	                    }

	                    var to = this._validateConnector(dataItem.to);
	                    if (!defined(to) || to === null) {
	                        to = new Point(dataItem.toX, dataItem.toY);
	                    }

	                    if (defined(from) && defined(to)) {
	                        var options = deepExtend({}, this.options.connectionDefaults);
	                        options.dataItem = dataItem;
	                        var connection = new Connection(from, to, options);

	                        this._connectionsDataMap[dataItem.uid] = connection;
	                        this.addConnection(connection, undoable);
	                    }
	                }
	            },

	            _validateConnector: function(value) {
	                var connector;

	                if (defined(value) && value !== null) {
	                    connector = this._dataMap[value];
	                }

	                return connector;
	            },

	            _treeDataSource: function () {
	                var that = this,
	                    options = that.options,
	                    dataSource = options.dataSource;

	                dataSource = isArray(dataSource) ? { data: dataSource } : dataSource;

	                if (dataSource instanceof kendo.data.DataSource && !(dataSource instanceof kendo.data.HierarchicalDataSource)) {
	                    throw new Error("Incorrect DataSource type. If a single dataSource instance is set to the diagram then it should be a HierarchicalDataSource. You should set only the options instead of an instance or a HierarchicalDataSource instance or supply connectionsDataSource as well.");
	                }

	                if (!dataSource.fields) {
	                    dataSource.fields = [
	                        { field: "text" },
	                        { field: "url" },
	                        { field: "spriteCssClass" },
	                        { field: "imageUrl" }
	                    ];
	                }
	                if (that.dataSource && that._refreshHandler) {
	                    that._unbindDataSource();
	                }

	                that._refreshHandler = proxy(that._refreshSource, that);
	                that._errorHandler = proxy(that._error, that);

	                that.dataSource = HierarchicalDataSource.create(dataSource)
	                    .bind(CHANGE, that._refreshHandler)
	                    .bind(ERROR, that._errorHandler);
	            },

	            _unbindDataSource: function () {
	                var that = this;

	                that.dataSource.unbind(CHANGE, that._refreshHandler).unbind(ERROR, that._errorHandler);
	            },

	            _adorn: function (adorner, isActive) {
	                if (isActive !== undefined && adorner) {
	                    if (isActive) {
	                        this._adorners.push(adorner);
	                        this.adornerLayer.append(adorner.visual);
	                    }
	                    else {
	                        Utils.remove(this._adorners, adorner);
	                        this.adornerLayer.remove(adorner.visual);
	                    }
	                }
	            },

	            _showConnectors: function (shape, value) {
	                if (value) {
	                    this._connectorsAdorner.show(shape);
	                } else {
	                    this._connectorsAdorner.destroy();
	                }
	            },

	            _updateAdorners: function() {
	                var adorners = this._adorners;

	                for(var i = 0; i < adorners.length; i++) {
	                    var adorner = adorners[i];

	                    if (adorner.refreshBounds) {
	                        adorner.refreshBounds();
	                    }
	                    adorner.refresh();
	                }
	            },

	            _refresh: function () {
	                for (var i = 0; i < this.connections.length; i++) {
	                    this.connections[i].refresh();
	                }
	            },

	            _destroyToolBar: function() {
	                if (this.singleToolBar) {
	                    this.singleToolBar.hide();
	                    this.singleToolBar.destroy();
	                    this.singleToolBar = null;
	                }
	            },

	            _destroyGlobalToolBar: function() {
	                if (this.toolBar) {
	                    this.toolBar.hide();
	                    this.toolBar.destroy();
	                    this.toolBar = null;
	                }
	            },

	            exportDOMVisual: function() {
	                var viewBox = this.canvas._viewBox;
	                var scrollOffset = geom.transform()
	                                       .translate(-viewBox.x, -viewBox.y);

	                var viewRect = new geom.Rect([0, 0], [viewBox.width, viewBox.height]);
	                var clipPath = draw.Path.fromRect(viewRect);
	                var wrap = new draw.Group({ transform: scrollOffset });
	                var clipWrap = new draw.Group({ clip: clipPath });
	                var root = this.canvas.drawingElement.children[0];

	                clipWrap.append(wrap);

	                // Don't reparent the root
	                wrap.children.push(root);

	                return clipWrap;
	            },

	            exportVisual: function() {
	                var scale = geom.transform().scale(1 / this._zoom);
	                var wrap = new draw.Group({
	                    transform: scale
	                });

	                var root = this.mainLayer.drawingElement;
	                wrap.children.push(root);

	                return wrap;
	            },

	            _syncChanges: function() {
	                this._syncShapeChanges();
	                this._syncConnectionChanges();
	            },

	            _syncShapeChanges: function() {
	                if (this.dataSource && this._isEditable) {
	                    this.dataSource.sync();
	                }
	            },

	            _syncConnectionChanges: function() {
	                var that = this;
	                if (that.connectionsDataSource && that._isEditable) {
	                    $.when.apply($, that._deferredConnectionUpdates).then(function() {
	                        that.connectionsDataSource.sync();
	                    });
	                    that.deferredConnectionUpdates = [];
	                }
	            }
	        });

	        dataviz.ExportMixin.extend(Diagram.fn, true);

	        if (kendo.PDFMixin) {
	            kendo.PDFMixin.extend(Diagram.fn);
	        }

	        function filterShapeDataItem(dataItem) {
	            var result = {};

	            dataItem = dataItem || {};

	            if (defined(dataItem.text) && dataItem.text !== null) {
	                result.text = dataItem.text;
	            }

	            if (defined(dataItem.x) && dataItem.x !== null) {
	                result.x = dataItem.x;
	            }

	            if (defined(dataItem.y) && dataItem.y !== null) {
	                result.y = dataItem.y;
	            }

	            if (defined(dataItem.width) && dataItem.width !== null) {
	                result.width = dataItem.width;
	            }

	            if (defined(dataItem.height) && dataItem.height !== null) {
	                result.height = dataItem.height;
	            }

	            if (defined(dataItem.type) && dataItem.type !== null) {
	                result.type = dataItem.type;
	            }

	            return result;
	        }

	        function filterConnectionDataItem(dataItem) {
	            var result = {};

	            dataItem = dataItem || {};

	            if (defined(dataItem.text) && dataItem.text !== null) {
	                result.content = dataItem.text;
	            }

	            if (defined(dataItem.type) && dataItem.type !== null) {
	                result.type = dataItem.type;
	            }

	            if (defined(dataItem.from) && dataItem.from !== null) {
	                result.from = dataItem.from;
	            }

	            if (defined(dataItem.fromConnector) && dataItem.fromConnector !== null) {
	                result.fromConnector = dataItem.fromConnector;
	            }

	            if (defined(dataItem.fromX) && dataItem.fromX !== null) {
	                result.fromX = dataItem.fromX;
	            }

	            if (defined(dataItem.fromY) && dataItem.fromY !== null) {
	                result.fromY = dataItem.fromY;
	            }

	            if (defined(dataItem.to) && dataItem.to !== null) {
	                result.to = dataItem.to;
	            }

	            if (defined(dataItem.toConnector) && dataItem.toConnector !== null) {
	                result.toConnector = dataItem.toConnector;
	            }

	            if (defined(dataItem.toX) && dataItem.toX !== null) {
	                result.toX = dataItem.toX;
	            }

	            if (defined(dataItem.toY) && dataItem.toY !== null) {
	                result.toY = dataItem.toY;
	            }

	            return result;
	        }


	        var DiagramToolBar = kendo.Observable.extend({
	            init: function(diagram, options) {
	                kendo.Observable.fn.init.call(this);
	                this.diagram = diagram;
	                this.options = deepExtend({}, this.options, options);
	                this._tools = [];
	                this.createToolBar();
	                this.createTools();
	                this.appendTools();

	                if (this.options.modal) {
	                    this.createPopup();
	                }

	                this.bind(this.events, options);
	            },

	            events: ["click"],

	            createPopup: function() {
	                this.container = $("<div/>").append(this.element);
	                this._popup = this.container.kendoPopup({}).getKendoPopup();
	            },

	            appendTools: function() {
	                for (var i = 0; i < this._tools.length; i++) {
	                    var tool = this._tools[i];
	                    if (tool.buttons && tool.buttons.length || !defined(tool.buttons)) {
	                        this._toolBar.add(tool);
	                    }
	                }
	            },

	            createToolBar: function() {
	                this.element = $("<div/>");
	                this._toolBar = this.element
	                    .kendoToolBar({
	                        click: proxy(this.click, this),
	                        resizable: false
	                    }).getKendoToolBar();

	                this.element.css("border", "none");
	            },

	            createTools: function() {
	                for (var i = 0; i < this.options.tools.length; i++) {
	                    this.createTool(this.options.tools[i]);
	                }
	            },

	            createTool: function(tool) {
	                if (!isPlainObject(tool)) {
	                    tool = {
	                        name: tool
	                    };
	                }
	                var toolName = tool.name + "Tool";
	                if (this[toolName]) {
	                    this[toolName](tool);
	                } else {
	                    this._tools.push(deepExtend({}, tool, {
	                        attributes: this._setAttributes({action: tool.name})
	                    }));
	                }
	            },

	            showAt: function(point) {
	                var popupZIndex = parseInt(this.options.popupZIndex, 10);

	                if (this._popup) {
	                    this._popup.open(point.x, point.y);

	                    if (popupZIndex) {
	                        this._popup.wrapper.css("zIndex", popupZIndex);
	                    }
	                }
	            },

	            hide: function() {
	                if (this._popup) {
	                    this._popup.close();
	                }
	            },

	            newGroup: function() {
	                return {
	                    type: "buttonGroup",
	                    buttons: []
	                };
	            },

	            editTool: function() {
	                this._tools.push({
	                    icon: "edit",
	                    showText: "overflow",
	                    type: "button",
	                    text: "Edit",
	                    attributes: this._setAttributes({ action: "edit" })
	                });
	            },

	            deleteTool: function() {
	                this._tools.push({
	                    icon: "close",
	                    showText: "overflow",
	                    type: "button",
	                    text: "Delete",
	                    attributes: this._setAttributes({ action: "delete" })
	                });
	            },

	            rotateAnticlockwiseTool: function(options) {
	                this._appendGroup("rotate");
	                this._rotateGroup.buttons.push({
	                    icon: "rotate-left",
	                    showText: "overflow",
	                    text: "RotateAnticlockwise",
	                    group: "rotate",
	                    attributes: this._setAttributes({ action: "rotateAnticlockwise", step: options.step })
	                });
	            },

	            rotateClockwiseTool: function(options) {
	                this._appendGroup("rotate");
	                this._rotateGroup.buttons.push({
	                    icon: "rotate-right",
	                    attributes: this._setAttributes({ action: "rotateClockwise", step: options.step }),
	                    showText: "overflow",
	                    text: "RotateClockwise",
	                    group: "rotate"
	                });
	            },

	            createShapeTool: function() {
	                this._appendGroup("create");
	                this._createGroup.buttons.push({
	                    icon: "shape",
	                    showText: "overflow",
	                    text: "CreateShape",
	                    group: "create",
	                    attributes: this._setAttributes({ action: "createShape" })
	                });
	            },

	            createConnectionTool: function() {
	                this._appendGroup("create");
	                this._createGroup.buttons.push({
	                    icon: "connector",
	                    showText: "overflow",
	                    text: "CreateConnection",
	                    group: "create",
	                    attributes: this._setAttributes({ action: "createConnection" })
	                });
	            },

	            undoTool: function() {
	                this._appendGroup("history");
	                this._historyGroup.buttons.push({
	                    icon: "undo",
	                    showText: "overflow",
	                    text: "Undo",
	                    group: "history",
	                    attributes: this._setAttributes({ action: "undo" })
	                });
	            },

	            redoTool: function() {
	                this._appendGroup("history");
	                this._historyGroup.buttons.push({
	                    icon: "redo",
	                    showText: "overflow",
	                    text: "Redo",
	                    group: "history",
	                    attributes: this._setAttributes({ action: "redo" })
	                });
	            },

	            _appendGroup: function(name) {
	                var prop = "_" + name + "Group";
	                if (!this[prop]) {
	                    this[prop] = this.newGroup();
	                    this._tools.push(this[prop]);
	                }
	            },

	            _setAttributes: function(attributes) {
	                var attr = {};

	                if (attributes.action) {
	                    attr[kendo.attr("action")] = attributes.action;
	                }

	                if (attributes.step) {
	                    attr[kendo.attr("step")] = attributes.step;
	                }

	                return attr;
	            },

	            _getAttributes: function(element) {
	                var attr = {};

	                var action = element.attr(kendo.attr("action"));
	                if (action) {
	                    attr.action = action;
	                }

	                var step = element.attr(kendo.attr("step"));
	                if (step) {
	                    attr.step = step;
	                }

	                return attr;
	            },

	            click: function(e) {
	                var attributes = this._getAttributes($(e.target));
	                var action = attributes.action;

	                if (action && this[action]) {
	                    this[action](attributes);
	                }

	                this.trigger("click", this.eventData(action, e.target));
	            },

	            eventData: function(action, target) {
	                var elements = this.selectedElements(),
	                    length = elements.length,
	                    shapes = [], connections = [], element;

	                for (var idx = 0; idx < length; idx++) {
	                    element = elements[idx];
	                    if (element instanceof Shape) {
	                        shapes.push(element);
	                    } else {
	                        connections.push(element);
	                    }
	                }

	                return {
	                    shapes: shapes,
	                    connections: connections,
	                    action: action,
	                    target: target
	                };
	            },

	            "delete": function() {
	                var diagram = this.diagram;
	                var toRemove = diagram._triggerRemove(this.selectedElements());
	                if (toRemove.length) {
	                    this.diagram.remove(toRemove, true);
	                    this.diagram._syncChanges();
	                }
	            },

	            edit: function() {
	                var selectedElemens = this.selectedElements();
	                if (selectedElemens.length === 1) {
	                    this.diagram.edit(selectedElemens[0]);
	                }
	            },

	            rotateClockwise: function(options) {
	                var angle = parseFloat(options.step || 90);
	                this._rotate(angle);
	            },

	            rotateAnticlockwise: function(options) {
	                var angle = parseFloat(options.step || 90);
	                this._rotate(-angle);
	            },

	            _rotate: function(angle) {
	                var adorner = this.diagram._resizingAdorner;
	                adorner.angle(adorner.angle() + angle);
	                adorner.rotate();
	            },

	            selectedElements: function() {
	                return this.diagram.select();
	            },

	            createShape: function() {
	                this.diagram.createShape();
	            },

	            createConnection: function() {
	                this.diagram.createConnection();
	            },

	            undo: function() {
	                this.diagram.undo();
	            },

	            redo: function() {
	                this.diagram.redo();
	            },

	            destroy: function() {
	                this.diagram = null;
	                this.element = null;
	                this.options = null;

	                if (this._toolBar) {
	                    this._toolBar.destroy();
	                }

	                if (this._popup) {
	                    this._popup.destroy();
	                }
	            }
	        });

	        var Editor = kendo.Observable.extend({
	            init: function(element, options) {
	                kendo.Observable.fn.init.call(this);

	                this.options = extend(true, {}, this.options, options);
	                this.element = element;
	                this.model = this.options.model;
	                this.fields = this._getFields();
	                this._initContainer();
	                this.createEditable();
	            },

	            options: {
	                editors: {}
	            },

	            _initContainer: function() {
	                this.wrapper = this.element;
	            },

	            createEditable: function() {
	                var options = this.options;

	                this.editable = new kendo.ui.Editable(this.wrapper, {
	                    fields: this.fields,
	                    target: options.target,
	                    clearContainer: false,
	                    model: this.model
	                });
	            },

	            _isEditable: function(field) {
	                return this.model.editable && this.model.editable(field);
	            },

	            _getFields: function() {
	                var fields = [];
	                var modelFields = this.model.fields;

	                for (var field in modelFields) {
	                    var result = {};
	                    if (this._isEditable(field)) {
	                        var editor = this.options.editors[field];
	                        if (editor) {
	                            result.editor = editor;
	                        }
	                        result.field = field;
	                        fields.push(result);
	                    }
	                }

	                return fields;
	            },

	            end: function() {
	                return this.editable.end();
	            },

	            destroy: function() {
	                this.editable.destroy();
	                this.editable.element.find("[" + kendo.attr("container-for") + "]").empty();
	                this.model = this.wrapper = this.element = this.columns = this.editable = null;
	            }
	        });

	        var PopupEditor = Editor.extend({
	            init: function(element, options) {
	                Editor.fn.init.call(this, element, options);
	                this.bind(this.events, this.options);

	                this.open();
	            },

	            events: [ "update", "cancel" ],

	            options: {
	                window: {
	                    modal: true,
	                    resizable: false,
	                    draggable: true,
	                    title: "Edit",
	                    visible: false
	                }
	            },

	            _initContainer: function() {
	                var that = this;
	                this.wrapper = $('<div class="k-popup-edit-form"/>')
	                    .attr(kendo.attr("uid"), this.model.uid);

	                var formContent = "";

	                if (this.options.template) {
	                    formContent += this._renderTemplate();
	                    this.fields = [];
	                } else {
	                    formContent += this._renderFields();
	                }

	                formContent += this._renderButtons();

	                this.wrapper.append(
	                    $('<div class="k-edit-form-container"/>').append(formContent));

	                this.window = new kendo.ui.Window(this.wrapper.appendTo(this.element), this.options.window);
	                this.window.bind("close", function(e) {
	                    //The bellow line is required due to: draggable window in IE, change event will be triggered while the window is closing
	                    if (e.userTriggered) {
	                        e.sender.element.focus();
	                        that._cancelClick(e);
	                    }
	                });

	                this._attachButtonEvents();
	            },

	            _renderTemplate: function() {
	                var template = this.options.template;

	                if (typeof template === "string") {
	                    template = window.unescape(template);
	                }

	                template = kendo.template(template)(this.model);

	                return template;
	            },

	            _renderFields: function() {
	                var form = "";
	                for (var i = 0; i < this.fields.length; i++) {
	                    var field = this.fields[i];

	                    form += '<div class="k-edit-label"><label for="' + field.field + '">' + (field.field || "") + '</label></div>';

	                    if (this._isEditable(field.field)) {
	                        form += '<div ' + kendo.attr("container-for") + '="' + field.field +
	                        '" class="k-edit-field"></div>';
	                    }
	                }

	                return form;
	            },

	            _renderButtons: function() {
	                var form = '<div class="k-edit-buttons k-state-default">';
	                form += this._createButton("update");
	                form += this._createButton("cancel");
	                form += '</div>';
	                return form;
	            },

	            _createButton: function(name) {
	                return kendo.template(BUTTON_TEMPLATE)(defaultButtons[name]);
	            },

	            _attachButtonEvents: function() {
	                this._cancelClickHandler = proxy(this._cancelClick, this);
	                this.window.element.on(CLICK + NS, "a.k-diagram-cancel", this._cancelClickHandler);

	                this._updateClickHandler = proxy(this._updateClick, this);
	                this.window.element.on(CLICK + NS, "a.k-diagram-update", this._updateClickHandler);
	            },

	            _updateClick: function(e) {
	                e.preventDefault();
	                this.trigger("update");
	            },

	            _cancelClick: function (e) {
	                e.preventDefault();
	                this.trigger("cancel");
	            },

	            open: function() {
	                this.window.center().open();
	            },

	            close: function() {
	                this.window.bind("deactivate", proxy(this.destroy, this)).close();
	            },

	            destroy: function() {
	                this.window.close().destroy();
	                this.window.element.off(CLICK + NS, "a.k-diagram-cancel", this._cancelClickHandler);
	                this.window.element.off(CLICK + NS, "a.k-diagram-update", this._updateClickHandler);
	                this._cancelClickHandler = null;
	                this._editUpdateClickHandler = null;
	                this.window = null;
	                Editor.fn.destroy.call(this);
	            }
	        });

	        function connectionSelector(container, options) {
	            var model = this.dataSource.reader.model;
	            if (model) {
	                var textField = model.fn.fields.text ? "text": model.idField;
	                $("<input name='" + options.field + "' />")
	                    .appendTo(container).kendoDropDownList({
	                        dataValueField: model.idField,
	                        dataTextField: textField,
	                        dataSource: this.dataSource.data().toJSON(),
	                        optionLabel: " ",
	                        valuePrimitive: true
	                    });
	            }
	        }

	        function InactiveItem(dataItem) {
	            this.dataItem = dataItem;
	            this.callbacks = [];
	        }

	        InactiveItem.fn = InactiveItem.prototype = {
	            onActivate: function(callback) {
	                var deffered = $.Deferred();
	                this.callbacks.push({
	                    callback: callback,
	                    deferred: deffered
	                });
	                return deffered;
	            },

	            activate: function() {
	                var callbacks = this.callbacks;
	                var item;
	                for (var idx = 0; idx < callbacks.length; idx++) {
	                    item = this.callbacks[idx];
	                    item.callback(this.dataItem);
	                    item.deferred.resolve();
	                }
	                this.callbacks = [];
	            }
	        };

	        function InactiveItemsCollection() {
	            this.items = {};
	        }

	        InactiveItemsCollection.fn = InactiveItemsCollection.prototype = {
	            add: function(items) {
	                for(var idx = 0; idx < items.length; idx++) {
	                    this.items[items[idx].uid] = new InactiveItem(items[idx]);
	                }
	            },

	            forEach: function(callback){
	                for (var uid in this.items) {
	                    callback(this.items[uid]);
	                }
	            },

	            getByUid: function(uid) {
	                return this.items[uid];
	            },

	            remove: function(item) {
	                delete this.items[item.uid];
	            }
	        };

	        var QuadRoot = Class.extend({
	            init: function() {
	                this.shapes = [];
	            },

	            _add: function(shape, bounds) {
	                this.shapes.push({
	                    bounds: bounds,
	                    shape: shape
	                });
	                shape._quadNode = this;
	            },

	            insert: function(shape, bounds) {
	                this._add(shape, bounds);
	            },

	            remove: function(shape) {
	                var shapes = this.shapes;
	                var length = shapes.length;

	                for (var idx = 0; idx < length; idx++) {
	                    if (shapes[idx].shape === shape) {
	                        shapes.splice(idx, 1);
	                        break;
	                    }
	                }
	            },

	            hitTestRect: function(rect, exclude) {
	                var shapes = this.shapes;
	                var length = shapes.length;

	                for (var i = 0; i < length; i++) {
	                    if (this._testRect(shapes[i].shape, rect) && !dataviz.inArray(shapes[i].shape, exclude)) {
	                        return true;
	                    }
	                }
	            },

	            _testRect: function(shape, rect) {
	                var angle = shape.rotate().angle;
	                var bounds = shape.bounds();
	                var hit;
	                if (!angle) {
	                    hit = bounds.overlaps(rect);
	                } else {
	                    hit = Intersect.rects(rect, bounds, -angle);
	                }
	                return hit;
	            }
	        });

	        var QuadNode = QuadRoot.extend({
	            init: function(rect) {
	                QuadRoot.fn.init.call(this);
	                this.children = [];
	                this.rect = rect;
	            },

	            inBounds: function(rect) {
	                var nodeRect = this.rect;
	                var nodeBottomRight = nodeRect.bottomRight();
	                var bottomRight = rect.bottomRight();
	                var inBounds = nodeRect.x <= rect.x && nodeRect.y <= rect.y && bottomRight.x <= nodeBottomRight.x &&
	                    bottomRight.y <= nodeBottomRight.y;
	                return inBounds;
	            },

	            overlapsBounds: function(rect) {
	                return this.rect.overlaps(rect);
	            },

	            insert: function (shape, bounds) {
	                var inserted = false;
	                var children = this.children;
	                var length = children.length;
	                if (this.inBounds(bounds)) {
	                    if (!length && this.shapes.length < 4) {
	                        this._add(shape, bounds);
	                    } else {
	                        if (!length) {
	                            this._initChildren();
	                        }

	                        for (var idx = 0; idx < children.length; idx++) {
	                            if (children[idx].insert(shape, bounds)) {
	                                inserted = true;
	                                break;
	                            }
	                        }

	                        if (!inserted) {
	                            this._add(shape, bounds);
	                        }
	                    }
	                    inserted = true;
	                }

	                return inserted;
	            },

	            _initChildren: function() {
	                var rect = this.rect,
	                    children = this.children,
	                    shapes = this.shapes,
	                    center = rect.center(),
	                    halfWidth = rect.width / 2,
	                    halfHeight = rect.height / 2,
	                    childIdx, shapeIdx;

	                children.push(
	                    new QuadNode(new Rect(rect.x, rect.y, halfWidth, halfHeight)),
	                    new QuadNode(new Rect(center.x, rect.y, halfWidth, halfHeight)),
	                    new QuadNode(new Rect(rect.x, center.y, halfWidth, halfHeight)),
	                    new QuadNode(new Rect(center.x, center.y, halfWidth, halfHeight))
	                );
	                for (shapeIdx = shapes.length - 1; shapeIdx >= 0; shapeIdx--) {
	                    for (childIdx = 0; childIdx < children.length; childIdx++) {
	                        if (children[childIdx].insert(shapes[shapeIdx].shape, shapes[shapeIdx].bounds)) {
	                            shapes.splice(shapeIdx, 1);
	                            break;
	                        }
	                    }
	                }
	            },

	            hitTestRect: function(rect, exclude) {
	                var idx;
	                var children = this.children;
	                var length = children.length;
	                var hit = false;

	                if (this.overlapsBounds(rect)) {
	                    if (QuadRoot.fn.hitTestRect.call(this, rect, exclude)) {
	                        hit = true;
	                    } else {
	                         for (idx = 0; idx < length; idx++) {
	                            if (children[idx].hitTestRect(rect, exclude)) {
	                               hit = true;
	                               break;
	                            }
	                        }
	                    }
	                }

	                return hit;
	            }
	        });

	        var ShapesQuadTree = Class.extend({
	            ROOT_SIZE: 1000,

	            init: function(diagram) {
	                var boundsChangeHandler = proxy(this._boundsChange, this);
	                diagram.bind(ITEMBOUNDSCHANGE, boundsChangeHandler);
	                diagram.bind(ITEMROTATE, boundsChangeHandler);
	                this.initRoots();
	            },

	            initRoots: function() {
	                this.rootMap = {};
	                this.root = new QuadRoot();
	            },

	            clear: function() {
	                this.initRoots();
	            },

	            _boundsChange: function(e) {
	                if (e.item._quadNode) {
	                    e.item._quadNode.remove(e.item);
	                }
	                this.insert(e.item);
	            },

	            insert: function(shape) {
	                var bounds = shape.bounds(ROTATED);
	                var rootSize = this.ROOT_SIZE;
	                var sectors = this.getSectors(bounds);
	                var x = sectors[0][0];
	                var y = sectors[1][0];

	                if (this.inRoot(sectors)) {
	                    this.root.insert(shape, bounds);
	                } else {
	                    if (!this.rootMap[x]) {
	                        this.rootMap[x] = {};
	                    }

	                    if (!this.rootMap[x][y]) {
	                        this.rootMap[x][y] = new QuadNode(
	                            new Rect(x * rootSize, y * rootSize, rootSize, rootSize)
	                        );
	                    }

	                    this.rootMap[x][y].insert(shape, bounds);
	                }
	            },

	            remove: function(shape) {
	                if (shape._quadNode) {
	                    shape._quadNode.remove(shape);
	                }
	            },

	            inRoot: function(sectors) {
	                return sectors[0].length > 1 || sectors[1].length > 1;
	            },

	            getSectors: function(rect) {
	                var rootSize = this.ROOT_SIZE;
	                var bottomRight = rect.bottomRight();
	                var bottomX = math.floor(bottomRight.x / rootSize);
	                var bottomY = math.floor(bottomRight.y / rootSize);
	                var sectors = [[],[]];
	                for (var x = math.floor(rect.x / rootSize); x <= bottomX; x++) {
	                    sectors[0].push(x);
	                }
	                for (var y = math.floor(rect.y / rootSize); y <= bottomY; y++) {
	                    sectors[1].push(y);
	                }
	                return sectors;
	            },

	            hitTestRect: function(rect, exclude) {
	                var sectors = this.getSectors(rect);
	                var xIdx, yIdx, x, y;
	                var root;

	                if (this.root.hitTestRect(rect, exclude)) {
	                    return true;
	                }

	                for (xIdx = 0; xIdx < sectors[0].length; xIdx++) {
	                    x = sectors[0][xIdx];
	                    for (yIdx = 0; yIdx < sectors[1].length; yIdx++) {
	                        y = sectors[1][yIdx];
	                        root = (this.rootMap[x] || {})[y];
	                        if (root && root.hitTestRect(rect, exclude)) {
	                            return true;
	                        }
	                    }
	                }

	                return false;
	            }
	        });

	        function cloneDataItem(dataItem) {
	            var result = dataItem;
	            if (dataItem instanceof kendo.data.Model) {
	                result = dataItem.toJSON();
	                result[dataItem.idField] = dataItem._defaultId;
	            }
	            return result;
	        }

	        function splitDiagramElements(elements) {
	            var connections = [];
	            var shapes = [];
	            var element, idx;
	            for (idx = 0; idx < elements.length; idx++) {
	                element = elements[idx];
	                if (element instanceof Shape) {
	                    shapes.push(element);
	                } else {
	                    connections.push(element);
	                }
	            }
	            return {
	                shapes: shapes,
	                connections: connections
	            };
	        }

	        function createModel(dataSource, model) {
	            if (dataSource.reader.model) {
	                return new dataSource.reader.model(model);
	            }

	            return new kendo.data.ObservableObject(model);
	        }

	        function clearField(field, model) {
	            if (defined(model[field])) {
	                model.set(field, null);
	            }
	        }

	        function copyDefaultOptions(mainOptions, elementOptions, fields) {
	            var field;
	            for (var idx = 0; idx < fields.length; idx++) {
	                field = fields[idx];
	                if (elementOptions && !defined(elementOptions[field])) {
	                    elementOptions[field] = mainOptions[field];
	                }
	            }
	        }

	        function translateToOrigin(visual) {
	            var bbox = visual.drawingContainer().clippedBBox(null);
	            if (bbox.origin.x !== 0 || bbox.origin.y !== 0) {
	                visual.position(-bbox.origin.x, -bbox.origin.y);
	            }
	        }

	        function preventDefault(e) {
	            e.preventDefault();
	        }

	        dataviz.ui.plugin(Diagram);

	        deepExtend(diagram, {
	            Shape: Shape,
	            Connection: Connection,
	            Connector: Connector,
	            DiagramToolBar: DiagramToolBar,
	            QuadNode: QuadNode,
	            QuadRoot: QuadRoot,
	            ShapesQuadTree: ShapesQuadTree,
	            PopupEditor: PopupEditor
	        });
	})(window.kendo.jQuery);

	}, __webpack_require__(3));


/***/ }),

/***/ 868:
/***/ (function(module, exports) {

	module.exports = require("../../kendo.dropdownlist");

/***/ }),

/***/ 869:
/***/ (function(module, exports) {

	module.exports = require("../../kendo.draganddrop");

/***/ }),

/***/ 870:
/***/ (function(module, exports) {

	module.exports = require("../../kendo.toolbar");

/***/ }),

/***/ 871:
/***/ (function(module, exports) {

	module.exports = require("../../kendo.editable");

/***/ }),

/***/ 872:
/***/ (function(module, exports) {

	module.exports = require("../../kendo.window");

/***/ }),

/***/ 873:
/***/ (function(module, exports) {

	module.exports = require("./svg");

/***/ }),

/***/ 874:
/***/ (function(module, exports) {

	module.exports = require("./services");

/***/ }),

/***/ 875:
/***/ (function(module, exports) {

	module.exports = require("./layout");

/***/ })

/******/ });