[CORD-1943] New service graph
- labels
- enforcing service position
- started documentation
- toggling service instances
- toggle fullscreen
Change-Id: I01b71fb2607fb58711d4624f6b5b6479609b2f4f
diff --git a/src/app/service-graph/components/coarse/coarse.component.scss b/src/app/service-graph/components/coarse/coarse.component.scss
deleted file mode 100644
index fabfb91..0000000
--- a/src/app/service-graph/components/coarse/coarse.component.scss
+++ /dev/null
@@ -1,59 +0,0 @@
-
-/*
- * Copyright 2017-present Open Networking Foundation
-
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
-
- * http://www.apache.org/licenses/LICENSE-2.0
-
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-@import './../../../style/vars.scss';
-@import '../../../../../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/variables';
-
-xos-coarse-tenancy-graph {
- display: block;
- // background: $color-accent;
-
- svg {
- height: 400px;
- width: 100%;
- background-color: $panel-filled-bg;
- border-radius: 3px;
- }
-
- .node-group {
-
- .node {
- cursor: pointer;
- }
-
- .node > rect {
- stroke: $color-accent;
- fill: $background-color;
- }
-
- .node > text {
- fill: #fff;
- font-size: 20px;
- }
- }
-
- .link-group {
- line {
- stroke: $color-accent;
- }
- }
- .arrow-marker {
- stroke: $color-accent;
- fill: $color-accent;
- }
-}
\ No newline at end of file
diff --git a/src/app/service-graph/components/coarse/coarse.component.ts b/src/app/service-graph/components/coarse/coarse.component.ts
deleted file mode 100644
index c8e2361..0000000
--- a/src/app/service-graph/components/coarse/coarse.component.ts
+++ /dev/null
@@ -1,265 +0,0 @@
-
-/*
- * Copyright 2017-present Open Networking Foundation
-
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
-
- * http://www.apache.org/licenses/LICENSE-2.0
-
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-import './coarse.component.scss';
-import * as d3 from 'd3';
-import * as $ from 'jquery';
-import * as _ from 'lodash';
-import {IXosServiceGraphStore} from '../../services/service-graph.store';
-import {IXosServiceGraph, IXosServiceGraphNode, IXosServiceGraphLink} from '../../interfaces';
-import {XosServiceGraphConfig as config} from '../../graph.config';
-import {IXosDebouncer} from '../../../core/services/helpers/debounce.helper';
-import {Subscription} from 'rxjs';
-import {IXosGraphHelpers} from '../../services/d3-helpers/graph.helpers';
-import {IXosServiceGraphReducer, IXosServiceGraphExtender} from '../../services/graph.extender';
-
-class XosCoarseTenancyGraphCtrl {
-
- static $inject = [
- '$log',
- 'XosServiceGraphStore',
- 'XosDebouncer',
- 'XosGraphHelpers',
- 'XosServiceGraphExtender'
- ];
-
- public graph: IXosServiceGraph;
-
- private CoarseGraphSubscription: Subscription;
- private svg;
- private forceLayout;
- private linkGroup;
- private nodeGroup;
- private textSize = 20;
- private textOffset = this.textSize / 4;
-
- // debounced functions
- private renderGraph;
-
- constructor (
- private $log: ng.ILogService,
- private XosServiceGraphStore: IXosServiceGraphStore,
- private XosDebouncer: IXosDebouncer,
- private XosGraphHelpers: IXosGraphHelpers,
- private XosServiceGraphExtender: IXosServiceGraphExtender
- ) {
-
- }
-
- $onInit() {
- this.renderGraph = this.XosDebouncer.debounce(this._renderGraph, 500, this);
-
- this.CoarseGraphSubscription = this.XosServiceGraphStore.getCoarse()
- .subscribe(
- (graph: IXosServiceGraph) => {
- this.$log.debug(`[XosCoarseTenancyGraph] Coarse Event and render`, graph);
-
- // id there are no data, do nothing
- if (graph.nodes.length === 0) {
- return;
- }
- this.graph = graph;
-
- _.forEach(this.XosServiceGraphExtender.getCoarse(), (r: IXosServiceGraphReducer) => {
- graph = r.reducer(graph);
- });
- this.renderGraph();
- },
- err => {
- this.$log.error(`[XosCoarseTenancyGraph] Coarse Event error`, err);
- });
-
- this.handleSvg();
- this.setupForceLayout();
-
- $(window).on('resize', () => {
- this.setupForceLayout();
- this.renderGraph();
- });
- }
-
- $onDestroy() {
- this.CoarseGraphSubscription.unsubscribe();
- }
-
- private _renderGraph() {
- if (!angular.isDefined(this.graph) || !angular.isDefined(this.graph.nodes) || !angular.isDefined(this.graph.links)) {
- return;
- }
- this.addNodeLinksToForceLayout(this.graph);
- this.renderNodes(this.graph.nodes);
- this.renderLinks(this.graph.links);
- }
-
- private getSvgDimensions(): {width: number, height: number} {
- return {
- width: $('xos-coarse-tenancy-graph svg').width() || 0,
- height: $('xos-coarse-tenancy-graph svg').height() || 0
- };
- }
-
- private handleSvg() {
- this.svg = d3.select('svg');
-
- this.svg.append('svg:defs')
- .selectAll('marker')
- .data(config.markers)
- .enter()
- .append('svg:marker')
- .attr('id', d => d.id)
- .attr('viewBox', d => d.viewBox)
- .attr('refX', d => d.refX)
- .attr('refY', d => d.refY)
- .attr('markerWidth', d => d.width)
- .attr('markerHeight', d => d.height)
- .attr('orient', 'auto')
- .attr('class', d => `${d.id}-marker`)
- .append('svg:path')
- .attr('d', d => d.path);
-
- this.linkGroup = this.svg.append('g')
- .attr({
- class: 'link-group'
- });
-
- this.nodeGroup = this.svg.append('g')
- .attr({
- class: 'node-group'
- });
- }
-
- private collide(n: any) {
- const svgDim = this.getSvgDimensions();
- const x = Math.max(n.width / 2, Math.min(n.x, svgDim.width - (n.width / 2)));
- const y = Math.max(n.height / 2, Math.min(n.y, svgDim.height - (n.height / 2)));
- return `${x}, ${y}`;
- }
-
- private setupForceLayout() {
-
- let svgDim = this.getSvgDimensions();
-
- const tick = () => {
-
- this.nodeGroup.selectAll('g.node')
- .attr({
- transform: d => `translate(${this.collide(d)})`
- });
-
- this.linkGroup.selectAll('line')
- .attr({
- x1: l => l.source.x || 0,
- y1: l => l.source.y || 0,
- x2: l => l.target.x || 0,
- y2: l => l.target.y || 0,
- });
- };
-
- this.forceLayout = d3.layout.force()
- .size([svgDim.width, svgDim.height])
- .linkDistance(config.force.linkDistance)
- .charge(config.force.charge)
- .gravity(config.force.gravity)
- .on('tick', tick);
- }
-
- private addNodeLinksToForceLayout(data: IXosServiceGraph) {
- this.forceLayout
- .nodes(data.nodes)
- .links(data.links)
- .start();
- }
-
- private renderNodes(nodes: IXosServiceGraphNode[]) {
- const self = this;
- const node = this.nodeGroup
- .selectAll('g.node')
- .data(nodes, n => n.id);
-
- const svgDim = this.getSvgDimensions();
- const entering = node.enter()
- .append('g')
- .attr({
- id: n => n.id,
- class: n => `node ${this.XosGraphHelpers.parseElemClasses(n.d3Class)}`,
- transform: `translate(${svgDim.width / 2}, ${svgDim.height / 2})`
- })
- .call(this.forceLayout.drag)
- .on('mousedown', () => {
- d3.event.stopPropagation();
- })
- .on('mouseup', (d) => {
- d.fixed = true;
- });
-
- entering.append('rect')
- .attr({
- rx: config.node.radius,
- ry: config.node.radius
- });
-
- entering.append('text')
- .attr({
- 'text-anchor': 'middle',
- 'transform': `translate(0,${this.textOffset})`
- })
- .text(n => n.label);
- // .text(n => `${n.id} - ${n.label}`);
-
- const existing = node.selectAll('rect');
-
- // resize node > rect as contained text
-
- existing.each(function(d: any) {
- const textBBox = self.XosGraphHelpers.getSiblingTextBBox(this);
- const rect = d3.select(this);
- rect.attr({
- width: textBBox.width + config.node.padding,
- height: textBBox.height + config.node.padding,
- x: textBBox.x - (config.node.padding / 2),
- y: (textBBox.y + self.textOffset) - (config.node.padding / 2)
- });
- d.width = textBBox.width + config.node.padding;
- d.height = textBBox.height + config.node.padding;
- });
-
- }
-
- private renderLinks(links: IXosServiceGraphLink[]) {
- const link = this.linkGroup
- .selectAll('line')
- .data(links, l => l.id);
-
- const entering = link.enter();
-
- // TODO read classes from graph links
-
- entering.append('line')
- .attr({
- id: n => n.id,
- class: l => `link ${this.XosGraphHelpers.parseElemClasses(l.d3Class)}`,
- 'marker-start': 'url(#arrow)'
- });
- }
-}
-
-export const XosCoarseTenancyGraph: angular.IComponentOptions = {
- template: require('./coarse.component.html'),
- controllerAs: 'vm',
- controller: XosCoarseTenancyGraphCtrl,
-};
diff --git a/src/app/service-graph/components/fine-grained/fine-grained.component.html b/src/app/service-graph/components/fine-grained/fine-grained.component.html
deleted file mode 100644
index 2e8b92e..0000000
--- a/src/app/service-graph/components/fine-grained/fine-grained.component.html
+++ /dev/null
@@ -1,22 +0,0 @@
-
-<!--
-Copyright 2017-present Open Networking Foundation
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
--->
-
-
-<h1>Fine Grained Tenancy Graph</h1>
-
-<svg>
-</svg>
diff --git a/src/app/service-graph/components/fine-grained/fine-grained.component.scss b/src/app/service-graph/components/fine-grained/fine-grained.component.scss
deleted file mode 100644
index 29ea116..0000000
--- a/src/app/service-graph/components/fine-grained/fine-grained.component.scss
+++ /dev/null
@@ -1,96 +0,0 @@
-
-/*
- * Copyright 2017-present Open Networking Foundation
-
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
-
- * http://www.apache.org/licenses/LICENSE-2.0
-
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-@import './../../../style/vars.scss';
-@import '../../../../../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/variables';
-
-xos-fine-grained-tenancy-graph {
- display: block;
- height: 100%;
- // background: $color-accent;
-
- svg {
- height: 90%;
- width: 100%;
- background-color: $panel-filled-bg;
- border-radius: 3px;
- }
-
- .node-group {
-
- .node {
- cursor: pointer;
- }
-
- .node .symbol {
- fill-rule: evenodd;
- stroke: #bbddff;
- stroke-width: 4.0px;
- fill: none;
- }
- .node .symbol-bg {
- fill-rule: evenodd;
- stroke: none;
- fill: $background-color;
- }
-
- .node {
- rect, circle {
- stroke: $color-accent;
- fill: $background-color;
- }
-
- &.network > circle{
- stroke: blue;
- }
-
- &.tenant, &.serviceinstance > rect{
- stroke: green;
- }
-
- &.subscriber > rect,
- &.tenantroot > rect{
- stroke: red;
- }
- }
-
- .node > text {
- fill: #fff;
- font-size: 20px;
- }
- }
-
- .link-group {
- line {
- stroke: $color-accent;
-
- &.ext-service-instance {
- stroke: green;
- }
-
- &.ext-owner {
- stroke: green;
- stroke-dasharray: 5;
- }
- }
- }
- .arrow-marker {
- stroke: $color-accent;
- fill: $color-accent;
- }
-}
\ No newline at end of file
diff --git a/src/app/service-graph/components/fine-grained/fine-grained.component.ts b/src/app/service-graph/components/fine-grained/fine-grained.component.ts
deleted file mode 100644
index 7d21131..0000000
--- a/src/app/service-graph/components/fine-grained/fine-grained.component.ts
+++ /dev/null
@@ -1,388 +0,0 @@
-
-/*
- * Copyright 2017-present Open Networking Foundation
-
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
-
- * http://www.apache.org/licenses/LICENSE-2.0
-
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-import './fine-grained.component.scss';
-import * as d3 from 'd3';
-import * as $ from 'jquery';
-import * as _ from 'lodash';
-import {Subscription} from 'rxjs';
-import {XosServiceGraphConfig as config} from '../../graph.config';
-import {IXosDebouncer} from '../../../core/services/helpers/debounce.helper';
-import {IXosServiceGraph, IXosServiceGraphLink, IXosServiceGraphNode} from '../../interfaces';
-import {IXosSidePanelService} from '../../../core/side-panel/side-panel.service';
-import {IXosGraphHelpers} from '../../services/d3-helpers/graph.helpers';
-import {IXosServiceGraphExtender, IXosServiceGraphReducer} from '../../services/graph.extender';
-import {IXosServiceInstanceGraphStore} from '../../services/service-instance.graph.store';
-import {IXosModeldefsCache} from '../../../datasources/helpers/modeldefs.service';
-
-class XosFineGrainedTenancyGraphCtrl {
- static $inject = [
- '$log',
- 'XosServiceInstanceGraphStore',
- 'XosDebouncer',
- 'XosModelDiscoverer',
- 'XosSidePanel',
- 'XosGraphHelpers',
- 'XosServiceGraphExtender'
- ];
-
- public graph: IXosServiceGraph;
-
- private GraphSubscription: Subscription;
- private svg;
- private forceLayout;
- private linkGroup;
- private nodeGroup;
- private defs;
- private textSize = 20;
- private textOffset = this.textSize / 4;
-
- // debounced functions
- private renderGraph;
-
- constructor(
- private $log: ng.ILogService,
- private XosServiceInstanceGraphStore: IXosServiceInstanceGraphStore,
- private XosDebouncer: IXosDebouncer,
- private XosModeldefsCache: IXosModeldefsCache,
- private XosSidePanel: IXosSidePanelService,
- private XosGraphHelpers: IXosGraphHelpers,
- private XosServiceGraphExtender: IXosServiceGraphExtender
- ) {
- this.handleSvg();
- this.loadDefs();
- this.setupForceLayout();
- this.renderGraph = this.XosDebouncer.debounce(this._renderGraph, 1000, this);
-
- $(window).on('resize', () => {
- this.setupForceLayout();
- this.renderGraph();
- });
-
- this.GraphSubscription = this.XosServiceInstanceGraphStore.get()
- .subscribe(
- (graph) => {
- this.$log.debug(`[XosServiceInstanceGraphStore] Fine-Grained Event and render`, graph);
-
- if (!graph || !graph.nodes || !graph.links) {
- return;
- }
-
- _.forEach(this.XosServiceGraphExtender.getFinegrained(), (r: IXosServiceGraphReducer) => {
- graph = r.reducer(graph);
- });
-
- this.graph = graph;
- this.renderGraph();
- },
- (err) => {
- this.$log.error(`[XosFineGrainedTenancyGraphCtrl] Error: `, err);
- }
- );
- }
-
- $onDestroy() {
- this.GraphSubscription.unsubscribe();
- }
-
- private _renderGraph() {
- if (!angular.isDefined(this.graph) || !angular.isDefined(this.graph.nodes) || !angular.isDefined(this.graph.links)) {
- return;
- }
- this.addNodeLinksToForceLayout(this.graph);
- this.renderNodes(this.graph.nodes);
- this.renderLinks(this.graph.links);
- }
-
- private getSvgDimensions(): {width: number, height: number} {
- return {
- width: $('xos-fine-grained-tenancy-graph svg').width(),
- height: $('xos-fine-grained-tenancy-graph svg').height()
- };
- }
-
- private handleSvg() {
- this.svg = d3.select('svg');
-
- this.defs = this.svg.append('defs');
-
- this.linkGroup = this.svg.append('g')
- .attr({
- class: 'link-group'
- });
-
- this.nodeGroup = this.svg.append('g')
- .attr({
- class: 'node-group'
- });
- }
-
- private loadDefs() {
- const cloud = {
- vbox: '0 0 303.8 185.8',
- path: `M88.6,44.3c31.7-45.5,102.1-66.7,135-3
- M37.8,142.9c-22.5,3.5-60.3-32.4-16.3-64.2
- M101.8,154.2c-15.6,59.7-121.4,18.8-77.3-13
- M194.6,150c-35.4,51.8-85.7,34.3-98.8-9.5
- M274.4,116.4c29.4,73.2-81.9,80.3-87.7,44.3
- M28.5,89.2C3.7,77.4,55.5,4.8,95.3,36.1
- M216.1,28.9C270.9-13,340.8,91,278.4,131.1`,
- bgpath: `M22,78.3C21.5,55.1,62.3,10.2,95.2,36
- h0c31.9-33.4,88.1-50.5,120.6-7.2l0.3,0.2
- C270.9-13,340.8,91,278.4,131.1v-0.5
- c10.5,59.8-86.4,63.7-91.8,30.1h-0.4
- c-30.2,33.6-67.6,24-84.6-6v-0.4
- c-15.6,59.7-121.4,18.8-77.3-13
- l-0.2-.2c-20.2-7.9-38.6-36.5-2.8-62.3Z`
- };
-
- this.defs.append('symbol')
- .attr({ id: 'cloud', viewBox: cloud.vbox })
- .append('path').attr('d', cloud.path);
-
- this.defs.append('symbol')
- .attr({ id: 'cloud_bg', viewBox: cloud.vbox })
- .append('path').attr('d', cloud.bgpath);
- }
-
- private setupForceLayout() {
- this.$log.debug(`[XosFineGrainedTenancyGraphCtrl] Setup Force Layout`);
- const tick = () => {
- this.nodeGroup.selectAll('g.node')
- .attr({
- transform: d => `translate(${d.x}, ${d.y})`
- });
-
- this.linkGroup.selectAll('line')
- .attr({
- x1: l => l.source.x || 0,
- y1: l => l.source.y || 0,
- x2: l => l.target.x || 0,
- y2: l => l.target.y || 0,
- });
- };
- const getLinkStrenght = (l: IXosServiceGraphLink) => {
- return 1;
- };
- const svgDim = this.getSvgDimensions();
- this.forceLayout = d3.layout.force()
- .size([svgDim.width, svgDim.height])
- .linkDistance(config.force.linkDistance)
- .linkStrength(l => getLinkStrenght(l))
- .charge(config.force.charge)
- .gravity(config.force.gravity)
- .on('tick', tick);
- }
-
- private addNodeLinksToForceLayout(data: IXosServiceGraph) {
- this.forceLayout
- .nodes(data.nodes)
- .links(data.links)
- .start();
- }
-
- private renderServiceNodes(nodes: any) {
-
- const self = this;
-
- nodes.append('rect')
- .attr({
- rx: config.node.radius,
- ry: config.node.radius
- });
-
- nodes.append('text')
- .attr({
- 'text-anchor': 'middle',
- 'transform': `translate(0,${this.textOffset})`
- })
- .text(n => n.label);
- // .text(n => `${n.id} - ${n.label}`);
-
- const existing = nodes.selectAll('rect');
-
- // resize node > rect as contained text
- existing.each(function() {
- const textBBox = self.XosGraphHelpers.getSiblingTextBBox(this);
- const rect = d3.select(this);
- rect.attr({
- width: textBBox.width + config.node.padding,
- height: textBBox.height + config.node.padding,
- x: textBBox.x - (config.node.padding / 2),
- y: (textBBox.y + self.textOffset) - (config.node.padding / 2)
- });
- });
- }
-
- private renderTenantNodes(nodes: any) {
- nodes.append('rect')
- .attr({
- width: 40,
- height: 40,
- x: -20,
- y: -20,
- transform: `rotate(45)`
- });
-
- nodes.append('text')
- .attr({
- 'text-anchor': 'middle',
- 'transform': `translate(0,${this.textOffset})`
- })
- .text(n => n.label);
- }
-
- private renderNetworkNodes(nodes: any) {
- const self = this;
-
- nodes.append('use')
- .attr({
- class: 'symbol-bg',
- 'xlink:href': '#cloud_bg'
- });
-
- nodes.append('use')
- .attr({
- class: 'symbol',
- 'xlink:href': '#cloud'
- });
-
- nodes.append('text')
- .attr({
- 'text-anchor': 'middle',
- 'transform': `translate(0,${this.textOffset})`
- })
- .text(n => n.label);
-
- const existing = nodes.selectAll('use');
-
- // resize node > rect as contained text
- existing.each(function() {
- const textBBox = self.XosGraphHelpers.getSiblingTextBBox(this);
- const useElem = d3.select(this);
- const w = textBBox.width + config.node.padding * 2;
- const h = w;
- const xoff = -(w / 2);
- const yoff = -(h / 2);
-
- useElem.attr({
- width: w,
- height: h,
- transform: 'translate(' + xoff + ',' + yoff + ')'
- });
- });
- }
-
- private renderSubscriberNodes(nodes: any) {
- const self = this;
- nodes.append('rect');
-
- nodes.append('text')
- .attr({
- 'text-anchor': 'middle',
- 'transform': `translate(0,${this.textOffset})`
- })
- .text(n => n.label);
-
- const existing = nodes.selectAll('rect');
-
- // resize node > rect as contained text
- existing.each(function() {
- const textBBox = self.XosGraphHelpers.getSiblingTextBBox(this);
- const rect = d3.select(this);
- rect.attr({
- width: textBBox.width + config.node.padding,
- height: textBBox.height + config.node.padding,
- x: textBBox.x - (config.node.padding / 2),
- y: (textBBox.y + self.textOffset) - (config.node.padding / 2)
- });
- });
- }
-
- private renderNodes(nodes: IXosServiceGraphNode[]) {
- const node = this.nodeGroup
- .selectAll('g.node')
- .data(nodes, n => n.id);
-
- let mouseEventsTimer, selectedModel;
- const svgDim = this.getSvgDimensions();
- const hStep = svgDim.width / (nodes.length - 1);
- const vStep = svgDim.height / (nodes.length - 1);
- const entering = node.enter()
- .append('g')
- .attr({
- id: n => n.id,
- class: n => `node ${n.type} ${this.XosGraphHelpers.parseElemClasses(n.d3Class)}`,
- transform: (n, i) => `translate(${hStep * i}, ${vStep * i})`
- })
- .call(this.forceLayout.drag)
- .on('mousedown', () => {
- mouseEventsTimer = new Date().getTime();
- d3.event.stopPropagation();
- })
- .on('mouseup', (n) => {
- mouseEventsTimer = new Date().getTime() - mouseEventsTimer;
- n.fixed = true;
- })
- .on('click', (n: IXosServiceGraphNode) => {
- if (mouseEventsTimer > 100) {
- // it is a drag
- return;
- }
- if (selectedModel === n.id) {
- // this model is already selected, so close the panel
- this.XosSidePanel.removeInjectedComponents();
- selectedModel = null;
- return;
- }
- selectedModel = n.id;
- const modelName = n.model['class_names'].split(',')[0];
- const formConfig = this.XosModeldefsCache.get(modelName).formCfg;
- const model = angular.copy(n.model);
- delete model.d3Id;
- this.XosSidePanel.injectComponent('xosForm', {config: formConfig, ngModel: model});
- });
-
- this.renderServiceNodes(entering.filter('.service'));
- this.renderTenantNodes(entering.filter('.serviceinstance'));
- this.renderNetworkNodes(entering.filter('.network'));
- this.renderSubscriberNodes(entering.filter('.subscriber'));
- // this.renderSubscriberNodes(entering.filter('.tenantroot'));
- }
-
- private renderLinks(links: IXosServiceGraphLink[]) {
- const link = this.linkGroup
- .selectAll('line')
- .data(links, l => l.id);
-
- const entering = link.enter();
-
- entering.append('line')
- .attr({
- id: n => n.id,
- class: n => `link ${this.XosGraphHelpers.parseElemClasses(n.d3Class)}`,
- 'marker-start': 'url(#arrow)'
- });
- }
-}
-
-export const XosFineGrainedTenancyGraph: angular.IComponentOptions = {
- template: require('./fine-grained.component.html'),
- controllerAs: 'vm',
- controller: XosFineGrainedTenancyGraphCtrl,
-};
diff --git a/src/app/service-graph/components/coarse/coarse.component.html b/src/app/service-graph/components/graph/graph.component.html
similarity index 69%
rename from src/app/service-graph/components/coarse/coarse.component.html
rename to src/app/service-graph/components/graph/graph.component.html
index c0bb4e5..6510a9f 100644
--- a/src/app/service-graph/components/coarse/coarse.component.html
+++ b/src/app/service-graph/components/graph/graph.component.html
@@ -1,4 +1,3 @@
-
<!--
Copyright 2017-present Open Networking Foundation
@@ -15,8 +14,12 @@
limitations under the License.
-->
+<h1>Service Graph</h1>
-<h1>Service Dependency Graph</h1>
-
-<svg>
-</svg>
+<div class="graph-container">
+ <div class="loader-container" ng-if="vm.loader">
+ <div class="loader"></div>
+ </div>
+ <a ng-click="vm.closeFullscreen()" class="close-btn"><i class="fa fa-times"></i></a>
+ <svg></svg>
+</div>
diff --git a/src/app/service-graph/components/graph/graph.component.scss b/src/app/service-graph/components/graph/graph.component.scss
new file mode 100644
index 0000000..40b6f11
--- /dev/null
+++ b/src/app/service-graph/components/graph/graph.component.scss
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+@import './../../../style/vars.scss';
+@import '../../../../../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/variables';
+
+$svg-size: 600px;
+
+xos-service-graph {
+ display: block;
+ // background: $color-accent;
+
+ .graph-container {
+ position: relative;
+
+ .loader-container {
+ position: absolute;
+ left: 0;
+ top: 0;
+ height: $svg-size;
+ width: 100%;
+ }
+ }
+
+ svg {
+ height: $svg-size;
+ width: 100%;
+ background-color: $panel-filled-bg;
+ border-radius: 3px;
+ }
+
+ .close-btn {
+ display: none;
+ }
+
+ .fullscreen {
+ svg {
+ z-index: 1040;
+ width: 100%;
+ height: 100%;
+ position: fixed;
+ top: 0;
+ left: 0;
+ background-color: $background-color;
+ transition: all .5s;
+ }
+
+ .close-btn {
+ cursor: pointer;
+ display: block;
+ position: fixed;
+ top: 10px;
+ right: 10px;
+ z-index: 1041;
+ }
+ }
+
+ .node-group {
+
+ .node {
+ cursor: pointer;
+ }
+
+ .node.service {
+ > rect {
+ stroke: $color-accent;
+ fill: $background-color;
+ }
+ > .icon {
+ fill: $color-accent;
+ }
+ }
+
+ .node.serviceinstance {
+ > rect {
+ stroke: green;
+ fill: $background-color;
+ }
+ > .icon {
+ fill: green;
+ }
+ }
+
+ .node {
+ >.label {
+ >text {
+ fill: #fff;
+ }
+ >rect {
+ fill: $background-color;
+ stroke: #fff;
+ }
+ }
+ }
+ }
+
+ .link-group {
+ line {
+ stroke: $color-accent;
+ }
+
+ line.ownership {
+ stroke: green;
+ stroke-dasharray: 5;
+ }
+
+ line.serviceinstancelink {
+ stroke: green;
+ }
+ }
+ .arrow-marker {
+ stroke: $color-accent;
+ fill: $color-accent;
+ }
+}
\ No newline at end of file
diff --git a/src/app/service-graph/components/graph/graph.component.ts b/src/app/service-graph/components/graph/graph.component.ts
new file mode 100644
index 0000000..5769b6f
--- /dev/null
+++ b/src/app/service-graph/components/graph/graph.component.ts
@@ -0,0 +1,192 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import './graph.component.scss';
+
+import * as d3 from 'd3';
+import * as $ from 'jquery';
+
+import {IXosGraphStore} from '../../services/graph.store';
+import {Subscription} from 'rxjs/Subscription';
+import {XosServiceGraphConfig as config} from '../../graph.config';
+import {IXosGraphHelpers} from '../../services/d3-helpers/graph-elements.helpers';
+import {IXosServiceGraphIcons} from '../../services/d3-helpers/graph-icons.service';
+import {IXosNodePositioner} from '../../services/node-positioner.service';
+import {IXosNodeRenderer} from '../../services/renderer/node.renderer';
+import {IXosSgNode} from '../../interfaces';
+import {IXosGraphConfig} from '../../services/graph.config';
+
+class XosServiceGraphCtrl {
+ static $inject = [
+ '$log',
+ '$scope',
+ 'XosGraphStore',
+ 'XosGraphHelpers',
+ 'XosServiceGraphIcons',
+ 'XosNodePositioner',
+ 'XosNodeRenderer',
+ 'XosGraphConfig'
+ ];
+
+ public loader: boolean = true;
+
+ private GraphSubscription: Subscription;
+ private graph: any; // this is the Graph instance
+
+ // graph element
+ private svg;
+ private linkGroup;
+ private nodeGroup;
+ private forceLayout;
+
+ constructor (
+ private $log: ng.ILogService,
+ private $scope: ng.IScope,
+ private XosGraphStore: IXosGraphStore,
+ private XosGraphHelpers: IXosGraphHelpers,
+ private XosServiceGraphIcons: IXosServiceGraphIcons,
+ private XosNodePositioner: IXosNodePositioner,
+ private XosNodeRenderer: IXosNodeRenderer,
+ private XosGraphConfig: IXosGraphConfig
+ ) {
+ this.$log.info('[XosServiceGraph] Component setup');
+
+ this.XosGraphConfig.setupKeyboardShortcuts();
+
+ this.setupSvg();
+ this.setupForceLayout();
+
+ this.GraphSubscription = this.XosGraphStore.get()
+ .subscribe(
+ graph => {
+ this.graph = graph;
+ if (this.graph.nodes().length > 0) {
+ this.loader = false;
+ this.renderGraph(this.graph);
+ }
+ },
+ error => {
+ this.$log.error('[XosServiceGraph] XosGraphStore observable error: ', error);
+ }
+ );
+
+ this.$scope.$on('xos.sg.update', () => {
+ this.$log.info(`[XosServiceGraph] Received event: xos.sg.update`);
+ this.renderGraph(this.graph);
+ });
+ }
+
+ $onDestroy() {
+ this.GraphSubscription.unsubscribe();
+ }
+
+ public closeFullscreen() {
+ this.XosGraphConfig.toggleFullscreen();
+ }
+
+ private setupSvg() {
+ this.svg = d3.select('xos-service-graph svg');
+
+ this.linkGroup = this.svg.append('g')
+ .attr({
+ class: 'link-group'
+ });
+
+ this.nodeGroup = this.svg.append('g')
+ .attr({
+ class: 'node-group'
+ });
+ }
+
+ private setupForceLayout() {
+ this.$log.debug(`[XosServiceGraph] Setup Force Layout`);
+ const tick = () => {
+ this.nodeGroup.selectAll('g.node')
+ .attr({
+ transform: d => `translate(${d.x}, ${d.y})`
+ });
+
+ this.linkGroup.selectAll('line')
+ .attr({
+ x1: l => l.source.x || 0,
+ y1: l => l.source.y || 0,
+ x2: l => l.target.x || 0,
+ y2: l => l.target.y || 0,
+ });
+ };
+
+ const svgDim = this.getSvgDimensions();
+
+ this.forceLayout =
+ d3.layout.force()
+ .size([svgDim.width, svgDim.height])
+ .on('tick', tick);
+ }
+
+ private getSvgDimensions(): {width: number, height: number} {
+ return {
+ width: $('xos-service-graph svg').width(),
+ height: $('xos-service-graph svg').height()
+ };
+ }
+
+ private renderGraph(graph: any) {
+ let nodes: IXosSgNode[] = this.XosGraphStore.nodesFromGraph(graph);
+ let links = this.XosGraphStore.linksFromGraph(graph);
+ const svgDim = this.getSvgDimensions();
+
+ this.XosNodePositioner.positionNodes(svgDim, nodes)
+ .then((nodes: IXosSgNode[]) => {
+
+ this.forceLayout
+ .nodes(nodes)
+ .links(links)
+ .size([svgDim.width, svgDim.height])
+ .linkDistance(config.force.linkDistance)
+ .charge(config.force.charge)
+ .gravity(config.force.gravity)
+ .start();
+
+ // render nodes
+ this.XosNodeRenderer.renderNodes(this.forceLayout, this.nodeGroup, nodes);
+ this.renderLinks(links);
+ });
+ }
+
+ private renderLinks(links: any[]) {
+
+ const link = this.linkGroup
+ .selectAll('line')
+ .data(links, l => l.id);
+
+ const entering = link.enter();
+
+ entering.append('line')
+ .attr({
+ id: n => n.id,
+ class: n => n.type
+ });
+
+ link.exit().remove();
+ }
+
+}
+
+export const XosServiceGraph: angular.IComponentOptions = {
+ template: require('./graph.component.html'),
+ controllerAs: 'vm',
+ controller: XosServiceGraphCtrl,
+};