blob: bfe6c582dd1ad43eef128294a053939a3034c361 [file] [log] [blame]
Matteo Scandolo8cf33a32017-11-14 15:52:29 -08001/*
2 * Copyright 2017-present Open Networking Foundation
3
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7
8 * http://www.apache.org/licenses/LICENSE-2.0
9
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17
18import * as _ from 'lodash';
19import {IXosResourceService} from '../../datasources/rest/model.rest';
20import {IXosSgNode} from '../interfaces';
Matteo Scandolo35fdf242017-11-30 12:29:45 -080021import {IXosConfirm} from '../../core/confirm/confirm.service';
Matteo Scandolo8cf33a32017-11-14 15:52:29 -080022
23export interface IXosNodePositioner {
24 positionNodes(svg: {width: number, height: number}, nodes: any[]): ng.IPromise<IXosSgNode[]>;
25}
26
27export class XosNodePositioner implements IXosNodePositioner {
28 static $inject = [
29 '$log',
30 '$q',
Matteo Scandolo35fdf242017-11-30 12:29:45 -080031 'ModelRest',
32 'XosConfirm'
Matteo Scandolo8cf33a32017-11-14 15:52:29 -080033 ];
34
35 constructor (
36 private $log: ng.ILogService,
37 private $q: ng.IQService,
38 private ModelRest: IXosResourceService,
Matteo Scandolo35fdf242017-11-30 12:29:45 -080039 private XosConfirm: IXosConfirm
Matteo Scandolo8cf33a32017-11-14 15:52:29 -080040 ) {
41 this.$log.info('[XosNodePositioner] Setup');
42 }
43
Matteo Scandolo35fdf242017-11-30 12:29:45 -080044 public positionNodes(svg: {width: number, height: number}, nodes: IXosSgNode[]): ng.IPromise<IXosSgNode[]> {
Matteo Scandolo8cf33a32017-11-14 15:52:29 -080045
Matteo Scandolo8cf33a32017-11-14 15:52:29 -080046 const d = this.$q.defer();
47
48 this.getConstraints()
49 .then(constraints => {
50 const hStep = this.getHorizontalStep(svg.width, constraints);
Matteo Scandolo35fdf242017-11-30 12:29:45 -080051 const positionConstraints = _.reduce(constraints, (all: any, horizontalConstraint: string | string[], i: number) => {
Matteo Scandolo8cf33a32017-11-14 15:52:29 -080052 // NOTE it's a single element, leave it in the middle
Matteo Scandolo35fdf242017-11-30 12:29:45 -080053 if (angular.isString(horizontalConstraint)) {
54 all[horizontalConstraint] = {
55 x: (i + 1) * hStep,
56 y: svg.height / 2,
57 fixed: true
58 };
Matteo Scandolo8cf33a32017-11-14 15:52:29 -080059 }
60 else {
Matteo Scandolo35fdf242017-11-30 12:29:45 -080061 const verticalConstraints = horizontalConstraint;
Matteo Scandolo8cf33a32017-11-14 15:52:29 -080062 const vStep = this.getVerticalStep(svg.height, verticalConstraints);
Matteo Scandolo35fdf242017-11-30 12:29:45 -080063 _.forEach(verticalConstraints, (verticalConstraint: string, v: number) => {
64 if (angular.isString(verticalConstraint)) {
65 all[verticalConstraint] = {
66 x: (i + 1) * hStep,
67 y: (v + 1) * vStep,
68 fixed: true
69 };
Matteo Scandolo8cf33a32017-11-14 15:52:29 -080070 }
71 });
72 }
73 return all;
74 }, {});
75
Matteo Scandolo865b11c2018-02-14 16:57:44 -080076 // find the nodes that don't have a position defined and put them at the bottom
77 const allServiceNodes = _.reduce(nodes, (all: string[], n: IXosSgNode) => {
Matteo Scandolo35fdf242017-11-30 12:29:45 -080078 if (n.type === 'service') {
79 all.push(n.data.name);
80 }
81 return all;
82 }, []);
83 const positionedNodes = Object.keys(positionConstraints);
Matteo Scandolo865b11c2018-02-14 16:57:44 -080084 const unpositionedNodes = _.difference(allServiceNodes, positionedNodes);
Matteo Scandolo35fdf242017-11-30 12:29:45 -080085
86 _.forEach(unpositionedNodes, (node: string, i: number) => {
87 const hStep = this.getHorizontalStep(svg.width, unpositionedNodes);
88 positionConstraints[node] = {
89 x: (i + 1) * hStep,
90 y: svg.height - 50,
91 fixed: true
92 };
93 });
94
Matteo Scandolo8cf33a32017-11-14 15:52:29 -080095 d.resolve(_.map(nodes, n => {
96 return angular.merge(n, positionConstraints[n.data.name]);
97 }));
98 })
99 .catch(e => {
100 this.$log.error(`[XosNodePositioner] Error retrieving constraints`, e);
101 });
102
103 return d.promise;
104 }
105
106 private getConstraints(): ng.IPromise<any[]> {
107 const d = this.$q.defer();
108 this.ModelRest.getResource('/core/servicegraphconstraints').query().$promise
109 .then(res => {
110 d.resolve(JSON.parse(res[0].constraints));
111 })
112 .catch(e => {
Matteo Scandolo35fdf242017-11-30 12:29:45 -0800113 this.XosConfirm.open({
114 header: 'Error in graph constraints config',
115 text: `
116 There was an error in the settings you provided as graph constraints.
117 Please check the declaration of the <code>"Graph Constraints"</code> model. <br/>
118 The error was: <br/><br/>
119 <code>${e}</code>
120 <br/><br/>
121 Please fix it to see the graph.`,
122 actions: []
123 });
Matteo Scandolo8cf33a32017-11-14 15:52:29 -0800124 d.reject(e);
125 });
126 return d.promise;
127 }
128
129 private getHorizontalStep(svgWidth: number, constraints: any[]) {
130 return svgWidth / (constraints.length + 1);
131 }
132
133 private getVerticalStep(svgHeight: number, verticalConstraints: string[]) {
134 // NOTE verticalConstraints represent the vertical part (the nested array)
135 return svgHeight / (verticalConstraints.length + 1);
136 }
137}