UNPKG

@progress/kendo-ui

Version:

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

1,637 lines (1,628 loc) 49.4 kB
import { AddConnectionUnit, AddShapeUnit, ArrowMarker, Canvas, CascadingRouter, Circle, CircleMarker, Collate, CompositeTransform, CompositeUnit, Connection, ConnectionEditAdorner, ConnectionEditTool, ConnectionEditUnit, ConnectionRouterBase, ConnectionTool, Connector, ConnectorVisual, ConnectorsAdorner, Cursors, DataInputOutput, DataStorage, Database, Decision, DefaultConnectors, Delay, DeleteConnectionUnit, DeleteShapeUnit, Diagram, DiagramToHyperTreeAdapter, Dictionary, DirectAccessStorage, Display, Document, Element, Extract, Geometry, Graph, Group, HashTable, Image, InternalStorage, Intersect, LayeredLayout, Layout, LayoutBase, LayoutState, LayoutUndoUnit, Line, Link, LogicalOr, ManualInputOutput, ManualOperation, MarkerBase, Markers, Matrix, MatrixVector, Merge, MultipleDocuments, Node, OffPageConnector, OnPageConnector, PanUndoUnit, Path, PathDefiner, Point, PointerTool, Polyline, PolylineRouter, PredefinedProcess, Preparation, Process, QuadNode, QuadRoot, Queue, Range, Rect, RectAlign, Rectangle, ResizingAdorner, RotateUnit, Rotation, Scale, ScrollerTool, SelectionTool, Selector, Set, Shape, ShapesQuadTree, Size, Sort, SpringLayout, SummingJunction, TemplateService, Terminator, TextBlock, Ticker, ToBackUnit, ToFrontUnit, ToolService, TransformUnit, Translation, TreeLayout, UndoRedoService, Utils, VisualBase, defaultOptions, diffNumericOptions, events, loadTheme, normalVariable, placeTooltip, randomId, shapeDefaults } from "@progress/kendo-diagram-common"; //#region ../src/dataviz/diagram/utils.js (function() { var kendo = window.kendo, diagram = kendo.dataviz.diagram = {}; kendo.deepExtend(diagram, { init: function(element) { kendo.init(element, diagram.ui); }, Utils, Range, Ticker }); })(); //#endregion //#region ../src/dataviz/diagram/math.js (function() { var kendo = window.kendo, diagram = kendo.dataviz.diagram; kendo.deepExtend(diagram, { init: function(element) { kendo.init(element, diagram.ui); }, Point, Intersect, Geometry, Rect, Size, RectAlign, Matrix, MatrixVector, normalVariable, randomId, Dictionary, HashTable, Queue, Set, Node, Link, Graph, PathDefiner }); })(); //#endregion //#region ../src/dataviz/diagram/svg.js const { isFunction } = Utils; (function() { var kendo = window.kendo, drawing = kendo.drawing, diagram = kendo.dataviz.diagram; class Canvas$1 extends Canvas { constructor(element, options) { options = options || {}; super(element, options); this.surface = drawing.Surface.create(element, options); this.translate = isFunction(this.surface.translate) ? this._translate : undefined; this._viewBox = new Rect(0, 0, options.width, options.height); this.size(this._viewBox); } } kendo.deepExtend(diagram, { init: function(element) { kendo.init(element, diagram.ui); }, diffNumericOptions, Markers, Element, Scale, Translation, Rotation, Circle, Group, Rectangle, Canvas: Canvas$1, Path, Layout, Line, MarkerBase, ArrowMarker, CircleMarker, Polyline, CompositeTransform, TextBlock, Terminator, Process, Decision, PredefinedProcess, Document, ManualInputOutput, Preparation, ManualOperation, InternalStorage, Display, DirectAccessStorage, Database, OnPageConnector, OffPageConnector, DataInputOutput, SummingJunction, LogicalOr, Merge, Extract, DataStorage, Delay, Sort, Collate, MultipleDocuments, Image, VisualBase }); })(); //#endregion //#region ../src/dataviz/diagram/services.js (function() { var kendo = window.kendo, dataviz = kendo.dataviz, diagram = dataviz.diagram; diagram.Cursors = Cursors; kendo.deepExtend(diagram, { CompositeUnit, TransformUnit, PanUndoUnit, AddShapeUnit, AddConnectionUnit, DeleteShapeUnit, DeleteConnectionUnit, ConnectionEditAdorner, ConnectionTool, ConnectorVisual, UndoRedoService, ResizingAdorner, Selector, ToolService, ConnectorsAdorner, LayoutUndoUnit, ConnectionEditUnit, ToFrontUnit, ToBackUnit, ConnectionRouterBase, PolylineRouter, CascadingRouter, SelectionTool, ScrollerTool, PointerTool, ConnectionEditTool, RotateUnit }); })(); //#endregion //#region ../src/dataviz/diagram/layout.js (function() { var kendo = window.kendo, diagram = kendo.dataviz.diagram; kendo.deepExtend(diagram, { init: function(element) { kendo.init(element, diagram.ui); }, SpringLayout, TreeLayout, GraphAdapter: DiagramToHyperTreeAdapter, LayeredLayout, LayoutBase, LayoutState }); })(); //#endregion //#region ../src/dataviz/diagram/theme.js (function() { const kendo = window.kendo; const dataviz = kendo.dataviz; dataviz.diagramTheme = loadTheme; })(); //#endregion //#region ../src/dataviz/diagram/dom.js (function($, undefined) { var dataviz = kendo.dataviz, diagram = dataviz.diagram, Widget = kendo.ui.Widget, deepExtend = kendo.deepExtend, outerWidth = kendo._outerWidth, outerHeight = kendo._outerHeight, extend = $.extend, HierarchicalDataSource = kendo.data.HierarchicalDataSource, Canvas = diagram.Canvas, Rect = diagram.Rect, Point = diagram.Point, defined = kendo.drawing.util.defined, isPlainObject = $.isPlainObject, DataSource = kendo.data.DataSource; TemplateService.register({ compile: function(template) { return kendo.template(template, { paramName: "dataItem" }); } }); var NS = ".kendoDiagram", CLICK = "click", ROTATED = "rotated", CHANGE = "change", ERROR = "error", BUTTON_TEMPLATE = ({ className, icon, themeColor, text }) => kendo.html.renderButton(`<button class="${className}" href="#">${text}</button>`, { icon, themeColor }); function preventDefault(e) { e.preventDefault(); } function clearField(field, model) { if (defined(model[field])) { model.set(field, null); } } const toolTipContainer = (content) => `<div class="k-popup">${content}</div>`; const toPx = (v) => Math.round(v) + "px"; diagram.DefaultConnectors = DefaultConnectors; var defaultButtons = { cancel: { text: "Cancel", icon: "cancel", className: "k-diagram-cancel" }, update: { text: "Save", imageClass: "save", className: "k-diagram-update", icon: "save", themeColor: "primary" } }; diagram.shapeDefaults = shapeDefaults; var Diagram$1 = Widget.extend({ init: function(element, userOptions = {}) { var that = this; kendo.destroy(element); Widget.fn.init.call(that, element, userOptions); const theme = that._initTheme(); const isEditable = defined(userOptions.connectionsDataSource); this._isEditable = isEditable; const extendedOptions = { ...that.options, _syncChanges: that._syncChanges.bind(that), _syncShapeChanges: that._syncShapeChanges.bind(that), _syncConnectionChanges: that._syncConnectionChanges.bind(that), _removeConnectionDataItem: that._removeConnectionDataItem.bind(that), _removeShapeDataItem: that._removeShapeDataItem.bind(that), _addConnection: that._addConnection.bind(that), _addShape: that._addShape.bind(that), updateConnectionModel: that.updateConnectionModel.bind(that), updateShapeModel: that.updateShapeModel.bind(that), cloneDataItem, connect: isEditable ? that.connect.bind(that) : undefined, createToolBar: that._createToolBar.bind(that), destroyToolBar: that._destroyToolBar.bind(that), Canvas, shapeDefaults: { ...userOptions.shapeDefaults }, navigation: { ...userOptions.navigatable }, connectionDefaults: { ...userOptions.connectionDefaults } }; const widget = new Diagram(element, extendedOptions, theme); that.events.forEach(function(eventName) { widget.bind(eventName, function(e) { if (eventName === "tooltipShow") { that._clearTooltips(); const tooltipSettings = that.options.tooltip || {}; if (e.item.name === "Shape" && tooltipSettings.shapeTemplate) { that._createTooltip(e.item, e.point, tooltipSettings.shapeTemplate, true); } else if (e.item.name === "Connection" && tooltipSettings.connectionTemplate) { that._createTooltip(e.item, e.point, tooltipSettings.connectionTemplate, false); } } if (eventName === "tooltipHide") { that._clearTooltips(); } e.sender = that; that.trigger(eventName, e); }); }); that.widget = widget; that.wrapper = $(widget.wrapper); that.scrollable = $(widget.scrollable); that.shapes = widget.shapes; that.connections = widget.connections; that._connectionsDataMap = widget._connectionsDataMap; that._dataMap = widget._dataMap; that._inactiveShapeItems = widget._inactiveShapeItems; that._copyOffset = 0; that._selectedItems = widget._selectedItems; that.options = widget.options; that._clipboard = widget._clipboard; that.id = widget.id; that.undoRedoService = widget.undoRedoService; that.toolService = widget.toolService; that._resizingAdorner = widget._resizingAdorner; that._connectorsAdorner = widget._connectorsAdorner; that.selector = widget.selector; that.mainLayer = widget.mainLayer; that._fetchFreshData(); that._createGlobalToolBar(); that.widget._createOptionElements(); that.widget.zoom(that.options.zoom); that.widget.canvas.draw(); }, options: deepExtend({}, defaultOptions), events: [...events], shapes: [], connections: [], dataSource: null, connectionsDataSource: null, connect: function(source, target, options) { let connection; if (this.connectionsDataSource && this._isEditable) { const dataItem = this.connectionsDataSource.add({}); connection = this.widget._connectionsDataMap[dataItem.uid]; connection.source(source); connection.target(target); connection.redraw(options); connection.updateModel(); } else { connection = this.widget.connect(source, target, options); } return connection; }, connected: function(source, target) { return this.widget.connected(source, target); }, addConnection: function(connection, undoable) { return this.widget.addConnection(connection, undoable); }, addShape: function(item, undoable) { return this.widget.addShape(item, undoable); }, remove: function(items, undoable) { return this.widget.remove(items, undoable); }, undo: function() { return this.widget.undo(); }, redo: function() { return this.widget.redo(); }, select: function(item, options) { return this.widget.select(item, options); }, deselect: function(item) { this.widget.deselect(item); }, toFront: function(items, undoable) { return this.widget.toFront(items, undoable); }, toBack: function(items, undoable) { return this.widget.toBack(items, undoable); }, bringIntoView: function(item, options) { return this.widget.bringIntoView(item, options); }, boundingBox: function(items, origin) { return this.widget.boundingBox(items, origin); }, layout: function(options) { return this.widget.layout(options); }, getShapeById: function(id) { return this.widget.getShapeById(id); }, getConnectionByModelId(id) { let connectionResult; if (this.connectionsDataSource) { connectionResult = Utils.first(this.connections, function(connection) { return (connection.dataItem || {}).id === id; }); } return connectionResult; }, getConnectionByModelUid(uid) { let connection; if (this.connectionsDataSource) { connection = this.widget._connectionsDataMap[uid]; } return connection; }, copy: function() { this.widget.copy(); }, cut: function() { this.widget.cut(); }, alignShapes: function(direction) { return this.widget.alignShapes(direction); }, 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.widget._createShape(model, {}); if (!this.trigger("add", { shape })) { dataSource.insert(index, model); var inactiveItem = this.widget._inactiveShapeItems.getByUid(model.uid); inactiveItem.element = shape; this.edit(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.widget._createConnection(model); if (!this.trigger("add", { connection })) { this.widget._connectionsDataMap[model.uid] = connection; connectionsDataSource.insert(index, model); this.addConnection(connection, false); this.edit(connection); } } }, exportVisual: function() { return this.widget.exportVisual(); }, exportDOMVisual: function() { return this.widget.exportDOMVisual(); }, _syncChanges() { this._syncShapeChanges(); this._syncConnectionChanges(); }, _syncShapeChanges() { if (this.dataSource && this._isEditable) { this.dataSource.sync(); } }, _syncConnectionChanges() { if (this.connectionsDataSource && this._isEditable) { Promise.all(this.widget._deferredConnectionUpdates).then(() => { this.connectionsDataSource.sync(); this.widget._deferredConnectionUpdates.length = 0; }); } }, editModel: function(dataItem, editorType) { this.cancelEdit(); var editors, template; var editable = this.widget.options.editable; if (editorType == "shape") { editors = editable.shapeEditors; template = editable.shapeTemplate; } else if (editorType == "connection") { var connectionSelectorHandler = connectionSelector.bind(this); editors = deepExtend({}, { from: connectionSelectorHandler, to: connectionSelectorHandler }, editable.connectionEditors); template = editable.connectionTemplate; } else { return; } this.editor = new PopupEditor(this.element, { update: this._update.bind(this), cancel: this._cancel.bind(this), model: dataItem, type: editorType, target: this, editors, 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(); } }, clear() { this.widget.clear(); }, saveEdit: function() { if (this.editor && this.editor.end() && !this.trigger("save", this._editArgs())) { this._getEditDataSource().sync(); } }, updateConnectionModel: function(connection, syncChanges) { if (this.connectionsDataSource) { const model = this.connectionsDataSource.getByUid(connection.dataItem.uid); if (model) { this._suspendModelRefresh(); if (defined(connection.options.fromX) && connection.options.fromX !== null) { clearField("from", model); clearField("fromConnector", model); model.set("fromX", connection.options.fromX); model.set("fromY", connection.options.fromY); } else { model.set("from", connection.options.from); if (defined(model.fromConnector)) { model.set("fromConnector", connection.sourceConnector ? connection.sourceConnector.options.name : null); } clearField("fromX", model); clearField("fromY", model); } if (defined(connection.options.toX) && connection.options.toX !== null) { clearField("to", model); clearField("toConnector", model); model.set("toX", connection.options.toX); model.set("toY", connection.options.toY); } else { model.set("to", connection.options.to); if (defined(model.toConnector)) { model.set("toConnector", connection.targetConnector ? connection.targetConnector.options.name : null); } clearField("toX", model); clearField("toY", model); } if (defined(connection.options.type) && defined(model.type)) { model.set("type", connection.options.type); } connection.dataItem = model; this._resumeModelRefresh(); if (syncChanges) { this._syncConnectionChanges(); } } } }, updateShapeModel: function(shape, syncChanges) { const bounds = shape._bounds; const model = shape.dataItem; if (model) { this._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); } shape.dataItem = model; this._resumeModelRefresh(); if (syncChanges) { this._syncShapeChanges(); } } }, destroy: function() { this.diagram = null; this.element = null; this.options = null; if (this._toolBar) { this._toolBar.destroy(); } if (this._popup) { this._popup.destroy(); } this._destroyGlobalToolBar(); this._destroyToolBar(); if (this.widget) { this.widget.destroy(); this.widget = null; } }, documentToModel: function(point) { return this.widget.documentToModel(point); }, documentToView: function(point) { return this.widget.documentToView(point); }, focus: function() { return this.widget.focus(); }, getShapeByModelId: function(id) { return this.widget.getShapeByModelId(id); }, getShapeByModelUid: function(uid) { return this.widget.getShapeByModelUid(uid); }, layerToModel: function(point) { return this.widget.layerToModel(point); }, load: function(options) { this.widget.load(options); }, modelToDocument: function(point) { return this.widget.modelToDocument(point); }, modelToLayer: function(point) { return this.widget.modelToLayer(point); }, modelToView: function(point) { return this.widget.modelToView(point); }, pan: function(pan, animate) { return this.widget.pan(pan, animate); }, paste: function() { this.widget.paste(); }, save: function() { return this.widget.save(); }, selectAll: function() { this.widget.selectAll(); }, selectArea: function(rect) { this.widget.selectArea(rect); }, setDataSource(dataSource) { this.options.dataSource = dataSource; this._dataSource(); if (this.options.autoBind !== false) { this.dataSource.fetch(); } }, setConnectionsDataSource(dataSource) { this.options.connectionsDataSource = dataSource; this._connectionDataSource(); if (this.options.autoBind !== false) { this.connectionsDataSource.fetch(); } }, viewToDocument: function(point) { return this.widget.viewToDocument(point); }, viewToModel: function(point) { return this.widget.viewToModel(point); }, viewport: function() { return this.widget.viewport(); }, zoom: function(zoom, options) { return this.widget.zoom(zoom, options); }, _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) { that.element.addClass("k-diagram"); themeOptions = dataviz.diagramTheme(that.element[0]); that.element.removeClass("k-diagram"); } else { themeOptions = (themes[themeName] || {}).diagram; } return themeOptions; }, items: function() { return $(); }, _createGlobalToolBar: function() { const widget = this.widget; var editable = this.widget.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: this._toolBarClick.bind(this), modal: false }); this.widget.toolBar = { element: this.toolBar.element[0] }; this.toolBar.element.css({ textAlign: "left" }); this.element.prepend(this.toolBar.element); this.widget._resize(); } } }, _toolBarClick: function(e) { this.trigger("toolBarClick", e); this._destroyToolBar(); }, _createToolBar: function(preventClosing) { const diagram = this; const widget = this.widget; 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 && 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(this, { tools, click: this._toolBarClick.bind(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 = widget.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 = widget.modelToView(element.bounds()); point = new Point(connectionBounds.x, connectionBounds.y).minus(new Point((popupWidth - connectionBounds.width - 20) / 2, popupHeight + padding)); } if (point) { if (!widget.canvas.translate) { point = point.minus(new Point(widget.scroller.scrollLeft, widget.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(); } } } } }, _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; } }, _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.widget._connectionsDataMap[model.uid] || this.widget._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; }, _fetchFreshData() { this._dataSource(); if (this._isEditable) { this._connectionDataSource(); } if (this.options.autoBind !== false) { if (this._isEditable) { this._loadingShapes = true; this._loadingConnections = true; this.dataSource.fetch(); this.connectionsDataSource.fetch(); } else { this.dataSource.fetch(); } } }, _dataSource() { if (defined(this.options.connectionsDataSource)) { this.widget._isEditable = true; const dsOptions = this.options.dataSource || {}; const ds = Array.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 = this._refreshShapes.bind(this); this._shapesRequestStartHandler = this._shapesRequestStart.bind(this); this._shapesErrorHandler = this._error.bind(this); } this.dataSource = DataSource.create(ds).bind("change", this._shapesRefreshHandler).bind("requestStart", this._shapesRequestStartHandler).bind("error", this._shapesErrorHandler); } else { this._treeDataSource(); this.widget._isEditable = false; } }, _connectionDataSource() { const dsOptions = this.options.connectionsDataSource; if (dsOptions) { const ds = Array.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 = this._refreshConnections.bind(this); this._connectionsRequestStartHandler = this._connectionsRequestStart.bind(this); this._connectionsErrorHandler = this._connectionsError.bind(this); } this.connectionsDataSource = DataSource.create(ds).bind("change", this._connectionsRefreshHandler).bind("requestStart", this._connectionsRequestStartHandler).bind("error", this._connectionsErrorHandler); } }, _shapesRequestStart(e) { if (e.type === "read") { this._loadingShapes = true; } }, _connectionsRequestStart(e) { if (e.type === "read") { this._loadingConnections = true; } }, _error() { this._loadingShapes = false; }, _connectionsError() { this._loadingConnections = false; }, _refreshShapes(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(); } else { this.refresh(); } }, _shouldRefresh() { return this.widget._shouldRefresh(); }, _suspendModelRefresh() { this.widget._suspendModelRefresh(); }, _resumeModelRefresh() { this.widget._resumeModelRefresh(); }, refresh() { this._loadingShapes = false; if (!this._loadingConnections) { this._rebindShapesAndConnections(); } }, _rebindShapesAndConnections() { 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() { this._loadingConnections = false; if (!this._loadingShapes) { this._rebindShapesAndConnections(); } }, _redrawConnections() { this.widget._redrawConnections(); }, _removeShapes(items) { const dataMap = this.widget._dataMap; let 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() { const inactiveItems = this._inactiveShapeItems; inactiveItems.forEach((inactiveItem) => { const dataItem = inactiveItem.dataItem; const shape = inactiveItem.element; if (!dataItem.isNew()) { if (shape) { shape._setOptionsFromModel(); this.addShape(shape, inactiveItem.undoable); this.widget._dataMap[dataItem.id] = shape; } else { this._addDataItem(dataItem); } inactiveItem.activate(); inactiveItems.remove(dataItem); } }); }, _updateShapes(items, field) { for (let i = 0; i < items.length; i++) { const dataItem = items[i]; const shape = this.widget._dataMap[dataItem.id]; if (shape) { shape.updateOptionsFromModel(dataItem, field); } } }, _addShapes(dataItems) { for (let i = 0; i < dataItems.length; i++) { this._addDataItem(dataItems[i], false); } }, _addDataItem(dataItem, undoable) { if (!Utils.defined(dataItem)) { return; } let shape = this.widget._dataMap[dataItem.id]; if (shape) { return shape; } const options = deepExtend({}, this.widget.options.shapeDefaults); options.dataItem = dataItem; shape = new Shape(options, this.widget); this.addShape(shape, undoable !== false); this.widget._dataMap[dataItem.id] = shape; return shape; }, _refreshConnections(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") {} else if (e.action === "itemchange") { if (this._shouldRefresh()) { this._updateConnections(e.items); } } else { this.refreshConnections(); } }, _removeConnections(items) { for (let i = 0; i < items.length; i++) { this.remove(this.widget._connectionsDataMap[items[i].uid], false); this.widget._connectionsDataMap[items[i].uid] = null; } }, _updateConnections(items) { for (let i = 0; i < items.length; i++) { const dataItem = items[i]; const connection = this.widget._connectionsDataMap[dataItem.uid]; connection.updateOptionsFromModel(dataItem); } }, _addConnections(connections, undoable) { this.widget._addConnections(connections, undoable); }, _addShape(shape, undoable) { const dataSource = this.dataSource; let dataItem; if (dataSource && this._isEditable) { dataItem = createModel(dataSource, cloneDataItem(shape.dataItem)); shape.dataItem = dataItem; shape.updateModel(); if (!this.trigger("add", { shape })) { this.dataSource.add(dataItem); const inactiveItem = this.widget._inactiveShapeItems.getByUid(dataItem.uid); inactiveItem.element = shape; inactiveItem.undoable = undoable; return shape; } } else if (!this.trigger("add", { shape })) { return this.addShape(shape, undoable); } }, _addConnection(connection, undoable) { const connectionsDataSource = this.connectionsDataSource; let dataItem; if (connectionsDataSource && this._isEditable) { dataItem = createModel(connectionsDataSource, cloneDataItem(connection.dataItem)); connection.dataItem = dataItem; connection.updateModel(); if (!this.trigger("add", { connection })) { this.widget._connectionsDataMap[dataItem.uid] = connection; connectionsDataSource.add(dataItem); this.addConnection(connection, undoable); connection._updateConnectors(); return connection; } } else if (!this.trigger("add", { connection })) { this.addConnection(connection, undoable); connection._updateConnectors(); return connection; } }, _treeDataSource() { const options = this.widget.options; let dataSource = options.dataSource; dataSource = Array.isArray(dataSource) ? { data: dataSource } : dataSource; if (dataSource instanceof DataSource && !(dataSource instanceof 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 (this.dataSource && this._refreshHandler) { this._unbindDataSource(); } this._refreshHandler = this._refreshSource.bind(this); this._errorHandler = this._error.bind(this); this.dataSource = HierarchicalDataSource.create(dataSource).bind(CHANGE, this._refreshHandler).bind(ERROR, this._errorHandler); }, _unbindDataSource() { this.dataSource.unbind(CHANGE, this._refreshHandler).unbind(ERROR, this._errorHandler); }, _refreshSource(e) { const node = e.node, action = e.action, items = e.items, options = this.options; let idx, dataBound; if (e.field) { for (idx = 0; idx < items.length; idx++) { if (this.widget._dataMap[items[idx].uid]) { this.widget._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) { this.clear(); } this.widget._addDataItems(items, node); for (idx = 0; idx < items.length; idx++) { items[idx].load(); } } if (options.layout && (dataBound || action === "remove" || action === "add")) { this.layout(options.layout); } if (dataBound) { this.trigger("dataBound"); this._bindingRoots = false; } }, _removeDataItems(items, recursive) { let item, children, shape, idx; items = Array.isArray(items) ? items : [items]; while (items.length) { item = items.shift(); shape = this.widget._dataMap[item.uid]; if (shape) { this.widget._removeShapeConnections(shape); this.widget._removeItem(shape, false); delete this.widget._dataMap[item.uid]; if (recursive && item.hasChildren && item.loaded()) { children = item.children.data(); for (idx = 0; idx < children.length; idx++) { items.push(children[idx]); } } } } }, _removeConnectionDataItem(dataItem) { this.connectionsDataSource.remove(dataItem); }, _removeShapeDataItem(dataItem) { this.dataSource.remove(dataItem); }, _clearTooltips: function() { if (this._shapeTooltip) { this._shapeTooltip.remove(); this._shapeTooltip = null; } if (this._connectionTooltip) { this._connectionTooltip.remove(); this._connectionTooltip = null; } }, _positionTooltip: function(tooltip, hovered, point) { const that = this; const diagram = that.widget; const zoom = diagram.zoom(); const pan = diagram.pan(); const toolTipEleement = tooltip[0]; const tooltipRect = toolTipEleement.getBoundingClientRect(); const diagramRect = diagram.element.getBoundingClientRect(); const win = diagram.element.ownerDocument.defaultView; const connections = diagram.connections.map((con) => con.allPoints()); const shapes = diagram.shapes.map((shp) => shp.bounds()); const pos = placeTooltip({ hovered, mouse: point, shapes, connections, diagramRect, zoom, pan, tooltipSize: { width: tooltipRect.width, height: tooltipRect.height }, viewportBounds: new DOMRect(0, 0, win.innerWidth, win.innerHeight) }); toolTipEleement.style.left = toPx(pos.left + win.scrollX); toolTipEleement.style.top = toPx(pos.top + win.scrollY); }, _createTooltip: function(shape, point, template, isShape) { const that = this; const tooltip = isShape ? "_shapeTooltip" : "_connectionTooltip"; that[tooltip] = $(toolTipContainer(kendo.template(template)(shape))).css("position", "absolute"); that._positionTooltip(that[tooltip], shape, point); that[tooltip].appendTo("body"); }, _destroyEditor: function() { if (this.editor) { this.editor.close(); this.editor = null; } } }); dataviz.ExportMixin.extend(Diagram$1.fn, true); if (kendo.PDFMixin) { kendo.PDFMixin.extend(Diagram$1.fn); } 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: this.click.bind(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: "pencil", showText: "overflow", type: "button", text: "Edit", attributes: this._setAttributes({ action: "edit" }) }); }, deleteTool: function() { this._tools.push({ icon: "x", 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: "shapes", 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, connections, action, target }; }, "delete": function() { var diagram = this.diagram; var toRemove = diagram.widget._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.widget._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) { if (e.userTriggered) { e.sender.element.trigger("focus"); that._cancelClick(e); } }); this._attachButtonEvents(); }, _renderTemplate: function() { var template = this.options.template; if (typeof template === "string") { template = kendo.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\">"; 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 = this._cancelClick.bind(this); this.window.element.on(CLICK + NS, "button.k-diagram-cancel", this._cancelClickHandler); this._updateClickHandler = this._updateClick.bind(this); this.window.element.on(CLICK + NS, "button.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", this.destroy.bind(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 cloneDataItem(dataItem) { var result = dataItem; if (dataItem instanceof kendo.data.Model) { result = dataItem.toJSON(); result[dataItem.idField] = dataItem._defaultId; } return result; } function createModel(dataSource, model) { if (dataSource.reader.model) { return new dataSource.reader.model(model); } return new kendo.data.ObservableObject(model); } dataviz.ui.plugin(Diagram$1); deepExtend(diagram, { Shape, Connection, Connector, DiagramToolBar, QuadNode, QuadRoot, ShapesQuadTree, PopupEditor }); })(window.kendo.jQuery); //#endregion //#region ../src/kendo.dataviz.diagram.js const __meta__ = { id: "dataviz.diagram", name: "Diagram", category: "dataviz", description: "The Kendo DataViz Diagram ", depends: [ "data", "userevents", "mobile.scroller", "draganddrop", "drawing", "dataviz.core", "dataviz.themes", "toolbar" ], features: [{ id: "dataviz.diagram-pdf-export", name: "PDF export", description: "Export Diagram as PDF", depends: ["pdf"] }, { id: "dataviz.diagram-editing", name: "Editing", description: "Support for model editing", depends: [ "editable", "window", "dropdownlist" ] }] }; var kendo_dataviz_diagram_default = kendo; //#endregion export { kendo_dataviz_diagram_default as n, __meta__ as t };