Rift.IO OSM R1 Initial Submission
[osm/UI.git] / skyquake / plugins / composer / src / src / libraries / graph / GraphDescriptorModel.js
diff --git a/skyquake/plugins/composer/src/src/libraries/graph/GraphDescriptorModel.js b/skyquake/plugins/composer/src/src/libraries/graph/GraphDescriptorModel.js
new file mode 100644 (file)
index 0000000..cc323af
--- /dev/null
@@ -0,0 +1,243 @@
+/**
+ * Created by onvelocity on 2/11/16.
+ */
+'use strict';
+
+import d3 from 'd3'
+import ColorGroups from '../ColorGroups'
+import PathBuilder from '../graph/PathBuilder'
+import DescriptorModelFactory from '../model/DescriptorModelFactory'
+import DescriptorGraphSelection from './DescriptorGraphSelection'
+import CatalogItemsActions from '../../actions/CatalogItemsActions'
+import HighlightRecordServicePaths from './HighlightRecordServicePaths'
+import ComposerAppActions from '../../actions/ComposerAppActions'
+
+import '../../styles/GraphDescriptorModel.scss'
+
+const iconTitles = {
+       'vnffgd': 'fg',
+       'constituent-vnfd': 'vnf',
+       'nsd': 'ns',
+       'vnfd': 'vnf',
+       'vld': 'vl',
+       'internal-vld': 'vl'
+};
+
+export default class GraphDescriptorModel {
+
+       constructor(graph, classType, props = {}) {
+               this.props = {};
+               this.graph = graph;
+               this.classType = classType;
+               this.containers = [];
+               this._dragHandler = () => {};
+               if (!classType) {
+                       throw TypeError('Expect class type to be provided. Did you forget to pass in a class type, for example, DescriptorModelFactory.VirtualNetworkFunction?');
+               }
+               const defaults = {type: classType.type, className: classType.className, selector: [classType.className, classType.type, 'descriptor']};
+               this.props = Object.assign(this.props, defaults, {descriptorBorderRadius: 20, descriptorWidth: 250, descriptorHeight: 55}, props);
+               GraphDescriptorModel.buildRef(classType.type, this.graph.defs);
+       }
+
+       addContainers(containers) {
+               this.containers = containers.filter(d => d instanceof this.classType);
+       }
+
+       get dragHandler() {
+               return this._dragHandler;
+       }
+
+       set dragHandler(drag) {
+               this._dragHandler = drag;
+       }
+
+       render() {
+
+               const g = this.graph.containersGroup;
+
+               const descriptor = g.selectAll('.' + this.props.selector.join('.')).data(this.containers, DescriptorModelFactory.containerIdentity);
+
+               const path = new PathBuilder();
+
+               const descriptorPath = PathBuilder.descriptorPath(this.props.descriptorBorderRadius, this.props.descriptorHeight, this.props.descriptorWidth).toString();
+
+               // ENTER
+               const box = descriptor.enter().append('g')
+                       .attr({
+                               'data-uid': d => d.uid,
+                               'data-key': d => d.key,
+                               'class': d => {
+                                       return this.props.selector.join(' ');
+                               }
+                       }).on('cut', (container) => {
+
+                               let success = false;
+
+                               if (container && container.remove) {
+                                       success = container.remove();
+                               }
+
+                               if (success) {
+                                       CatalogItemsActions.catalogItemDescriptorChanged(container.getRoot());
+                               } else {
+                                       d3.event.preventDefault();
+                               }
+
+                               d3.event.stopPropagation();
+
+                       }).call(this.dragHandler);
+
+               box.append('path')
+                       .attr({
+                               class: d => d.type + '-descriptor-model-background-layer background-layer',
+                               d: descriptorPath,
+                               fill: ColorGroups.common.background,
+                               stroke: ColorGroups.common.background,
+                               'stroke-width': '2px'
+                       });
+
+               box.append('path')
+                       .attr({
+                               class: d => d.type + '-descriptor-model-background background',
+                               d: descriptorPath,
+                               fill: d => `url(#${d.type}-descriptor-model-badge-fill)`,
+                               stroke: 'transparent',
+                               'stroke-width': '2px'
+                       });
+
+               box.append('path')
+                       .attr({
+                               class: d => d.type + '-descriptor-model-border border',
+                               d: descriptorPath,
+                               fill: 'transparent',
+                               stroke: d => ColorGroups.getColorPairForType(d.type).secondary,
+                               'stroke-width': 1.25
+                       }).style({opacity: 0.75});
+
+               box.append('path').attr({
+                       class: d => d.type + '-icon icon',
+                       d: d => d.icon.d,
+                       transform: d => `translate(${d.icon.translate ? d.icon.translate : '-4, 2'}) rotate(0) scale(${24 / d.icon.width}, ${24 / d.icon.width})`,
+                       fill: 'white',
+                       stroke: 'white'
+               });
+
+               box.append('text')
+                       .attr({
+                               class:d => d.type + '-type type',
+                               'font-weight': 100,
+                               'font-size': '12px',
+                               'text-anchor': 'middle',
+                               'text-transform': 'uppercase',
+                               fill: 'white',
+                               stroke: 'white',
+                               x: 13,
+                               y: 49
+                       }).text(d => iconTitles[d.type] || d.type).style({opacity: 1});
+
+               box.append('text')
+                       .attr({
+                               class: d => d.type + '-title title',
+                               'font-weight': 100,
+                               'font-size': '12px',
+                               'text-anchor': 'middle',
+                               x: (d) => {
+                                       const left = 0;
+                                       const widthOffset = (d.position.width / 2) + 20;
+                                       return left + widthOffset;
+                               },
+                               y: (d) => {
+                                       const top = 0;
+                                       const height = d.position.height;
+                                       const heightOffset = height / 2;
+                                       const textHeightOffset = 12 / 2;
+                                       return top + heightOffset + textHeightOffset;
+                               }
+                       });
+
+               box.each(function (d) {
+                       if (DescriptorModelFactory.isForwardingGraph(d)) {
+                               const box = d3.select(this);
+
+                               d.rsp.forEach((rsp, i) => {
+                                       const colorLegend = box.append('g').attr({
+                                               class:d => d.type + '-rsp-color-legend color-legend',
+                                               transform: d => {
+                                                       const widthOffset = d.position.width - 20 - (i * 26);
+                                                       const heightOffset = d.position.height - 10;
+                                                       return `translate(${widthOffset}, ${heightOffset})`;
+                                               }
+                                       });
+                                       colorLegend.append('ellipse').classed('colors', true).attr({
+                                               rx: 12,
+                                               ry: 7.5,
+                                               fill: d => d.colors && d.colors.primary,
+                                               stroke: d => d.colors && d.colors.secondary
+                                       }).on('mouseenter', function (d) {
+                                               HighlightRecordServicePaths.highlightPaths(rsp);
+                                       }).on('mouseout', function () {
+                                               HighlightRecordServicePaths.removeHighlighting();
+                                       }).on('mouseleave', function () {
+                                               HighlightRecordServicePaths.removeHighlighting();
+                                       }).on('click', function () {
+                                               d3.event.preventDefault();
+                                               ComposerAppActions.selectModel(rsp);
+                                       });
+                               });
+
+                       }
+               });
+
+
+               // ENTER & UPDATE
+               descriptor.attr({
+                       transform: d => {
+                               const x = d.position.left;
+                               const y = d.position.top;
+                               return 'translate(' + x + ', ' + y + ')';
+                       }
+               });
+
+               descriptor.select('text.title')
+                       .text(d => {
+                               return d.title;
+                       });
+
+               // EXIT
+               descriptor.exit()
+                       .remove();
+
+       }
+
+       static buildRef(type, defs) {
+               if (defs.selectAll('#' + type + '-descriptor-model-badge-fill')[0].length === 0) {
+                       var vld = defs.append('pattern').attr({
+                               id: type + '-descriptor-model-badge-fill',
+                               //patternUnits: 'userSpaceOnUse',
+                               patternContentUnits: 'objectBoundingBox',
+                               width: 1,
+                               height: 1,
+                               viewBox: '0 0 1 1',
+                               preserveAspectRatio: 'none'
+                       });
+                       vld.append('rect').attr({
+                               width: 1,
+                               height: 1,
+                               fill: 'white'//ensure transparent layers keep their color
+                       });
+                       vld.append('rect').attr({
+                               width: 1,
+                               height: 1,
+                               fill: ColorGroups.getColorPairForType(type).secondary
+                       }).style({opacity: 1});
+                       vld.append('rect').attr({
+                               y: 0,
+                               x: 0.22,
+                               width: 1,
+                               height: 1,
+                               fill: ColorGroups.common.background
+                       });
+               }
+       }
+
+}