b70c921947fc8491affc115d463c656b61f20843
[osm/UI.git] / skyquake / plugins / composer / src / src / libraries / graph / DescriptorGraph.js
1
2 /*
3 *
4 * Copyright 2016 RIFT.IO Inc
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *
18 */
19 /**
20 * Created by onvelocity on 8/24/15.
21 */
22 'use strict';
23
24 import _ from 'lodash'
25 import d3 from 'd3'
26 import math from './math'
27 import ClassNames from 'classnames'
28 import ColorGroups from '../ColorGroups'
29 import DescriptorModel from './../model/DescriptorModel'
30 import DescriptorModelFactory from './../model/DescriptorModelFactory'
31 import DescriptorGraphSelection from './DescriptorGraphSelection'
32 import DescriptorGraphEdgeBuilder from './DescriptorGraphPathBuilder'
33 import CatalogItemsActions from '../../actions/CatalogItemsActions'
34 import DescriptorGraphGrid from './DescriptorGraphGrid'
35 import SelectionManager from './../SelectionManager'
36 import GraphConnectionPointNumber from './GraphConnectionPointNumber'
37 import RelationsAndNetworksLayout from './layouts/RelationsAndNetworksLayout'
38
39 const defaults = {
40 width: 1000,
41 height: 500,
42 padding: 10,
43 snapTo: 15,
44 zoom: 100,
45 connectionPointSize: 135
46 };
47
48 export default class DescriptorGraph {
49
50 constructor(element, props) {
51
52 this.element = element;
53 this.props = Object.assign({}, props, defaults);
54 this.layouts = [RelationsAndNetworksLayout];
55 this.containers = [];
56 this.showMoreInfo = false;
57 this.scale = 1;
58
59 if (!element) {
60 throw new ReferenceError('An HTML DOM element is required to render DescriptorGraph.');
61 }
62
63 this.svg = d3.select(element).append('svg')
64 .attr('class', 'DescriptorGraph')
65 .attr('width', this.props.width)
66 .attr('height', this.props.height)
67 .attr('data-offset-parent', true);
68
69 this.g = this.svg.append('g')
70 .attr('class', 'viewport');
71
72 // set the scale of everything
73 this.zoom(this.props.zoom || defaults.zoom);
74
75 this.defs = this.svg.append('defs');
76 this.grid = this.g.append('g').classed('grid', true);
77 this.paths = this.g.append('g').classed('paths', true);
78 this.connectorsGroup = this.g.append('g').classed('connectors', true);
79 this.containersGroup = this.g.append('g').classed('containers', true);
80 this.cpNumbers = this.g.append('g').classed('connection-point-numbers', true);
81 this.forwardingGraphPaths = this.g.append('g').classed('forwarding-graph-paths', true);
82 this.selectionOutlineGroup = this.g.append('g').attr('data-outline-indicator', true);
83
84 this.defs.append('marker')
85 .attr({
86 id: 'relation-marker-end',
87 'markerWidth': 30,
88 'markerHeight': 30,
89 'orient': '0',
90 //markerUnits: 'userSpaceOnUse'
91 viewBox: '-15 -15 30 30'
92 })
93 .append('path')
94 .attr({
95 d: d3.svg.symbol().type('circle'),
96 'class': 'relation-marker-end'
97 });
98
99 this.update();
100
101 }
102
103 zoom(zoom) {
104 const scale = zoom / 100;
105 if (this.scale !== scale) {
106 this.scale = scale;
107 const transform = 'scale(' + this.scale + ')';
108 requestAnimationFrame(() => {
109 this.g.attr('transform', transform);
110 });
111 }
112 }
113
114 get containerPositionMap() {
115 if (this.containers[0].uiState.containerPositionMap) {
116 return this.containers[0].uiState.containerPositionMap;
117 } else {
118 return this.containers[0].uiState.containerPositionMap = {};
119 }
120 }
121
122 lookupSavedContainerPosition(container) {
123 return this.containerPositionMap[container.key];
124 }
125
126 saveContainerPosition(container) {
127 this.containerPositionMap[container.key] = container.position.value();
128 }
129
130 update() {
131
132 const graph = this;
133
134 const filterContainers = d => (graph.showMoreInfo ? true : d.type !== 'vdu');
135 const containers = this.containers.filter(filterContainers);
136 const layouts = graph.layouts.map(layoutFactory => layoutFactory.bind(this)());
137
138 function runLayout(i) {
139 const layout = layouts[i];
140 if (layout) {
141 layout.addContainers(containers);
142 layout.render(graph, runLayout.bind(null, i + 1));
143 }
144 }
145 runLayout(0);
146
147 const selection = new DescriptorGraphSelection(graph);
148 selection.addContainers(containers);
149 selection.render();
150
151 const edgeBuilder = new DescriptorGraphEdgeBuilder(graph);
152 edgeBuilder.addContainers(containers);
153 edgeBuilder.render();
154
155 const grid = new DescriptorGraphGrid(graph, {size: defaults.snapTo, padding: defaults.padding});
156 grid.render();
157
158 }
159
160 destroy() {
161 if (this.svg) {
162 this.svg.remove();
163 delete this.svg;
164 }
165 }
166
167 }