(function() { 'use strict'; function Modelfactory($q, Modelvalidation) { return function innerModelfactory(model, selectedObjects, dropNode, createEdge, edgeAddedCallback, nodeRemovedCallback, edgeRemovedCallback) { Modelvalidation.validateModel(model); var modelservice = { selectedObjects: selectedObjects }; modelservice.connectorsHtmlElements = {}; modelservice.nodesHtmlElements = {}; modelservice.canvasHtmlElement = null; modelservice.dragImage = null; modelservice.svgHtmlElement = null; modelservice.dropNode = dropNode || angular.noop; modelservice.createEdge = createEdge || function() { return $q.when({ label: "label" })}; modelservice.edgeAddedCallback = edgeAddedCallback || angular.noop; modelservice.nodeRemovedCallback = nodeRemovedCallback || angular.noop; modelservice.edgeRemovedCallback = edgeRemovedCallback || angular.noop; function selectObject(object) { if (modelservice.isEditable()) { if (modelservice.selectedObjects.indexOf(object) === -1) { modelservice.selectedObjects.push(object); } } } function deselectObject(object) { if (modelservice.isEditable()) { var index = modelservice.selectedObjects.indexOf(object); if (index === -1) { throw new Error('Tried to deselect an unselected object'); } modelservice.selectedObjects.splice(index, 1); } } function toggleSelectedObject(object) { if (isSelectedObject(object)) { deselectObject(object); } else { selectObject(object); } } function isSelectedObject(object) { return modelservice.selectedObjects.indexOf(object) !== -1; } function isEditObject(object) { return modelservice.selectedObjects.length === 1 && modelservice.selectedObjects.indexOf(object) !== -1; } modelservice.connectors = { getConnector: function(connectorId) { for(var i=0; i -1) { return node; } } return null; } }; modelservice.edges = { sourceCoord: function(edge) { return modelservice.connectors.getCenteredCoord(edge.source, edge.source); }, destCoord: function(edge) { return modelservice.connectors.getCenteredCoord(edge.destination); }, select: selectObject, deselect: deselectObject, toggleSelected: toggleSelectedObject, isSelected: isSelectedObject, isEdit: isEditObject, delete: function (edge) { var index = model.edges.indexOf(edge); if (index === -1) { throw new Error('Tried to delete not existing edge') } if (this.isSelected(edge)) { this.deselect(edge) } model.edges.splice(index, 1); modelservice.edgeRemovedCallback(edge); }, getSelectedEdges: function() { return model.edges.filter(function(edge) { return modelservice.edges.isSelected(edge) }); }, handleEdgeMouseClick: function(edge, ctrlKey) { if (ctrlKey) { modelservice.edges.toggleSelected(edge); } else { modelservice.deselectAll(); modelservice.edges.select(edge); } }, putEdge: function(edge) { model.edges.push(edge); }, _addEdge: function(event, sourceConnector, destConnector, label) { Modelvalidation.validateConnector(sourceConnector); Modelvalidation.validateConnector(destConnector); var edge = {}; edge.source = sourceConnector.id; edge.destination = destConnector.id; edge.label = label; Modelvalidation.validateEdges(model.edges.concat([edge]), model.nodes); modelservice.createEdge(event, edge).then( function (edge) { model.edges.push(edge); modelservice.edgeAddedCallback(edge); } ); } }; function inRectBox(x, y, rectBox) { return x >= rectBox.left && x <= rectBox.right && y >= rectBox.top && y <= rectBox.bottom; } modelservice.getItemInfoAtPoint = function(x,y) { return { node: modelservice.getNodeAtPoint(x,y), edge: modelservice.getEdgeAtPoint(x,y) }; }; modelservice.getNodeAtPoint = function(x,y) { for (var i=0;i= nodeElementBox.left && x <= nodeElementBox.right && y >= nodeElementBox.top && y <= nodeElementBox.bottom) { return node; } } return null; }; modelservice.getEdgeAtPoint = function(x,y) { var element = document.elementFromPoint(x, y); var id = element.id; var edgeIndex = -1; if (id) { if (id.startsWith("fc-edge-path-")) { edgeIndex = Number(id.substring("fc-edge-path-".length)); } else if (id.startsWith("fc-edge-label-")) { edgeIndex = Number(id.substring("fc-edge-label-".length)); } } if (edgeIndex > -1) { return model.edges[edgeIndex]; } return null; }; modelservice.selectAllInRect = function(rectBox) { angular.forEach(model.nodes, function(value) { var element = modelservice.nodes.getHtmlElement(value.id); var nodeElementBox = element.getBoundingClientRect(); if (!value.readonly) { var x = nodeElementBox.left + nodeElementBox.width/2; var y = nodeElementBox.top + nodeElementBox.height/2; if (inRectBox(x, y, rectBox)) { modelservice.nodes.select(value); } else { if (modelservice.nodes.isSelected(value)) { modelservice.nodes.deselect(value); } } } }); angular.forEach(model.edges, function(value) { var start = modelservice.edges.sourceCoord(value); var end = modelservice.edges.destCoord(value); var x = (start.x + end.x)/2 + rectBox.parentOffset.left; var y = (start.y + end.y)/2 + rectBox.parentOffset.top; if (inRectBox(x, y, rectBox)) { modelservice.edges.select(value); } else { if (modelservice.edges.isSelected(value)) { modelservice.edges.deselect(value); } } }); }; modelservice.selectAll = function() { angular.forEach(model.nodes, function(value) { if (!value.readonly) { modelservice.nodes.select(value); } }); angular.forEach(model.edges, function(value) { modelservice.edges.select(value); }); }; modelservice.deselectAll = function() { modelservice.selectedObjects.splice(0, modelservice.selectedObjects.length); }; modelservice.deleteSelected = function() { var edgesToDelete = modelservice.edges.getSelectedEdges(); angular.forEach(edgesToDelete, function(edge) { modelservice.edges.delete(edge); }); var nodesToDelete = modelservice.nodes.getSelectedNodes(); angular.forEach(nodesToDelete, function(node) { modelservice.nodes.delete(node); }); }; modelservice.setDropTargetId = function(dropTargetId) { modelservice.dropTargetId = dropTargetId; }; modelservice.getDropTargetId = function() { return modelservice.dropTargetId; }; modelservice.isDropSource = function() { return modelservice.dropTargetId; }; modelservice.isEditable = function() { return !modelservice.dropTargetId; }; modelservice.setCanvasHtmlElement = function(element) { modelservice.canvasHtmlElement = element; }; modelservice.getCanvasHtmlElement = function() { return modelservice.canvasHtmlElement; }; modelservice.getDragImage = function() { if (!modelservice.dragImage) { modelservice.dragImage = new Image(); modelservice.dragImage.src = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"; modelservice.dragImage.style.visibility = 'hidden'; } return modelservice.dragImage; }; modelservice.setSvgHtmlElement = function(element) { modelservice.svgHtmlElement = element; }; modelservice.getSvgHtmlElement = function() { return modelservice.svgHtmlElement; }; modelservice.registerCallbacks = function (edgeAddedCallback, nodeRemovedCallback, edgeRemovedCallback) { modelservice.edgeAddedCallback = edgeAddedCallback; modelservice.nodeRemovedCallback = nodeRemovedCallback; modelservice.edgeRemovedCallback = edgeRemovedCallback; }; return modelservice; } } angular.module('flowchart') .service('Modelfactory', Modelfactory); })();