/* ** Views/Partial/LCA/BOM.cshtml is using this controller */ angular.module('CarbonFootprint') .controller('LifecycleFlowChartController', ['$scope', '$routeParams', 'Notification', function ($scope, $routeParams, Notification) { main(document.getElementById('graphContainer')); // Program starts here. Creates a sample graph in the // DOM node with the specified ID. This function is invoked // from the onLoad event handler of the document (see below). function main(container) { // Checks if browser is supported if (!mxClient.isBrowserSupported()) { // Displays an error message if the browser is // not supported. mxUtils.error('Browser is not supported!', 200, false); } else { //// Creates a wrapper editor around a new graph inside //// the given container using an XML config for the //// keyboard bindings //var config = mxUtils.load( // 'Scripts/mxgraph/editors/config/keyhandler-commons.xml'). // getDocumentElement(); //var editor = new mxEditor(config); //editor.setGraphContainer(container); //var graph = editor.graph; //var model = graph.getModel(); // Creates the graph inside the given container var graph = new mxGraph(container); var model = graph.getModel(); // Disables folding graph.isCellFoldable = function (cell, collapse) { return false; }; // Auto-resizes the container graph.border = 80; graph.getView().translate = new mxPoint(graph.border / 2, graph.border / 2); graph.setResizeContainer(true); graph.graphHandler.setRemoveCellsFromParent(false); // Changes the default vertex style in-place var style = graph.getStylesheet().getDefaultVertexStyle(); style[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_SWIMLANE; style[mxConstants.STYLE_VERTICAL_ALIGN] = 'middle'; style[mxConstants.STYLE_LABEL_BACKGROUNDCOLOR] = 'white'; style[mxConstants.STYLE_FONTSIZE] = 11; style[mxConstants.STYLE_STARTSIZE] = 22; style[mxConstants.STYLE_HORIZONTAL] = false; style[mxConstants.STYLE_FONTCOLOR] = 'black'; style[mxConstants.STYLE_STROKECOLOR] = 'black'; delete style[mxConstants.STYLE_FILLCOLOR]; style = mxUtils.clone(style); style[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_RECTANGLE; style[mxConstants.STYLE_FONTSIZE] = 10; style[mxConstants.STYLE_ROUNDED] = false; style[mxConstants.STYLE_HORIZONTAL] = true; style[mxConstants.STYLE_VERTICAL_ALIGN] = 'middle'; delete style[mxConstants.STYLE_STARTSIZE]; style[mxConstants.STYLE_LABEL_BACKGROUNDCOLOR] = 'none'; graph.getStylesheet().putCellStyle('process', style); style = mxUtils.clone(style); style[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_ELLIPSE; style[mxConstants.STYLE_PERIMETER] = mxPerimeter.EllipsePerimeter; delete style[mxConstants.STYLE_ROUNDED]; graph.getStylesheet().putCellStyle('state', style); style = mxUtils.clone(style); style[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_RHOMBUS; style[mxConstants.STYLE_PERIMETER] = mxPerimeter.RhombusPerimeter; style[mxConstants.STYLE_VERTICAL_ALIGN] = 'top'; style[mxConstants.STYLE_SPACING_TOP] = 40; style[mxConstants.STYLE_SPACING_RIGHT] = 64; graph.getStylesheet().putCellStyle('condition', style); style = mxUtils.clone(style); style[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_DOUBLE_ELLIPSE; style[mxConstants.STYLE_PERIMETER] = mxPerimeter.EllipsePerimeter; style[mxConstants.STYLE_SPACING_TOP] = 28; style[mxConstants.STYLE_FONTSIZE] = 14; style[mxConstants.STYLE_FONTSTYLE] = 1; delete style[mxConstants.STYLE_SPACING_RIGHT]; graph.getStylesheet().putCellStyle('end', style); style = graph.getStylesheet().getDefaultEdgeStyle(); style[mxConstants.STYLE_EDGE] = mxEdgeStyle.ElbowConnector; style[mxConstants.STYLE_ENDARROW] = mxConstants.ARROW_BLOCK; style[mxConstants.STYLE_ROUNDED] = true; style[mxConstants.STYLE_FONTCOLOR] = 'black'; style[mxConstants.STYLE_STROKECOLOR] = 'black'; style = mxUtils.clone(style); style[mxConstants.STYLE_DASHED] = true; style[mxConstants.STYLE_ENDARROW] = mxConstants.ARROW_OPEN; style[mxConstants.STYLE_STARTARROW] = mxConstants.ARROW_OVAL; graph.getStylesheet().putCellStyle('crossover', style); // Installs double click on middle control point and // changes style of edges between empty and this value graph.alternateEdgeStyle = 'elbow=vertical'; // Adds automatic layout and various switches if the // graph is enabled if (graph.isEnabled()) { // Allows new connections but no dangling edges graph.setConnectable(true); graph.setAllowDanglingEdges(false); // End-states are no valid sources var previousIsValidSource = graph.isValidSource; graph.isValidSource = function (cell) { if (previousIsValidSource.apply(this, arguments)) { var style = this.getModel().getStyle(cell); return style == null || !(style == 'end' || style.indexOf('end') == 0); } return false; }; // Start-states are no valid targets, we do not // perform a call to the superclass function because // this would call isValidSource // Note: All states are start states in // the example below, so we use the state // style below graph.isValidTarget = function (cell) { var style = this.getModel().getStyle(cell); return !this.getModel().isEdge(cell) && !this.isSwimlane(cell) && (style == null || !(style == 'state' || style.indexOf('state') == 0)); }; // Allows dropping cells into new lanes and // lanes into new pools, but disallows dropping // cells on edges to split edges graph.setDropEnabled(false); graph.setSplitEnabled(false); // Returns true for valid drop operations graph.isValidDropTarget = function (target, cells, evt) { if (this.isSplitEnabled() && this.isSplitTarget(target, cells, evt)) { return true; } var model = this.getModel(); var lane = false; var pool = false; var cell = false; // Checks if any lanes or pools are selected for (var i = 0; i < cells.length; i++) { var tmp = model.getParent(cells[i]); lane = lane || this.isPool(tmp); pool = pool || this.isPool(cells[i]); cell = cell || !(lane || pool); } return !pool && cell != lane && ((lane && this.isPool(target)) || (cell && this.isPool(model.getParent(target)))); }; // Adds new method for identifying a pool graph.isPool = function (cell) { var model = this.getModel(); var parent = model.getParent(cell); return parent != null && model.getParent(parent) == model.getRoot(); }; // Changes swimlane orientation while collapsed graph.model.getStyle = function (cell) { var style = mxGraphModel.prototype.getStyle.apply(this, arguments); if (graph.isCellCollapsed(cell)) { if (style != null) { style += ';'; } else { style = ''; } style += 'horizontal=1;align=left;spacingLeft=14;'; } return style; }; // Keeps widths on collapse/expand var foldingHandler = function (sender, evt) { var cells = evt.getProperty('cells'); for (var i = 0; i < cells.length; i++) { var geo = graph.model.getGeometry(cells[i]); if (geo.alternateBounds != null) { geo.width = geo.alternateBounds.width; } } }; graph.addListener(mxEvent.FOLD_CELLS, foldingHandler); } // Applies size changes to siblings and parents new mxSwimlaneManager(graph); // Creates a stack depending on the orientation of the swimlane var layout = new mxStackLayout(graph, false); // Makes sure all children fit into the parent swimlane layout.resizeParent = true; // Applies the size to children if parent size changes layout.fill = true; // Only update the size of swimlanes layout.isVertexIgnored = function (vertex) { return !graph.isSwimlane(vertex); } // Keeps the lanes and pools stacked var layoutMgr = new mxLayoutManager(graph); layoutMgr.getLayout = function (cell) { if (!model.isEdge(cell) && graph.getModel().getChildCount(cell) > 0 && (model.getParent(cell) == model.getRoot() || graph.isPool(cell))) { layout.fill = graph.isPool(cell); return layout; } return null; }; // Installs a handler for click events in the graph // that toggles the overlay for the respective cell graph.addListener(mxEvent.CLICK, function (sender, evt) { var cell = evt.getProperty('cell'); clickHandler(sender.selectionModel.cells[0].value); //mxUtils.alert('Click: ' + sender.selectionModel.cells[0].value); //evt.consume(); }); // Gets the default parent for inserting new cells. This // is normally the first child of the root (ie. layer 0). var parent = graph.getDefaultParent(); // Adds cells to the model in a single step model.beginUpdate(); try { var pool1 = graph.insertVertex(parent, null, '生命週期階段', 0, 0, 640, 0); pool1.setConnectable(false); var lane1a = graph.insertVertex(pool1, null, '原料取得', 0, 0, 640, 110); lane1a.setConnectable(false); var lane2a = graph.insertVertex(pool1, null, '上游運輸', 0, 0, 640, 110); lane1a.setConnectable(false); var lane3a = graph.insertVertex(pool1, null, '運作支援及服務', 0, 0, 640, 330); lane1a.setConnectable(false); var lane4a = graph.insertVertex(pool1, null, '下游運輸', 0, 0, 640, 110); lane1a.setConnectable(false); var lane5a = graph.insertVertex(pool1, null, '產品使用及廢棄', 0, 0, 640, 110); lane1a.setConnectable(false); var lane6a = graph.insertVertex(pool1, null, '廢棄物處裡', 0, 0, 640, 110); lane1a.setConnectable(false); var step11 = graph.insertVertex(lane1a, null, '半導\n體控\n制IC', 120, 15, 40, 80, 'process'); var step12 = graph.insertVertex(lane1a, null, '洗板\n水', 170, 15, 40, 80, 'process'); var step13 = graph.insertVertex(lane1a, null, '主變\n壓器', 220, 15, 40, 80, 'process'); var step14 = graph.insertVertex(lane1a, null, 'PCB', 270, 15, 40, 80, 'process'); var step15 = graph.insertVertex(lane1a, null, '一次\n側大\n電容', 320, 15, 40, 80, 'process'); var step16 = graph.insertVertex(lane1a, null, '線材', 370, 15, 40, 80, 'process'); var step17 = graph.insertVertex(lane1a, null, '外殼', 420, 15, 40, 80, 'process'); var step18 = graph.insertVertex(lane1a, null, '套袋', 470, 15, 40, 80, 'process'); var step19 = graph.insertVertex(lane1a, null, '能源\n生產\n(c4)', 560, 15, 40, 80, 'process'); var step311 = graph.insertVertex(lane3a, null, '上\n游\n租\n賃', 50, 5, 20, 190, 'process'); var step312 = graph.insertVertex(lane3a, null, '下\n游\n租\n賃', 50, 200, 20, 125, 'process'); var step320 = graph.insertVertex(lane3a, null, '', 110, 5, 420, 320, 'process'); var step321 = graph.insertVertex(step320, null, '產品開發', 70, 15, 280, 50, 'process'); var step322 = graph.insertVertex(step320, null, '製造過程', 70, 135, 280, 50, 'process'); var step323 = graph.insertVertex(step320, null, '其他支援流程', 70, 255, 280, 50, 'process'); var step331 = graph.insertVertex(lane3a, null, '能\n資\n源', 570, 5, 20, 140, 'process'); var step332 = graph.insertVertex(lane3a, null, '廢\n棄\n物', 570, 150, 20, 175, 'process'); var step5 = graph.insertVertex(lane5a, null, '產品使用階段\n及\n廢棄階段', 220, 15, 200, 80, 'process'); var step61 = graph.insertVertex(lane6a, null, '焚化', 250, 15, 40, 80, 'process'); var step62 = graph.insertVertex(lane6a, null, '回收', 300, 15, 40, 80, 'process'); var step63 = graph.insertVertex(lane6a, null, '掩埋', 350, 15, 40, 80, 'process'); var e = null; graph.insertEdge(parent, null, null, step11, step320); graph.insertEdge(parent, null, null, step12, step320); graph.insertEdge(parent, null, null, step13, step320); graph.insertEdge(parent, null, null, step14, step320); graph.insertEdge(parent, null, null, step15, step320); graph.insertEdge(parent, null, null, step16, step320); graph.insertEdge(parent, null, null, step17, step320); graph.insertEdge(parent, null, null, step18, step320); graph.insertEdge(parent, null, null, step19, step331); graph.insertEdge(step320, null, null, step321, step322); graph.insertEdge(step320, null, null, step323, step322); graph.insertEdge(lane3a, null, null, step311, step320); e = graph.insertEdge(lane3a, null, null, step331, step320); // 能资源 -> step320 e.geometry.points = [new mxPoint(step320.geometry.x + step320.geometry.width, step331.geometry.y + step311.geometry.height / 2)]; //e.getGeometry().points = [{ x: 80, y: 10 }]; graph.insertEdge(lane3a, null, null, step320, step332); graph.insertEdge(parent, null, null, step320, step5); graph.insertEdge(parent, null, null, step5, step61); graph.insertEdge(parent, null, null, step5, step62); graph.insertEdge(parent, null, null, step5, step63); } finally { // Updates the display model.endUpdate(); } } }; function clickHandler(value) { if (value == '生命週期階段') { $scope.changeSelectedTab('LifecycleAssmt'); } else if (value == '原料取得') { $scope.changeSelectedTab('MaterialC3Emission'); } else if (value == '上游運輸') { $scope.changeSelectedTab('ItemPurchase'); } else if (value == '運作支援及服務') { $scope.changeSelectedTab('WaterUsage'); } else if (value == '下游運輸') { $scope.changeSelectedTab('ItemDelivery'); } else if (value == '產品使用及廢棄') { $scope.changeSelectedTab('PowerConsumption'); } else if (value == '廢棄物處裡') { $scope.changeSelectedTab('WasteMaterial'); } } }]);