2 * Created by onvelocity on 2/11/16.
7 import ColorGroups
from '../ColorGroups'
8 import PathBuilder
from '../graph/PathBuilder'
9 import DescriptorModelFactory
from '../model/DescriptorModelFactory'
10 import DescriptorGraphSelection
from './DescriptorGraphSelection'
11 import CatalogItemsActions
from '../../actions/CatalogItemsActions'
12 import HighlightRecordServicePaths
from './HighlightRecordServicePaths'
13 import ComposerAppActions
from '../../actions/ComposerAppActions'
15 import '../../styles/GraphDescriptorModel.scss'
19 'constituent-vnfd': 'vnf',
26 export default class GraphDescriptorModel
{
28 constructor(graph
, classType
, props
= {}) {
31 this.classType
= classType
;
33 this._dragHandler
= () => {};
35 throw TypeError('Expect class type to be provided. Did you forget to pass in a class type, for example, DescriptorModelFactory.VirtualNetworkFunction?');
37 const defaults
= {type
: classType
.type
, className
: classType
.className
, selector
: [classType
.className
, classType
.type
, 'descriptor']};
38 this.props
= Object
.assign(this.props
, defaults
, {descriptorBorderRadius
: 20, descriptorWidth
: 250, descriptorHeight
: 55}, props
);
39 GraphDescriptorModel
.buildRef(classType
.type
, this.graph
.defs
);
42 addContainers(containers
) {
43 this.containers
= containers
.filter(d
=> d
instanceof this.classType
);
47 return this._dragHandler
;
50 set dragHandler(drag
) {
51 this._dragHandler
= drag
;
56 const g
= this.graph
.containersGroup
;
58 const descriptor
= g
.selectAll('.' + this.props
.selector
.join('.')).data(this.containers
, DescriptorModelFactory
.containerIdentity
);
60 const path
= new PathBuilder();
62 const descriptorPath
= PathBuilder
.descriptorPath(this.props
.descriptorBorderRadius
, this.props
.descriptorHeight
, this.props
.descriptorWidth
).toString();
65 const box
= descriptor
.enter().append('g')
67 'data-uid': d
=> d
.uid
,
68 'data-key': d
=> d
.key
,
70 return this.props
.selector
.join(' ');
72 }).on('cut', (container
) => {
76 if (container
&& container
.remove
) {
77 success
= container
.remove();
81 CatalogItemsActions
.catalogItemDescriptorChanged(container
.getRoot());
83 d3
.event
.preventDefault();
86 d3
.event
.stopPropagation();
88 }).call(this.dragHandler
);
92 class: d
=> d
.type
+ '-descriptor-model-background-layer background-layer',
94 fill
: ColorGroups
.common
.background
,
95 stroke
: ColorGroups
.common
.background
,
101 class: d
=> d
.type
+ '-descriptor-model-background background',
103 fill
: d
=> `url(#${d.type}-descriptor-model-badge-fill)`,
104 stroke
: 'transparent',
105 'stroke-width': '2px'
110 class: d
=> d
.type
+ '-descriptor-model-border border',
113 stroke
: d
=> ColorGroups
.getColorPairForType(d
.type
).secondary
,
115 }).style({opacity
: 0.75});
117 box
.append('path').attr({
118 class: d
=> d
.type
+ '-icon icon',
120 transform
: d
=> `translate(${d.icon.translate ? d.icon.translate : '-4, 2'}) rotate(0) scale(${24 / d.icon.width}, ${24 / d.icon.width})`,
127 class:d
=> d
.type
+ '-type type',
130 'text-anchor': 'middle',
131 'text-transform': 'uppercase',
136 }).text(d
=> iconTitles
[d
.type
] || d
.type
).style({opacity
: 1});
140 class: d
=> d
.type
+ '-title title',
143 'text-anchor': 'middle',
146 const widthOffset
= (d
.position
.width
/ 2) + 20;
147 return left
+ widthOffset
;
151 const height
= d
.position
.height
;
152 const heightOffset
= height
/ 2;
153 const textHeightOffset
= 12 / 2;
154 return top
+ heightOffset
+ textHeightOffset
;
158 box
.each(function (d
) {
159 if (DescriptorModelFactory
.isForwardingGraph(d
)) {
160 const box
= d3
.select(this);
162 d
.rsp
.forEach((rsp
, i
) => {
163 const colorLegend
= box
.append('g').attr({
164 class:d
=> d
.type
+ '-rsp-color-legend color-legend',
166 const widthOffset
= d
.position
.width
- 20 - (i
* 26);
167 const heightOffset
= d
.position
.height
- 10;
168 return `translate(${widthOffset}, ${heightOffset})`;
171 colorLegend
.append('ellipse').classed('colors', true).attr({
174 fill
: d
=> d
.colors
&& d
.colors
.primary
,
175 stroke
: d
=> d
.colors
&& d
.colors
.secondary
176 }).on('mouseenter', function (d
) {
177 HighlightRecordServicePaths
.highlightPaths(rsp
);
178 }).on('mouseout', function () {
179 HighlightRecordServicePaths
.removeHighlighting();
180 }).on('mouseleave', function () {
181 HighlightRecordServicePaths
.removeHighlighting();
182 }).on('click', function () {
183 d3
.event
.preventDefault();
184 ComposerAppActions
.selectModel(rsp
);
195 const x
= d
.position
.left
;
196 const y
= d
.position
.top
;
197 return 'translate(' + x
+ ', ' + y
+ ')';
201 descriptor
.select('text.title')
212 static buildRef(type
, defs
) {
213 if (defs
.selectAll('#' + type
+ '-descriptor-model-badge-fill')[0].length
=== 0) {
214 var vld
= defs
.append('pattern').attr({
215 id
: type
+ '-descriptor-model-badge-fill',
216 //patternUnits: 'userSpaceOnUse',
217 patternContentUnits
: 'objectBoundingBox',
221 preserveAspectRatio
: 'none'
223 vld
.append('rect').attr({
226 fill
: 'white'//ensure transparent layers keep their color
228 vld
.append('rect').attr({
231 fill
: ColorGroups
.getColorPairForType(type
).secondary
232 }).style({opacity
: 1});
233 vld
.append('rect').attr({
238 fill
: ColorGroups
.common
.background