update from RIFT as of 696b75d2fe9fb046261b08c616f1bcf6c0b54a9b third try
[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 d3 from 'd3'
25 import math from './math'
26 import ClassNames from 'classnames'
27 import ColorGroups from '../ColorGroups'
28 import DescriptorModel from './../model/DescriptorModel'
29 import DescriptorModelFactory from './../model/DescriptorModelFactory'
30 import DescriptorGraphSelection from './DescriptorGraphSelection'
31 import DescriptorGraphEdgeBuilder from './DescriptorGraphPathBuilder'
32 import CatalogItemsActions from '../../actions/CatalogItemsActions'
33 import DescriptorGraphGrid from './DescriptorGraphGrid'
34 import SelectionManager from './../SelectionManager'
35 import GraphConnectionPointNumber from './GraphConnectionPointNumber'
36 import RelationsAndNetworksLayout from './layouts/RelationsAndNetworksLayout'
37
38 const defaults = {
39 width: 1000,
40 height: 500,
41 padding: 10,
42 snapTo: 15,
43 zoom: 100,
44 connectionPointSize: 135
45 };
46
47 export default class DescriptorGraph {
48
49 constructor(element, props) {
50
51 this.element = element;
52 this.props = Object.assign({}, props, defaults);
53 this.layouts = [RelationsAndNetworksLayout];
54 this.containers = [];
55 this.showMoreInfo = false;
56 this.scale = 1;
57
58 if (!element) {
59 throw new ReferenceError('An HTML DOM element is required to render DescriptorGraph.');
60 }
61
62 this.svg = d3.select(element).append('svg')
63 .attr('class', 'DescriptorGraph')
64 .attr('width', this.props.width)
65 .attr('height', this.props.height)
66 .attr('data-offset-parent', true);
67
68 this.g = this.svg.append('g')
69 .attr('class', 'viewport');
70
71 // set the scale of everything
72 this.zoom(this.props.zoom || defaults.zoom);
73
74 this.defs = this.svg.append('defs');
75 this.grid = this.g.append('g').classed('grid', true);
76 this.paths = this.g.append('g').classed('paths', true);
77 this.connectorsGroup = this.g.append('g').classed('connectors', true);
78 this.containersGroup = this.g.append('g').classed('containers', true);
79 this.cpNumbers = this.g.append('g').classed('connection-point-numbers', true);
80 this.forwardingGraphPaths = this.g.append('g').classed('forwarding-graph-paths', true);
81 this.selectionOutlineGroup = this.g.append('g').attr('data-outline-indicator', true);
82
83 this.defs.append('marker')
84 .attr({
85 id: 'relation-marker-end',
86 'markerWidth': 30,
87 'markerHeight': 30,
88 'orient': '0',
89 //markerUnits: 'userSpaceOnUse'
90 viewBox: '-15 -15 30 30'
91 })
92 .append('path')
93 .attr({
94 d: d3.svg.symbol().type('circle'),
95 'class': 'relation-marker-end'
96 });
97
98 this.update();
99
100 }
101
102 zoom(zoom) {
103 const scale = zoom / 100;
104 if (this.scale !== scale) {
105 this.scale = scale;
106 const transform = 'scale(' + this.scale + ')';
107 requestAnimationFrame(() => {
108 this.g.attr('transform', transform);
109 });
110 }
111 }
112
113 get containerPositionMap() {
114 if (this.containers[0].uiState.containerPositionMap) {
115 return this.containers[0].uiState.containerPositionMap;
116 } else {
117 return this.containers[0].uiState.containerPositionMap = {};
118 }
119 }
120
121 lookupSavedContainerPosition(container) {
122 return this.containerPositionMap[container.key];
123 }
124
125 saveContainerPosition(container) {
126 this.containerPositionMap[container.key] = container.position.value();
127 }
128
129 update() {
130
131 const graph = this;
132
133 const filterContainers = d => (graph.showMoreInfo ? true : d.type !== 'vdu');
134 const containers = this.containers.filter(filterContainers);
135 const layouts = graph.layouts.map(layoutFactory => layoutFactory.bind(this)());
136
137 function runLayout(i) {
138 const layout = layouts[i];
139 if (layout) {
140 layout.addContainers(containers);
141 layout.render(graph, runLayout.bind(null, i + 1));
142 }
143 }
144 runLayout(0);
145
146 const selection = new DescriptorGraphSelection(graph);
147 selection.addContainers(containers);
148 selection.render();
149
150 if (!this.props.readOnly) {
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 }