UNPKG

@progress/kendo-ui

Version:

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

1,314 lines (1,166 loc) 99.1 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__(880); /***/ }), /***/ 3: /***/ (function(module, exports) { module.exports = function() { throw new Error("define cannot be used indirect"); }; /***/ }), /***/ 859: /***/ (function(module, exports) { module.exports = require("../../kendo.drawing"); /***/ }), /***/ 873: /***/ (function(module, exports) { module.exports = require("./svg"); /***/ }), /***/ 880: /***/ (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__(859), __webpack_require__(873) ], __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 kendo = window.kendo, dataviz = kendo.dataviz, diagram = dataviz.diagram, Class = kendo.Class, Group = diagram.Group, Rect = diagram.Rect, Rectangle = diagram.Rectangle, Utils = diagram.Utils, isUndefined = Utils.isUndefined, Point = diagram.Point, Circle = diagram.Circle, Ticker = diagram.Ticker, deepExtend = kendo.deepExtend, Movable = kendo.ui.Movable, browser = kendo.support.browser, util = kendo.drawing.util, defined = util.defined, inArray = $.inArray, proxy = $.proxy; // Constants ============================================================== var Cursors = { arrow: "default", grip: "pointer", cross: "pointer", add: "pointer", move: "move", select: "pointer", south: "s-resize", east: "e-resize", west: "w-resize", north: "n-resize", rowresize: "row-resize", colresize: "col-resize" }, HIT_TEST_DISTANCE = 10, AUTO = "Auto", TOP = "Top", RIGHT = "Right", LEFT = "Left", BOTTOM = "Bottom", DEFAULT_SNAP_SIZE = 10, DEFAULT_SNAP_ANGLE = 10, DRAG_START = "dragStart", DRAG = "drag", DRAG_END = "dragEnd", ITEMROTATE = "itemRotate", ITEMBOUNDSCHANGE = "itemBoundsChange", MIN_SNAP_SIZE = 5, MIN_SNAP_ANGLE = 5, MOUSE_ENTER = "mouseEnter", MOUSE_LEAVE = "mouseLeave", ZOOM_START = "zoomStart", ZOOM_END = "zoomEnd", SCROLL_MIN = -20000, SCROLL_MAX = 20000, FRICTION = 0.90, FRICTION_MOBILE = 0.93, VELOCITY_MULTIPLIER = 5, TRANSPARENT = "transparent", PAN = "pan", ROTATED = "rotated", SOURCE = "source", TARGET = "target", HANDLE_NAMES = { "-1": SOURCE, "1": TARGET }; diagram.Cursors = Cursors; var PositionAdapter = kendo.Class.extend({ init: function (layoutState) { this.layoutState = layoutState; this.diagram = layoutState.diagram; }, initState: function () { this.froms = []; this.tos = []; this.subjects = []; function pusher(id, bounds) { var shape = this.diagram.getShapeById(id); if (shape) { this.subjects.push(shape); this.froms.push(shape.bounds().topLeft()); this.tos.push(bounds.topLeft()); } } this.layoutState.nodeMap.forEach(pusher, this); }, update: function (tick) { if (this.subjects.length <= 0) { return; } for (var i = 0; i < this.subjects.length; i++) { //todo: define a Lerp function instead this.subjects[i].position( new Point(this.froms[i].x + (this.tos[i].x - this.froms[i].x) * tick, this.froms[i].y + (this.tos[i].y - this.froms[i].y) * tick) ); } } }); var LayoutUndoUnit = Class.extend({ init: function (initialState, finalState, animate) { if (isUndefined(animate)) { this.animate = false; } else { this.animate = animate; } this._initialState = initialState; this._finalState = finalState; this.title = "Diagram layout"; }, undo: function () { this.setState(this._initialState); }, redo: function () { this.setState(this._finalState); }, setState: function (state) { var diagram = state.diagram; if (this.animate) { state.linkMap.forEach( function (id, points) { var conn = diagram.getShapeById(id); conn.visible(false); if (conn) { conn.points(points); } } ); var ticker = new Ticker(); ticker.addAdapter(new PositionAdapter(state)); ticker.onComplete(function () { state.linkMap.forEach( function (id) { var conn = diagram.getShapeById(id); conn.visible(true); } ); }); ticker.play(); } else { state.nodeMap.forEach(function (id, bounds) { var shape = diagram.getShapeById(id); if (shape) { shape.position(bounds.topLeft()); } }); state.linkMap.forEach( function (id, points) { var conn = diagram.getShapeById(id); if (conn) { conn.points(points); } } ); } } }); var CompositeUnit = Class.extend({ init: function (unit) { this.units = []; this.title = "Composite unit"; if (unit !== undefined) { this.units.push(unit); } }, add: function (undoUnit) { this.units.push(undoUnit); }, undo: function () { for (var i = 0; i < this.units.length; i++) { this.units[i].undo(); } }, redo: function () { for (var i = 0; i < this.units.length; i++) { this.units[i].redo(); } } }); var ConnectionEditUnit = Class.extend({ init: function (item, redoSource, redoTarget) { this.item = item; this._redoSource = redoSource; this._redoTarget = redoTarget; if (defined(redoSource)) { this._undoSource = item.source(); } if (defined(redoTarget)) { this._undoTarget = item.target(); } this.title = "Connection Editing"; }, undo: function () { if (this._undoSource !== undefined) { this.item._updateConnector(this._undoSource, "source"); } if (this._undoTarget !== undefined) { this.item._updateConnector(this._undoTarget, "target"); } this.item.updateModel(); }, redo: function () { if (this._redoSource !== undefined) { this.item._updateConnector(this._redoSource, "source"); } if (this._redoTarget !== undefined) { this.item._updateConnector(this._redoTarget, "target"); } this.item.updateModel(); } }); var ConnectionEditUndoUnit = Class.extend({ init: function (item, undoSource, undoTarget) { this.item = item; this._undoSource = undoSource; this._undoTarget = undoTarget; this._redoSource = item.source(); this._redoTarget = item.target(); this.title = "Connection Editing"; }, undo: function () { this.item._updateConnector(this._undoSource, "source"); this.item._updateConnector(this._undoTarget, "target"); this.item.updateModel(); }, redo: function () { this.item._updateConnector(this._redoSource, "source"); this.item._updateConnector(this._redoTarget, "target"); this.item.updateModel(); } }); var DeleteConnectionUnit = Class.extend({ init: function (connection) { this.connection = connection; this.diagram = connection.diagram; this.targetConnector = connection.targetConnector; this.title = "Delete connection"; }, undo: function () { this.diagram._addConnection(this.connection, false); }, redo: function () { this.diagram.remove(this.connection, false); } }); var DeleteShapeUnit = Class.extend({ init: function (shape) { this.shape = shape; this.diagram = shape.diagram; this.title = "Deletion"; }, undo: function () { this.diagram._addShape(this.shape, false); this.shape.select(false); }, redo: function () { this.shape.select(false); this.diagram.remove(this.shape, false); } }); /** * Holds the undoredo state when performing a rotation, translation or scaling. The adorner is optional. * @type {*} */ var TransformUnit = Class.extend({ init: function (shapes, undoStates, adorner) { this.shapes = shapes; this.undoStates = undoStates; this.title = "Transformation"; this.redoStates = []; this.adorner = adorner; for (var i = 0; i < this.shapes.length; i++) { var shape = this.shapes[i]; this.redoStates.push(shape.bounds()); } }, undo: function () { for (var i = 0; i < this.shapes.length; i++) { var shape = this.shapes[i]; shape.bounds(this.undoStates[i]); if (shape.hasOwnProperty("layout")) { shape.layout(shape, this.redoStates[i], this.undoStates[i]); } shape.updateModel(); } if (this.adorner) { this.adorner.refreshBounds(); this.adorner.refresh(); } }, redo: function () { for (var i = 0; i < this.shapes.length; i++) { var shape = this.shapes[i]; shape.bounds(this.redoStates[i]); // the 'layout' property, if implemented, lets the shape itself work out what to do with the new bounds if (shape.hasOwnProperty("layout")) { shape.layout(shape, this.undoStates[i], this.redoStates[i]); } shape.updateModel(); } if (this.adorner) { this.adorner.refreshBounds(); this.adorner.refresh(); } } }); var AddConnectionUnit = Class.extend({ init: function (connection, diagram) { this.connection = connection; this.diagram = diagram; this.title = "New connection"; }, undo: function () { this.diagram.remove(this.connection, false); }, redo: function () { this.diagram._addConnection(this.connection, false); } }); var AddShapeUnit = Class.extend({ init: function (shape, diagram) { this.shape = shape; this.diagram = diagram; this.title = "New shape"; }, undo: function () { this.diagram.deselect(); this.diagram.remove(this.shape, false); }, redo: function () { this.diagram._addShape(this.shape, false); } }); var PanUndoUnit = Class.extend({ init: function (initialPosition, finalPosition, diagram) { this.initial = initialPosition; this.finalPos = finalPosition; this.diagram = diagram; this.title = "Pan Unit"; }, undo: function () { this.diagram.pan(this.initial); }, redo: function () { this.diagram.pan(this.finalPos); } }); var RotateUnit = Class.extend({ init: function (adorner, shapes, undoRotates) { this.shapes = shapes; this.undoRotates = undoRotates; this.title = "Rotation"; this.redoRotates = []; this.redoAngle = adorner._angle; this.adorner = adorner; this.center = adorner._innerBounds.center(); for (var i = 0; i < this.shapes.length; i++) { var shape = this.shapes[i]; this.redoRotates.push(shape.rotate().angle); } }, undo: function () { var i, shape; for (i = 0; i < this.shapes.length; i++) { shape = this.shapes[i]; shape.rotate(this.undoRotates[i], this.center, false); if (shape.hasOwnProperty("layout")) { shape.layout(shape); } shape.updateModel(); } if (this.adorner) { this.adorner._initialize(); this.adorner.refresh(); } }, redo: function () { var i, shape; for (i = 0; i < this.shapes.length; i++) { shape = this.shapes[i]; shape.rotate(this.redoRotates[i], this.center, false); if (shape.hasOwnProperty("layout")) { shape.layout(shape); } shape.updateModel(); } if (this.adorner) { this.adorner._initialize(); this.adorner.refresh(); } } }); var ToFrontUnit = Class.extend({ init: function (diagram, items, initialIndices) { this.diagram = diagram; this.indices = initialIndices; this.items = items; this.title = "Rotate Unit"; }, undo: function () { this.diagram._toIndex(this.items, this.indices); }, redo: function () { this.diagram.toFront(this.items, false); } }); var ToBackUnit = Class.extend({ init: function (diagram, items, initialIndices) { this.diagram = diagram; this.indices = initialIndices; this.items = items; this.title = "Rotate Unit"; }, undo: function () { this.diagram._toIndex(this.items, this.indices); }, redo: function () { this.diagram.toBack(this.items, false); } }); /** * Undo-redo service. */ var UndoRedoService = kendo.Observable.extend({ init: function (options) { kendo.Observable.fn.init.call(this, options); this.bind(this.events, options); this.stack = []; this.index = 0; this.capacity = 100; }, events: ["undone", "redone"], /** * Starts the collection of units. Add those with * the addCompositeItem method and call commit. Or cancel to forget about it. */ begin: function () { this.composite = new CompositeUnit(); }, /** * Cancels the collection process of unit started with 'begin'. */ cancel: function () { this.composite = undefined; }, /** * Commits a batch of units. */ commit: function (execute) { if (this.composite.units.length > 0) { this._restart(this.composite, execute); } this.composite = undefined; }, /** * Adds a unit as part of the begin-commit batch. * @param undoUnit */ addCompositeItem: function (undoUnit) { if (this.composite) { this.composite.add(undoUnit); } else { this.add(undoUnit); } }, /** * Standard addition of a unit. See also the batch version; begin-addCompositeUnit-commit methods. * @param undoUnit The unit to be added. * @param execute If false, the unit will be added but not executed. */ add: function (undoUnit, execute) { this._restart(undoUnit, execute); }, /** * Returns the number of undoable unit in the stack. * @returns {Number} */ pop: function() { if (this.index > 0) { this.stack.pop(); this.index--; } }, count: function () { return this.stack.length; }, /** * Rollback of the unit on top of the stack. */ undo: function () { if (this.index > 0) { this.index--; this.stack[this.index].undo(); this.trigger("undone"); } }, /** * Redo of the last undone action. */ redo: function () { if (this.stack.length > 0 && this.index < this.stack.length) { this.stack[this.index].redo(); this.index++; this.trigger("redone"); } }, _restart: function (composite, execute) { // throw away anything beyond this point if this is a new branch this.stack.splice(this.index, this.stack.length - this.index); this.stack.push(composite); if (execute !== false) { this.redo(); } else { this.index++; } // check the capacity if (this.stack.length > this.capacity) { this.stack.splice(0, this.stack.length - this.capacity); this.index = this.capacity; //points to the end of the stack } }, /** * Clears the stack. */ clear: function () { this.stack = []; this.index = 0; } }); // Tools ========================================= var EmptyTool = Class.extend({ init: function (toolService) { this.toolService = toolService; }, start: function () { }, move: function () { }, end: function () { }, tryActivate: function () { return false; }, getCursor: function () { return Cursors.arrow; } }); var ScrollerTool = EmptyTool.extend({ init: function (toolService) { var tool = this; var friction = kendo.support.mobileOS ? FRICTION_MOBILE : FRICTION; EmptyTool.fn.init.call(tool, toolService); var diagram = tool.toolService.diagram, canvas = diagram.canvas; var scroller = diagram.scroller = tool.scroller = $(diagram.scrollable).kendoMobileScroller({ friction: friction, velocityMultiplier: VELOCITY_MULTIPLIER, mousewheelScrolling: false, zoom: false, scroll: proxy(tool._move, tool) }).data("kendoMobileScroller"); if (canvas.translate) { tool.movableCanvas = new Movable(canvas.element); } var virtualScroll = function (dimension, min, max) { dimension.makeVirtual(); dimension.virtualSize(min || SCROLL_MIN, max || SCROLL_MAX); }; virtualScroll(scroller.dimensions.x); virtualScroll(scroller.dimensions.y); scroller.disable(); }, tryActivate: function (p, meta) { var toolService = this.toolService; var options = toolService.diagram.options.pannable; var enabled = meta.ctrlKey; if (defined(options.key)) { if (!options.key || options.key == "none") { enabled = noMeta(meta) && !defined(toolService.hoveredItem); } else { enabled = meta[options.key + "Key"]; } } return options !== false && enabled && !defined(toolService.hoveredAdorner) && !defined(toolService._hoveredConnector); }, start: function () { this.scroller.enable(); }, move: function () { },//the tool itself should not handle the scrolling. Let kendo scroller take care of this part. Check _move _move: function (args) { var tool = this, diagram = tool.toolService.diagram, canvas = diagram.canvas, scrollPos = new Point(args.scrollLeft, args.scrollTop); if (canvas.translate) { diagram._storePan(scrollPos.times(-1)); tool.movableCanvas.moveTo(scrollPos); canvas.translate(scrollPos.x, scrollPos.y); } else { scrollPos = scrollPos.plus(diagram._pan.times(-1)); } diagram.trigger(PAN, {pan: scrollPos}); }, end: function () { this.scroller.disable(); }, getCursor: function () { return Cursors.move; } }); /** * The tool handling the transformations via the adorner. * @type {*} */ var PointerTool = Class.extend({ init: function (toolService) { this.toolService = toolService; }, tryActivate: function () { return true; // the pointer tool is last and handles all others requests. }, start: function (p, meta) { var toolService = this.toolService, diagram = toolService.diagram, hoveredItem = toolService.hoveredItem; if (hoveredItem) { toolService.selectSingle(hoveredItem, meta); if (hoveredItem.adorner) { //connection this.adorner = hoveredItem.adorner; this.handle = this.adorner._hitTest(p); } } if (!this.handle) { this.handle = diagram._resizingAdorner._hitTest(p); if (this.handle) { this.adorner = diagram._resizingAdorner; } } if (this.adorner) { if (!this.adorner.isDragHandle(this.handle) || !diagram.trigger(DRAG_START, { shapes: this.adorner.shapes, connections: [] })) { this.adorner.start(p); } else { toolService.startPoint = p; toolService.end(p); } } }, move: function (p) { if (this.adorner) { this.adorner.move(this.handle, p); if (this.adorner.isDragHandle(this.handle)) { this.toolService.diagram.trigger(DRAG, { shapes: this.adorner.shapes, connections: [] }); } } }, end: function () { var diagram = this.toolService.diagram, adorner = this.adorner, unit; if (adorner) { if (!adorner.isDragHandle(this.handle) || !diagram.trigger(DRAG_END, { shapes: adorner.shapes, connections: [] })) { unit = adorner.stop(); if (unit) { diagram.undoRedoService.add(unit, false); } } else { adorner.cancel(); } } this.adorner = undefined; this.handle = undefined; }, getCursor: function (p) { return this.toolService.hoveredItem ? this.toolService.hoveredItem._getCursor(p) : Cursors.arrow; } }); var SelectionTool = Class.extend({ init: function (toolService) { this.toolService = toolService; }, tryActivate: function (p, meta) { var toolService = this.toolService; var selectable = toolService.diagram.options.selectable; var enabled = selectable && selectable.multiple !== false; if (enabled) { if (selectable.key && selectable.key != "none") { enabled = meta[selectable.key + "Key"]; } else { enabled = noMeta(meta); } } return enabled && !defined(toolService.hoveredItem) && !defined(toolService.hoveredAdorner); }, start: function (p) { var diagram = this.toolService.diagram; diagram.deselect(); diagram.selector.start(p); }, move: function (p) { var diagram = this.toolService.diagram; diagram.selector.move(p); }, end: function (p, meta) { var diagram = this.toolService.diagram, hoveredItem = this.toolService.hoveredItem; var rect = diagram.selector.bounds(); if ((!hoveredItem || !hoveredItem.isSelected) && !meta.ctrlKey) { diagram.deselect(); } if (!rect.isEmpty()) { diagram.selectArea(rect); } diagram.selector.end(); }, getCursor: function () { return Cursors.arrow; } }); var ConnectionTool = Class.extend({ init: function (toolService) { this.toolService = toolService; this.type = "ConnectionTool"; }, tryActivate: function() { return this.toolService._hoveredConnector; }, start: function (p, meta) { var toolService = this.toolService, diagram = toolService.diagram, connector = toolService._hoveredConnector, connection = diagram._createConnection({}, connector._c, p); if (canDrag(connection) && !diagram.trigger(DRAG_START, { shapes: [], connections: [connection], connectionHandle: TARGET }) && diagram._addConnection(connection)) { toolService._connectionManipulation(connection, connector._c.shape, true); toolService._removeHover(); toolService.selectSingle(toolService.activeConnection, meta); if (meta.type == "touchmove") { diagram._cachedTouchTarget = connector.visual; } } else { connection.source(null); toolService.end(p); } }, move: function (p) { var toolService = this.toolService; var connection = toolService.activeConnection; connection.target(p); toolService.diagram.trigger(DRAG, { shapes: [], connections: [connection], connectionHandle: TARGET }); return true; }, end: function (p) { var toolService = this.toolService, d = toolService.diagram, connection = toolService.activeConnection, hoveredItem = toolService.hoveredItem, connector = toolService._hoveredConnector, target, cachedTouchTarget = d._cachedTouchTarget; if (!connection) { return; } if (connector && connector._c != connection.sourceConnector) { target = connector._c; } else if (hoveredItem && hoveredItem instanceof diagram.Shape) { target = hoveredItem.getConnector(AUTO) || hoveredItem.getConnector(p); } else { target = p; } connection.target(target); if (!d.trigger(DRAG_END, { shapes: [], connections: [connection], connectionHandle: TARGET })) { connection.updateModel(); d._syncConnectionChanges(); } else { d.remove(connection, false); d.undoRedoService.pop(); } toolService._connectionManipulation(); if(cachedTouchTarget) { d._connectorsAdorner.visual.remove(cachedTouchTarget); d._cachedTouchTarget = null; } }, getCursor: function () { return Cursors.arrow; } }); var ConnectionEditTool = Class.extend({ init: function (toolService) { this.toolService = toolService; this.type = "ConnectionTool"; }, tryActivate: function (p, meta) { var toolService = this.toolService, diagram = toolService.diagram, selectable = diagram.options.selectable, item = toolService.hoveredItem, isActive = selectable !== false && item && item.path && !(item.isSelected && meta.ctrlKey); if (isActive) { this._c = item; } return isActive; }, start: function (p, meta) { var toolService = this.toolService; var connection = this._c; toolService.selectSingle(connection, meta); var adorner = connection.adorner; var handle, name; if (adorner) { handle = adorner._hitTest(p); name = HANDLE_NAMES[handle]; } if (canDrag(connection) && adorner && !toolService.diagram.trigger(DRAG_START, { shapes: [], connections: [connection], connectionHandle: name })) { this.handle = handle; this.handleName = name; adorner.start(p); } else { toolService.startPoint = p; toolService.end(p); } }, move: function (p) { var adorner = this._c.adorner; if (canDrag(this._c) && adorner) { adorner.move(this.handle, p); this.toolService.diagram.trigger(DRAG, { shapes: [], connections: [this._c], connectionHandle: this.handleName }); return true; } }, end: function (p) { var connection = this._c; var adorner = connection.adorner; var toolService = this.toolService; var diagram = toolService.diagram; if (adorner) { if (canDrag(connection)) { var unit = adorner.stop(p); if (!diagram.trigger(DRAG_END, { shapes: [], connections: [connection], connectionHandle: this.handleName })) { diagram.undoRedoService.add(unit, false); connection.updateModel(); diagram._syncConnectionChanges(); } else { unit.undo(); } } } }, getCursor: function () { return Cursors.move; } }); function testKey(key, str) { return str.charCodeAt(0) == key || str.toUpperCase().charCodeAt(0) == key; } /** * The service managing the tools. * @type {*} */ var ToolService = Class.extend({ init: function (diagram) { this.diagram = diagram; this.tools = [ new ScrollerTool(this), new ConnectionEditTool(this), new ConnectionTool(this), new SelectionTool(this), new PointerTool(this) ]; // the order matters. this.activeTool = undefined; }, start: function (p, meta) { meta = deepExtend({}, meta); if (this.activeTool) { this.activeTool.end(p, meta); } this._updateHoveredItem(p); this._activateTool(p, meta); this.activeTool.start(p, meta); this._updateCursor(p); this.diagram.focus(); this.diagram.canvas.surface.suspendTracking(); this.startPoint = p; return true; }, move: function (p, meta) { meta = deepExtend({}, meta); var updateHovered = true; if (this.activeTool) { updateHovered = this.activeTool.move(p, meta); } if (updateHovered) { this._updateHoveredItem(p); } this._updateCursor(p); return true; }, end: function (p, meta) { meta = deepExtend({}, meta); if (this.activeTool) { this.activeTool.end(p, meta); } this.diagram.canvas.surface.resumeTracking(); this.activeTool = undefined; this._updateCursor(p); return true; }, keyDown: function (key, meta) { var diagram = this.diagram; meta = deepExtend({ ctrlKey: false, metaKey: false, altKey: false }, meta); if ((meta.ctrlKey || meta.metaKey) && !meta.altKey) {// ctrl or option if (testKey(key, "a")) {// A: select all diagram.selectAll(); diagram._destroyToolBar(); return true; } else if (testKey(key, "z")) {// Z: undo diagram.undo(); diagram._destroyToolBar(); return true; } else if (testKey(key, "y")) {// y: redo diagram.redo(); diagram._destroyToolBar(); return true; } else if (testKey(key, "c")) { diagram.copy(); diagram._destroyToolBar(); } else if (testKey(key, "x")) { diagram.cut(); diagram._destroyToolBar(); } else if (testKey(key, "v")) { diagram.paste(); diagram._destroyToolBar(); } else if (testKey(key, "l")) { diagram.layout(); diagram._destroyToolBar(); } else if (testKey(key, "d")) { diagram._destroyToolBar(); diagram.copy(); diagram.paste(); } } else if (key === 46 || key === 8) {// del: deletion var toRemove = this.diagram._triggerRemove(diagram.select()); if (toRemove.length) { this.diagram.remove(toRemove, true); this.diagram._syncChanges(); this.diagram._destroyToolBar(); } return true; } else if (key === 27) {// ESC: stop any action this._discardNewConnection(); diagram.deselect(); diagram._destroyToolBar(); return true; } }, wheel: function (p, meta) { var diagram = this.diagram, delta = meta.delta, z = diagram.zoom(), options = diagram.options, zoomRate = options.zoomRate, zoomOptions = { point: p, meta: meta, zoom: z }; if (diagram.trigger(ZOOM_START, zoomOptions)) { return; } if (delta < 0) { z += zoomRate; } else { z -= zoomRate; } z = kendo.dataviz.round(Math.max(options.zoomMin, Math.min(options.zoomMax, z)), 2); zoomOptions.zoom = z; diagram.zoom(z, zoomOptions); diagram.trigger(ZOOM_END, zoomOptions); return true; }, setTool: function (tool, index) { tool.toolService = this; this.tools[index] = tool; }, selectSingle: function(item, meta) { var diagram = this.diagram; var selectable = diagram.options.selectable; if (selectable && !item.isSelected && item.options.selectable !== false) { var addToSelection = meta.ctrlKey && selectable.multiple !== false; diagram.select(item, { addToSelection: addToSelection }); } }, _discardNewConnection: function () { if (this.newConnection) { this.diagram.remove(this.newConnection); this.newConnection = undefined; } }, _activateTool: function (p, meta) { for (var i = 0; i < this.tools.length; i++) { var tool = this.tools[i]; if (tool.tryActivate(p, meta)) { this.activeTool = tool; break; // activating the first available tool in the loop. } } }, _updateCursor: function (p) { var element = this.diagram.element; var cursor = this.activeTool ? this.activeTool.getCursor(p) : (this.hoveredAdorner ? this.hoveredAdorner._getCursor(p) : (this.hoveredItem ? this.hoveredItem._getCursor(p) : Cursors.arrow)); element.css({cursor: cursor}); // workaround for IE 7 issue in which the elements overflow the container after setting cursor if (browser.msie && browser.version == 7) { element[0].style.cssText = element[0].style.cssText; } }, _connectionManipulation: function (connection, disabledShape, isNew) { this.activeConnection = connection; this.disabledShape = disabledShape; if (isNew) { this.newConnection = this.activeConnection; } else { this.newConnection = undefined; } }, _updateHoveredItem: function (p) { var hit = this._hitTest(p); var diagram = this.diagram; if (hit != this.hoveredItem && (!this.disabledShape || hit != this.disabledShape)) { if (this.hoveredItem) { diagram.trigger(MOUSE_LEAVE, { item: this.hoveredItem }); this.hoveredItem._hover(false); } if (hit && hit.options.enable) { diagram.trigger(MOUSE_ENTER, { item: hit }); this.hoveredItem = hit; // Shape, connection or connector this.hoveredItem._hover(true); } else { this.hoveredItem = undefined; } } }, _removeHover: function () { if (this.hoveredItem) { this.hoveredItem._hover(false); this.hoveredItem = undefined; } }, _hitTest: function (point) { var hit, d = this.diagram, item, i; // connectors if (this._hoveredConnector) { this._hoveredConnector._hover(false); this._hoveredConnector = undefined; } if (d._connectorsAdorner._visible) { hit = d._connectorsAdorner._hitTest(point); if (hit) { return hit; } } hit = this.diagram._resizingAdorner._hitTest(point); if (hit) { this.hoveredAdorner = d._resizingAdorner; if (hit.x !== 0 || hit.y !== 0) { // hit testing for resizers or rotator, otherwise if (0,0) than pass through. return; } hit = undefined; } else { this.hoveredAdorner = undefined; } if (!this.activeTool || this.activeTool.type !== "ConnectionTool") { var selectedConnections = []; // only the connections should have higher presence because the connection edit point is on top of connector. // TODO: This should be reworked. The connection adorner should be one for all selected connections and should be hit tested prior the connections and shapes itself. for (i = 0; i < d._selectedItems.length; i++) { item = d._selectedItems[i]; if (item instanceof diagram.Connection) { selectedConnections.push(item); } } hit = this._hitTestItems(selectedConnections, point); } return hit || this._hitTestElements(point); }, _hitTestElements: function(point) { var diagram = this.diagram; var shapeHit = this._hitTestItems(diagram.shapes, point); var connectionHit = this._hitTestItems(diagram.connections, point); var hit; if ((!this.activeTool || this.activeTool.type != "ConnectionTool") && shapeHit && connectionHit && !hitTestShapeConnectors(shapeHit, point)) { var mainLayer = diagram.mainLayer; var shapeIdx = inArray(shapeHit.visual, mainLayer.children); var connectionIdx = inArray(connectionHit.visual, mainLayer.children); hit = shapeIdx > connectionIdx ? shapeHit : connectionHit; } return hit || shapeHit || connectionHit; }, _hitTestItems: function (array, point) { var i, item, hit; for (i = array.length - 1; i >= 0; i--) { item = array[i]; hit = item._hitTest(point); if (hit) { return hit; } } } }); // Routing ========================================= /** * Base class for connection routers. */