diff --git a/src/app/app.module.ts b/src/app/app.module.ts
index 74e82e1a..023c08d9 100644
--- a/src/app/app.module.ts
+++ b/src/app/app.module.ts
@@ -72,6 +72,7 @@ import { SnapshotMenuItemComponent } from './components/snapshots/snapshot-menu-
import { MATERIAL_IMPORTS } from './material.imports';
import { DrawingService } from './services/drawing.service';
import { ProjectNameValidator } from './components/projects/models/projectNameValidator';
+import { NodeSelectInterfaceComponent } from './components/project-map/node-select-interface/node-select-interface.component';
if (environment.production) {
@@ -113,6 +114,7 @@ if (environment.production) {
LocalServerComponent,
ProgressComponent,
ServerDiscoveryComponent,
+ NodeSelectInterfaceComponent
],
imports: [
NgbModule.forRoot(),
diff --git a/src/app/cartography/angular-map.imports.ts b/src/app/cartography/angular-map.imports.ts
new file mode 100644
index 00000000..3a78c523
--- /dev/null
+++ b/src/app/cartography/angular-map.imports.ts
@@ -0,0 +1,28 @@
+import { DraggableComponent } from './components/draggable/draggable.component';
+import { SelectionComponent } from './components/selection/selection.component';
+import { NodeComponent } from './components/experimental-map/node/node.component';
+import { LinkComponent } from './components/experimental-map/link/link.component';
+import { StatusComponent } from './components/experimental-map/status/status.component';
+import { DrawingComponent } from './components/experimental-map/drawing/drawing.component';
+import { EllipseComponent } from './components/experimental-map/drawing/drawings/ellipse/ellipse.component';
+import { ImageComponent } from './components/experimental-map/drawing/drawings/image/image.component';
+import { LineComponent } from './components/experimental-map/drawing/drawings/line/line.component';
+import { RectComponent } from './components/experimental-map/drawing/drawings/rect/rect.component';
+import { TextComponent } from './components/experimental-map/drawing/drawings/text/text.component';
+import { InterfaceLabelComponent } from './components/experimental-map/interface-label/interface-label.component';
+
+
+export const ANGULAR_MAP_DECLARATIONS = [
+ NodeComponent,
+ LinkComponent,
+ StatusComponent,
+ DrawingComponent,
+ EllipseComponent,
+ ImageComponent,
+ LineComponent,
+ RectComponent,
+ TextComponent,
+ DraggableComponent,
+ SelectionComponent,
+ InterfaceLabelComponent
+];
diff --git a/src/app/cartography/cartography.module.ts b/src/app/cartography/cartography.module.ts
index 8b9080fd..5898a32c 100644
--- a/src/app/cartography/cartography.module.ts
+++ b/src/app/cartography/cartography.module.ts
@@ -2,9 +2,7 @@ import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { MatMenuModule, MatIconModule } from '@angular/material';
-import { MapComponent } from './components/map/map.component';
import { DrawLinkToolComponent } from './components/draw-link-tool/draw-link-tool.component';
-import { NodeSelectInterfaceComponent } from './components/node-select-interface/node-select-interface.component';
import { CssFixer } from './helpers/css-fixer';
import { FontFixer } from './helpers/font-fixer';
@@ -14,10 +12,9 @@ import { QtDasharrayFixer } from './helpers/qt-dasharray-fixer';
import { LayersManager } from './managers/layers-manager';
import { MapChangeDetectorRef } from './services/map-change-detector-ref';
import { Context } from './models/context';
+import { ANGULAR_MAP_DECLARATIONS } from './angular-map.imports';
import { D3_MAP_IMPORTS } from './d3-map.imports';
import { CanvasSizeDetector } from './helpers/canvas-size-detector';
-import { MapListeners } from './listeners/map-listeners';
-import { DraggableListener } from './listeners/draggable-listener';
import { DrawingsEventSource } from './events/drawings-event-source';
import { NodesEventSource } from './events/nodes-event-source';
import { DrawingToMapDrawingConverter } from './converters/map/drawing-to-map-drawing-converter';
@@ -35,10 +32,14 @@ import { PortToMapPortConverter } from './converters/map/port-to-map-port-conver
import { SymbolToMapSymbolConverter } from './converters/map/symbol-to-map-symbol-converter';
import { LinkNodeToMapLinkNodeConverter } from './converters/map/link-node-to-map-link-node-converter';
import { GraphDataManager } from './managers/graph-data-manager';
-import { SelectionUpdateListener } from './listeners/selection-update-listener';
import { MapNodesDataSource, MapLinksDataSource, MapDrawingsDataSource, MapSymbolsDataSource } from './datasources/map-datasource';
-import { SelectionListener } from './listeners/selection-listener';
import { LinksEventSource } from './events/links-event-source';
+import { D3MapComponent } from './components/d3-map/d3-map.component';
+import { ExperimentalMapComponent } from './components/experimental-map/experimental-map.component';
+import { SelectionEventSource } from './events/selection-event-source';
+import { SelectionControlComponent } from './components/selection-control/selection-control.component';
+import { SelectionSelectComponent } from './components/selection-select/selection-select.component';
+import { DraggableSelectionComponent } from './components/draggable-selection/draggable-selection.component';
@NgModule({
@@ -48,9 +49,13 @@ import { LinksEventSource } from './events/links-event-source';
MatIconModule
],
declarations: [
- MapComponent,
+ D3MapComponent,
+ ExperimentalMapComponent,
DrawLinkToolComponent,
- NodeSelectInterfaceComponent
+ ...ANGULAR_MAP_DECLARATIONS,
+ SelectionControlComponent,
+ SelectionSelectComponent,
+ DraggableSelectionComponent
],
providers: [
CssFixer,
@@ -62,10 +67,6 @@ import { LinksEventSource } from './events/links-event-source';
MapChangeDetectorRef,
CanvasSizeDetector,
Context,
- SelectionUpdateListener,
- MapListeners,
- DraggableListener,
- SelectionListener,
DrawingsEventSource,
NodesEventSource,
LinksEventSource,
@@ -88,8 +89,9 @@ import { LinksEventSource } from './events/links-event-source';
MapLinksDataSource,
MapDrawingsDataSource,
MapSymbolsDataSource,
+ SelectionEventSource,
...D3_MAP_IMPORTS
],
- exports: [ MapComponent ]
+ exports: [ D3MapComponent, ExperimentalMapComponent ]
})
export class CartographyModule { }
diff --git a/src/app/cartography/components/d3-map/d3-map.component.html b/src/app/cartography/components/d3-map/d3-map.component.html
new file mode 100644
index 00000000..bebf16a7
--- /dev/null
+++ b/src/app/cartography/components/d3-map/d3-map.component.html
@@ -0,0 +1,14 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/app/cartography/components/map/map.component.scss b/src/app/cartography/components/d3-map/d3-map.component.scss
similarity index 100%
rename from src/app/cartography/components/map/map.component.scss
rename to src/app/cartography/components/d3-map/d3-map.component.scss
diff --git a/src/app/cartography/components/map/map.component.spec.ts b/src/app/cartography/components/d3-map/d3-map.component.spec.ts
similarity index 67%
rename from src/app/cartography/components/map/map.component.spec.ts
rename to src/app/cartography/components/d3-map/d3-map.component.spec.ts
index 2aa33cd9..ed5697fc 100644
--- a/src/app/cartography/components/map/map.component.spec.ts
+++ b/src/app/cartography/components/d3-map/d3-map.component.spec.ts
@@ -1,14 +1,14 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
-import { MapComponent } from './map.component';
+import { D3MapComponent } from './d3-map.component';
-describe('MapComponent', () => {
- let component: MapComponent;
- let fixture: ComponentFixture;
+describe('D3MapComponent', () => {
+ let component: D3MapComponent;
+ let fixture: ComponentFixture;
beforeEach(async(() => {
TestBed.configureTestingModule({
- declarations: [ MapComponent ]
+ declarations: [ D3MapComponent ]
})
.compileComponents();
}));
diff --git a/src/app/cartography/components/map/map.component.ts b/src/app/cartography/components/d3-map/d3-map.component.ts
similarity index 92%
rename from src/app/cartography/components/map/map.component.ts
rename to src/app/cartography/components/d3-map/d3-map.component.ts
index d3879d8b..416df23a 100644
--- a/src/app/cartography/components/map/map.component.ts
+++ b/src/app/cartography/components/d3-map/d3-map.component.ts
@@ -1,5 +1,5 @@
import {
- Component, ElementRef, HostListener, Input, OnChanges, OnDestroy, OnInit, SimpleChange, EventEmitter, Output
+ Component, ElementRef, HostListener, Input, OnChanges, OnDestroy, OnInit, SimpleChange, EventEmitter, Output, ViewChild
} from '@angular/core';
import { Selection, select } from 'd3-selection';
@@ -13,7 +13,6 @@ import { SelectionTool } from '../../tools/selection-tool';
import { MovingTool } from '../../tools/moving-tool';
import { MapChangeDetectorRef } from '../../services/map-change-detector-ref';
import { CanvasSizeDetector } from '../../helpers/canvas-size-detector';
-import { MapListeners } from '../../listeners/map-listeners';
import { DrawingsWidget } from '../../widgets/drawings';
import { Node } from '../../models/node';
import { Link } from '../../../models/link';
@@ -23,11 +22,11 @@ import { GraphDataManager } from '../../managers/graph-data-manager';
@Component({
- selector: 'app-map',
- templateUrl: './map.component.html',
- styleUrls: ['./map.component.scss']
+ selector: 'app-d3-map',
+ templateUrl: './d3-map.component.html',
+ styleUrls: ['./d3-map.component.scss']
})
-export class MapComponent implements OnInit, OnChanges, OnDestroy {
+export class D3MapComponent implements OnInit, OnChanges, OnDestroy {
@Input() nodes: Node[] = [];
@Input() links: Link[] = [];
@Input() drawings: Drawing[] = [];
@@ -36,6 +35,8 @@ export class MapComponent implements OnInit, OnChanges, OnDestroy {
@Input() width = 1500;
@Input() height = 600;
+ @ViewChild('svg') svgRef: ElementRef;
+
private parentNativeElement: any;
private svg: Selection;
@@ -50,7 +51,6 @@ export class MapComponent implements OnInit, OnChanges, OnDestroy {
private context: Context,
private mapChangeDetectorRef: MapChangeDetectorRef,
private canvasSizeDetector: CanvasSizeDetector,
- private mapListeners: MapListeners,
protected element: ElementRef,
protected nodesWidget: NodesWidget,
protected drawingsWidget: DrawingsWidget,
@@ -117,14 +117,11 @@ export class MapComponent implements OnInit, OnChanges, OnDestroy {
this.redraw();
}
});
-
- this.mapListeners.onInit(this.svg);
}
ngOnDestroy() {
this.graphLayout.disconnect(this.svg);
this.onChangesDetected.unsubscribe();
- this.mapListeners.onDestroy();
}
public createGraph(domElement: HTMLElement) {
diff --git a/src/app/cartography/components/draggable-selection/draggable-selection.component.html b/src/app/cartography/components/draggable-selection/draggable-selection.component.html
new file mode 100644
index 00000000..e69de29b
diff --git a/src/app/cartography/components/draggable-selection/draggable-selection.component.scss b/src/app/cartography/components/draggable-selection/draggable-selection.component.scss
new file mode 100644
index 00000000..e69de29b
diff --git a/src/app/cartography/components/draggable-selection/draggable-selection.component.spec.ts b/src/app/cartography/components/draggable-selection/draggable-selection.component.spec.ts
new file mode 100644
index 00000000..12b1884b
--- /dev/null
+++ b/src/app/cartography/components/draggable-selection/draggable-selection.component.spec.ts
@@ -0,0 +1,25 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { DraggableSelectionComponent } from './draggable-selection.component';
+
+describe('DraggableSelectionComponent', () => {
+ let component: DraggableSelectionComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ DraggableSelectionComponent ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(DraggableSelectionComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ // it('should create', () => {
+ // expect(component).toBeTruthy();
+ // });
+});
diff --git a/src/app/cartography/components/draggable-selection/draggable-selection.component.ts b/src/app/cartography/components/draggable-selection/draggable-selection.component.ts
new file mode 100644
index 00000000..bdca40e1
--- /dev/null
+++ b/src/app/cartography/components/draggable-selection/draggable-selection.component.ts
@@ -0,0 +1,147 @@
+import { Component, OnInit, OnDestroy, Input } from '@angular/core';
+import { Subscription, merge } from 'rxjs';
+import { NodesWidget } from '../../widgets/nodes';
+import { DrawingsWidget } from '../../widgets/drawings';
+import { LinksWidget } from '../../widgets/links';
+import { SelectionManager } from '../../managers/selection-manager';
+import { NodesEventSource } from '../../events/nodes-event-source';
+import { DrawingsEventSource } from '../../events/drawings-event-source';
+import { GraphDataManager } from '../../managers/graph-data-manager';
+import { DraggableStart, DraggableDrag, DraggableEnd } from '../../events/draggable';
+import { MapNode } from '../../models/map/map-node';
+import { MapDrawing } from '../../models/map/map-drawing';
+import { DraggedDataEvent } from '../../events/event-source';
+import { select } from 'd3-selection';
+import { NodeWidget } from '../../widgets/node';
+import { MapLabel } from '../../models/map/map-label';
+import { LabelWidget } from '../../widgets/label';
+
+@Component({
+ selector: 'app-draggable-selection',
+ templateUrl: './draggable-selection.component.html',
+ styleUrls: ['./draggable-selection.component.scss']
+})
+export class DraggableSelectionComponent implements OnInit, OnDestroy {
+ private start: Subscription;
+ private drag: Subscription;
+ private end: Subscription;
+
+ @Input('svg') svg: SVGSVGElement;
+
+ constructor(
+ private nodesWidget: NodesWidget,
+ private drawingsWidget: DrawingsWidget,
+ private linksWidget: LinksWidget,
+ private labelWidget: LabelWidget,
+ private selectionManager: SelectionManager,
+ private nodesEventSource: NodesEventSource,
+ private drawingsEventSource: DrawingsEventSource,
+ private graphDataManager: GraphDataManager
+ ) { }
+
+ ngOnInit() {
+ const svg = select(this.svg);
+
+ this.start = merge(
+ this.nodesWidget.draggable.start,
+ this.drawingsWidget.draggable.start,
+ this.labelWidget.draggable.start
+ ).subscribe((evt: DraggableStart) => {
+ const selected = this.selectionManager.getSelected();
+ if (evt.datum instanceof MapNode) {
+ if (selected.filter((item) => item instanceof MapNode && item.id === evt.datum.id).length === 0) {
+ this.selectionManager.setSelected([evt.datum]);
+ }
+ }
+
+ if (evt.datum instanceof MapDrawing) {
+ if (selected.filter((item) => item instanceof MapDrawing && item.id === evt.datum.id).length === 0) {
+ this.selectionManager.setSelected([evt.datum]);
+ }
+ }
+
+ if (evt.datum instanceof MapLabel) {
+ if (selected.filter((item) => item instanceof MapLabel && item.id === evt.datum.id).length === 0) {
+ this.selectionManager.setSelected([evt.datum]);
+ }
+ }
+ });
+
+ this.drag = merge(
+ this.nodesWidget.draggable.drag,
+ this.drawingsWidget.draggable.drag,
+ this.labelWidget.draggable.drag
+ ).subscribe((evt: DraggableDrag) => {
+ const selected = this.selectionManager.getSelected();
+ const selectedNodes = selected.filter((item) => item instanceof MapNode);
+ // update nodes
+ selectedNodes.forEach((node: MapNode) => {
+ node.x += evt.dx;
+ node.y += evt.dy;
+
+ this.nodesWidget.redrawNode(svg, node);
+
+ const links = this.graphDataManager.getLinks().filter(
+ (link) => link.target.id === node.id || link.source.id === node.id);
+ links.forEach((link) => {
+ this.linksWidget.redrawLink(svg, link);
+ });
+ });
+
+ // update drawings
+ selected.filter((item) => item instanceof MapDrawing).forEach((drawing: MapDrawing) => {
+ drawing.x += evt.dx;
+ drawing.y += evt.dy;
+ this.drawingsWidget.redrawDrawing(svg, drawing);
+ });
+
+ // update labels
+ selected.filter((item) => item instanceof MapLabel).forEach((label: MapLabel) => {
+ const isParentNodeSelected = selectedNodes.filter((node) => node.id === label.nodeId).length > 0;
+ if (isParentNodeSelected) {
+ return;
+ }
+
+ const node = this.graphDataManager.getNodes().filter((node) => node.id === label.nodeId)[0];
+ node.label.x += evt.dx;
+ node.label.y += evt.dy;
+ this.labelWidget.redrawLabel(svg, label);
+ });
+
+ });
+
+ this.end = merge(
+ this.nodesWidget.draggable.end,
+ this.drawingsWidget.draggable.end,
+ this.labelWidget.draggable.end,
+ ).subscribe((evt: DraggableEnd) => {
+ const selected = this.selectionManager.getSelected();
+ const selectedNodes = selected.filter((item) => item instanceof MapNode);
+
+ selectedNodes.forEach((item: MapNode) => {
+ this.nodesEventSource.dragged.emit(new DraggedDataEvent(item, evt.dx, evt.dy));
+ })
+
+ selected.filter((item) => item instanceof MapDrawing).forEach((item: MapDrawing) => {
+ this.drawingsEventSource.dragged.emit(new DraggedDataEvent(item, evt.dx, evt.dy));
+ });
+
+ selected.filter((item) => item instanceof MapLabel).forEach((label: MapLabel) => {
+ const isParentNodeSelected = selectedNodes.filter((node) => node.id === label.nodeId).length > 0;
+ if (isParentNodeSelected) {
+ return;
+ }
+
+ this.nodesEventSource.labelDragged.emit(new DraggedDataEvent(label, evt.dx, evt.dy));
+ });
+
+ });
+ }
+
+ ngOnDestroy() {
+ this.start.unsubscribe();
+ this.drag.unsubscribe();
+ this.end.unsubscribe();
+ }
+
+}
diff --git a/src/app/cartography/components/draggable/draggable.component.scss b/src/app/cartography/components/draggable/draggable.component.scss
new file mode 100644
index 00000000..e69de29b
diff --git a/src/app/cartography/components/draggable/draggable.component.spec.ts b/src/app/cartography/components/draggable/draggable.component.spec.ts
new file mode 100644
index 00000000..84bfbb9c
--- /dev/null
+++ b/src/app/cartography/components/draggable/draggable.component.spec.ts
@@ -0,0 +1,25 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { DraggableComponent } from './draggable.component';
+
+describe('DraggableComponent', () => {
+ let component: DraggableComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ DraggableComponent ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(DraggableComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ // it('should create', () => {
+ // expect(component).toBeTruthy();
+ // });
+});
diff --git a/src/app/cartography/components/draggable/draggable.component.ts b/src/app/cartography/components/draggable/draggable.component.ts
new file mode 100644
index 00000000..1cd1c20f
--- /dev/null
+++ b/src/app/cartography/components/draggable/draggable.component.ts
@@ -0,0 +1,101 @@
+import { Component, OnInit, ElementRef, AfterViewInit, OnDestroy, Input, Output, EventEmitter } from '@angular/core';
+import { Observable, Subscription } from 'rxjs';
+import { Point } from '../../models/point';
+
+
+export class DraggableDraggedEvent {
+ constructor(
+ public x: number,
+ public y: number,
+ public dx: number,
+ public dy: number
+ ) {}
+}
+
+
+@Component({
+ selector: '[app-draggable]',
+ template:``,
+ styleUrls: ['./draggable.component.scss']
+})
+export class DraggableComponent implements OnInit, AfterViewInit, OnDestroy {
+ @Input('app-draggable') item: Point;
+ @Output() dragging = new EventEmitter();
+ @Output() dragged = new EventEmitter();
+
+ draggable: Subscription;
+
+ private startX: number;
+ private startY: number;
+
+ private posX: number;
+ private posY: number;
+
+ constructor(
+ private elementRef: ElementRef
+ ) { }
+
+ ngOnInit() {
+ }
+
+ ngAfterViewInit() {
+ const down = Observable.fromEvent(this.elementRef.nativeElement, 'mousedown').do((e: MouseEvent) => e.preventDefault())
+
+ down.subscribe((e: MouseEvent) => {
+ this.posX = this.item.x;
+ this.posY = this.item.y;
+
+ this.startX = e.clientX;
+ this.startY = e.clientY;
+ });
+
+ const up = Observable
+ .fromEvent(document, 'mouseup')
+ .do((e: MouseEvent) => {
+ e.preventDefault();
+ });
+
+ const mouseMove = Observable
+ .fromEvent(document, 'mousemove')
+ .do((e: MouseEvent) => e.stopPropagation());
+
+ const scrollWindow = Observable
+ .fromEvent(document, 'scroll')
+ .startWith({});
+
+ const move = Observable.combineLatest(mouseMove, scrollWindow);
+
+ const drag = down.mergeMap((md: MouseEvent) => {
+ return move
+ .map(([mm, s]) => mm)
+ .do((mm: MouseEvent) => {
+ const x = this.startX - mm.clientX;
+ const y = this.startY - mm.clientY;
+
+ this.item.x = Math.round(this.posX - x);
+ this.item.y = Math.round(this.posY - y);
+ this.dragging.emit(new DraggableDraggedEvent(this.item.x, this.item.y, -x, -y));
+ })
+ .skipUntil(up
+ .take(1)
+ .do((e: MouseEvent) => {
+ const x = this.startX - e.clientX;
+ const y = this.startY - e.clientY;
+
+ this.item.x = Math.round(this.posX - x);
+ this.item.y = Math.round(this.posY - y);
+
+ this.dragged.emit(new DraggableDraggedEvent(this.item.x, this.item.y, -x, -y));
+ }))
+ .take(1);
+ });
+
+ this.draggable = drag.subscribe((e: MouseEvent) => {
+ // this.cd.detectChanges();
+ });
+ }
+
+ ngOnDestroy() {
+ this.draggable.unsubscribe();
+ }
+}
diff --git a/src/app/cartography/components/draw-link-tool/draw-link-tool.component.html b/src/app/cartography/components/draw-link-tool/draw-link-tool.component.html
index 16188157..89ab7db7 100644
--- a/src/app/cartography/components/draw-link-tool/draw-link-tool.component.html
+++ b/src/app/cartography/components/draw-link-tool/draw-link-tool.component.html
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/src/app/cartography/components/draw-link-tool/draw-link-tool.component.ts b/src/app/cartography/components/draw-link-tool/draw-link-tool.component.ts
index b4452b08..66845a31 100644
--- a/src/app/cartography/components/draw-link-tool/draw-link-tool.component.ts
+++ b/src/app/cartography/components/draw-link-tool/draw-link-tool.component.ts
@@ -1,7 +1,7 @@
import { Component, OnInit, Output, EventEmitter, OnDestroy, ViewChild } from '@angular/core';
import { DrawingLineWidget } from '../../widgets/drawing-line';
import { Subscription } from 'rxjs';
-import { NodeSelectInterfaceComponent } from '../node-select-interface/node-select-interface.component';
+// import { NodeSelectInterfaceComponent } from '../node-select-interface/node-select-interface.component';
import { MapLinkCreated } from '../../events/links';
import { NodeClicked } from '../../events/nodes';
import { NodeWidget } from '../../widgets/node';
@@ -16,7 +16,7 @@ import { LinksEventSource } from '../../events/links-event-source';
styleUrls: ['./draw-link-tool.component.scss']
})
export class DrawLinkToolComponent implements OnInit, OnDestroy {
- @ViewChild(NodeSelectInterfaceComponent) nodeSelectInterfaceMenu: NodeSelectInterfaceComponent;
+ // @ViewChild(NodeSelectInterfaceComponent) nodeSelectInterfaceMenu: NodeSelectInterfaceComponent;
// @Output('linkCreated') linkCreated = new EventEmitter();
@@ -29,13 +29,13 @@ export class DrawLinkToolComponent implements OnInit, OnDestroy {
) { }
ngOnInit() {
- this.onNodeClicked = this.nodeWidget.onNodeClicked.subscribe((eventNode: NodeClicked) => {
- this.nodeSelectInterfaceMenu.open(
- eventNode.node,
- eventNode.event.clientY,
- eventNode.event.clientX
- );
- });
+ // this.onNodeClicked = this.nodeWidget.onNodeClicked.subscribe((eventNode: NodeClicked) => {
+ // this.nodeSelectInterfaceMenu.open(
+ // eventNode.node,
+ // eventNode.event.clientY,
+ // eventNode.event.clientX
+ // );
+ // });
}
ngOnDestroy() {
diff --git a/src/app/cartography/components/experimental-map/drawing/drawing.component.html b/src/app/cartography/components/experimental-map/drawing/drawing.component.html
new file mode 100644
index 00000000..abfcf9e2
--- /dev/null
+++ b/src/app/cartography/components/experimental-map/drawing/drawing.component.html
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/app/cartography/components/experimental-map/drawing/drawing.component.scss b/src/app/cartography/components/experimental-map/drawing/drawing.component.scss
new file mode 100644
index 00000000..e69de29b
diff --git a/src/app/cartography/components/experimental-map/drawing/drawing.component.spec.ts b/src/app/cartography/components/experimental-map/drawing/drawing.component.spec.ts
new file mode 100644
index 00000000..d0ab0a6f
--- /dev/null
+++ b/src/app/cartography/components/experimental-map/drawing/drawing.component.spec.ts
@@ -0,0 +1,25 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { DrawingComponent } from './drawing.component';
+
+describe('DrawingComponent', () => {
+ let component: DrawingComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ DrawingComponent ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(DrawingComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ // it('should create', () => {
+ // expect(component).toBeTruthy();
+ // });
+});
diff --git a/src/app/cartography/components/experimental-map/drawing/drawing.component.ts b/src/app/cartography/components/experimental-map/drawing/drawing.component.ts
new file mode 100644
index 00000000..e2bfc811
--- /dev/null
+++ b/src/app/cartography/components/experimental-map/drawing/drawing.component.ts
@@ -0,0 +1,71 @@
+import { Component, OnInit, Input, ChangeDetectorRef } from '@angular/core';
+import { EllipseElement } from '../../../models/drawings/ellipse-element';
+import { ImageElement } from '../../../models/drawings/image-element';
+import { LineElement } from '../../../models/drawings/line-element';
+import { RectElement } from '../../../models/drawings/rect-element';
+import { TextElement } from '../../../models/drawings/text-element';
+import { SvgToDrawingConverter } from '../../../helpers/svg-to-drawing-converter';
+import { DraggedDataEvent } from '../../../events/event-source';
+import { MapDrawing } from '../../../models/map/map-drawing';
+import { DrawingsEventSource } from '../../../events/drawings-event-source';
+
+@Component({
+ selector: '[app-drawing]',
+ templateUrl: './drawing.component.html',
+ styleUrls: ['./drawing.component.scss']
+})
+export class DrawingComponent implements OnInit {
+ @Input('app-drawing') drawing: MapDrawing;
+
+ constructor(
+ private svgToDrawingConverter: SvgToDrawingConverter,
+ private drawingsEventSource: DrawingsEventSource,
+ private cd: ChangeDetectorRef,
+ ) { }
+
+ ngOnInit() {
+ try {
+ this.drawing.element = this.svgToDrawingConverter.convert(this.drawing.svg);
+ } catch (error) {
+ console.log(`Cannot convert due to Error: '${error}'`);
+ }
+ }
+
+ OnDragging(evt) {
+ this.drawing.x = evt.x;
+ this.drawing.y = evt.y;
+ this.cd.detectChanges();
+ }
+
+ OnDragged(evt) {
+ this.cd.detectChanges();
+ this.drawingsEventSource.dragged.emit(new DraggedDataEvent(this.drawing, evt.dx, evt.dy))
+ }
+
+ is(element, type: string) {
+ if (!element) {
+ return false;
+ }
+
+ if (type === "ellipse") {
+ return element instanceof EllipseElement;
+ }
+ if (type === "image") {
+ return element instanceof ImageElement;
+ }
+ if (type === "line") {
+ return element instanceof LineElement;
+ }
+ if (type === "rect") {
+ return element instanceof RectElement;
+ }
+ if (type === "text") {
+ return element instanceof TextElement;
+ }
+ return false;
+ }
+
+ get transformation() {
+ return `translate(${this.drawing.x},${this.drawing.y}) rotate(${this.drawing.rotation})`;
+ }
+}
diff --git a/src/app/cartography/components/experimental-map/drawing/drawings/ellipse/ellipse.component.html b/src/app/cartography/components/experimental-map/drawing/drawings/ellipse/ellipse.component.html
new file mode 100644
index 00000000..8c4a296b
--- /dev/null
+++ b/src/app/cartography/components/experimental-map/drawing/drawings/ellipse/ellipse.component.html
@@ -0,0 +1,12 @@
+
diff --git a/src/app/cartography/components/experimental-map/drawing/drawings/ellipse/ellipse.component.scss b/src/app/cartography/components/experimental-map/drawing/drawings/ellipse/ellipse.component.scss
new file mode 100644
index 00000000..e69de29b
diff --git a/src/app/cartography/components/experimental-map/drawing/drawings/ellipse/ellipse.component.spec.ts b/src/app/cartography/components/experimental-map/drawing/drawings/ellipse/ellipse.component.spec.ts
new file mode 100644
index 00000000..ac1e24ac
--- /dev/null
+++ b/src/app/cartography/components/experimental-map/drawing/drawings/ellipse/ellipse.component.spec.ts
@@ -0,0 +1,25 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { EllipseComponent } from './ellipse.component';
+
+describe('EllipseComponent', () => {
+ let component: EllipseComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ EllipseComponent ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(EllipseComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ // it('should create', () => {
+ // expect(component).toBeTruthy();
+ // });
+});
diff --git a/src/app/cartography/components/experimental-map/drawing/drawings/ellipse/ellipse.component.ts b/src/app/cartography/components/experimental-map/drawing/drawings/ellipse/ellipse.component.ts
new file mode 100644
index 00000000..c2bb0475
--- /dev/null
+++ b/src/app/cartography/components/experimental-map/drawing/drawings/ellipse/ellipse.component.ts
@@ -0,0 +1,40 @@
+import { Component, OnInit, Input } from '@angular/core';
+import { EllipseElement } from '../../../../../models/drawings/ellipse-element';
+import { QtDasharrayFixer } from '../../../../../helpers/qt-dasharray-fixer';
+
+@Component({
+ selector: '[app-ellipse]',
+ templateUrl: './ellipse.component.html',
+ styleUrls: ['./ellipse.component.scss']
+})
+export class EllipseComponent implements OnInit {
+ @Input('app-ellipse') ellipse: EllipseElement;
+
+ constructor(
+ private qtDasharrayFixer: QtDasharrayFixer
+ ) { }
+
+ ngOnInit() {
+ }
+
+ get fill_opacity() {
+ if(isFinite(this.ellipse.fill_opacity)) {
+ return this.ellipse.fill_opacity;
+ }
+ return null;
+ }
+
+ get stroke_width() {
+ if(isFinite(this.ellipse.stroke_width)) {
+ return this.ellipse.stroke_width;
+ }
+ return null
+ }
+
+ get stroke_dasharray() {
+ if(this.ellipse.stroke_dasharray) {
+ return this.qtDasharrayFixer.fix(this.ellipse.stroke_dasharray);
+ }
+ return null;
+ }
+}
diff --git a/src/app/cartography/components/experimental-map/drawing/drawings/image/image.component.html b/src/app/cartography/components/experimental-map/drawing/drawings/image/image.component.html
new file mode 100644
index 00000000..6e36c391
--- /dev/null
+++ b/src/app/cartography/components/experimental-map/drawing/drawings/image/image.component.html
@@ -0,0 +1,6 @@
+
\ No newline at end of file
diff --git a/src/app/cartography/components/experimental-map/drawing/drawings/image/image.component.scss b/src/app/cartography/components/experimental-map/drawing/drawings/image/image.component.scss
new file mode 100644
index 00000000..e69de29b
diff --git a/src/app/cartography/components/experimental-map/drawing/drawings/image/image.component.spec.ts b/src/app/cartography/components/experimental-map/drawing/drawings/image/image.component.spec.ts
new file mode 100644
index 00000000..6d8acaad
--- /dev/null
+++ b/src/app/cartography/components/experimental-map/drawing/drawings/image/image.component.spec.ts
@@ -0,0 +1,25 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { ImageComponent } from './image.component';
+
+describe('ImageComponent', () => {
+ let component: ImageComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ ImageComponent ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(ImageComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ // it('should create', () => {
+ // expect(component).toBeTruthy();
+ // });
+});
diff --git a/src/app/cartography/components/experimental-map/drawing/drawings/image/image.component.ts b/src/app/cartography/components/experimental-map/drawing/drawings/image/image.component.ts
new file mode 100644
index 00000000..f151d5a2
--- /dev/null
+++ b/src/app/cartography/components/experimental-map/drawing/drawings/image/image.component.ts
@@ -0,0 +1,17 @@
+import { Component, OnInit, Input } from '@angular/core';
+import { ImageElement } from '../../../../../models/drawings/image-element';
+
+@Component({
+ selector: '[app-image]',
+ templateUrl: './image.component.html',
+ styleUrls: ['./image.component.scss']
+})
+export class ImageComponent implements OnInit {
+
+ @Input('app-image') image: ImageElement;
+
+ constructor() { }
+
+ ngOnInit() {
+ }
+}
diff --git a/src/app/cartography/components/experimental-map/drawing/drawings/line/line.component.html b/src/app/cartography/components/experimental-map/drawing/drawings/line/line.component.html
new file mode 100644
index 00000000..d32f4207
--- /dev/null
+++ b/src/app/cartography/components/experimental-map/drawing/drawings/line/line.component.html
@@ -0,0 +1,10 @@
+
\ No newline at end of file
diff --git a/src/app/cartography/components/experimental-map/drawing/drawings/line/line.component.scss b/src/app/cartography/components/experimental-map/drawing/drawings/line/line.component.scss
new file mode 100644
index 00000000..e69de29b
diff --git a/src/app/cartography/components/experimental-map/drawing/drawings/line/line.component.spec.ts b/src/app/cartography/components/experimental-map/drawing/drawings/line/line.component.spec.ts
new file mode 100644
index 00000000..64f2500f
--- /dev/null
+++ b/src/app/cartography/components/experimental-map/drawing/drawings/line/line.component.spec.ts
@@ -0,0 +1,25 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { LineComponent } from './line.component';
+
+describe('LineComponent', () => {
+ let component: LineComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ LineComponent ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(LineComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ // it('should create', () => {
+ // expect(component).toBeTruthy();
+ // });
+});
diff --git a/src/app/cartography/components/experimental-map/drawing/drawings/line/line.component.ts b/src/app/cartography/components/experimental-map/drawing/drawings/line/line.component.ts
new file mode 100644
index 00000000..a7f8fa06
--- /dev/null
+++ b/src/app/cartography/components/experimental-map/drawing/drawings/line/line.component.ts
@@ -0,0 +1,34 @@
+import { Component, OnInit, Input } from '@angular/core';
+import { QtDasharrayFixer } from '../../../../../helpers/qt-dasharray-fixer';
+import { LineElement } from '../../../../../models/drawings/line-element';
+
+@Component({
+ selector: '[app-line]',
+ templateUrl: './line.component.html',
+ styleUrls: ['./line.component.scss']
+})
+export class LineComponent implements OnInit {
+ @Input('app-line') line: LineElement;
+
+ constructor(
+ private qtDasharrayFixer: QtDasharrayFixer
+ ) { }
+
+ ngOnInit() {
+ }
+
+ get stroke_width() {
+ if(isFinite(this.line.stroke_width)) {
+ return this.line.stroke_width;
+ }
+ return null
+ }
+
+ get stroke_dasharray() {
+ if(this.line.stroke_dasharray) {
+ return this.qtDasharrayFixer.fix(this.line.stroke_dasharray);
+ }
+ return null;
+ }
+
+}
diff --git a/src/app/cartography/components/experimental-map/drawing/drawings/rect/rect.component.html b/src/app/cartography/components/experimental-map/drawing/drawings/rect/rect.component.html
new file mode 100644
index 00000000..1a0944f4
--- /dev/null
+++ b/src/app/cartography/components/experimental-map/drawing/drawings/rect/rect.component.html
@@ -0,0 +1,10 @@
+
\ No newline at end of file
diff --git a/src/app/cartography/components/experimental-map/drawing/drawings/rect/rect.component.scss b/src/app/cartography/components/experimental-map/drawing/drawings/rect/rect.component.scss
new file mode 100644
index 00000000..e69de29b
diff --git a/src/app/cartography/components/experimental-map/drawing/drawings/rect/rect.component.spec.ts b/src/app/cartography/components/experimental-map/drawing/drawings/rect/rect.component.spec.ts
new file mode 100644
index 00000000..d7b1ea95
--- /dev/null
+++ b/src/app/cartography/components/experimental-map/drawing/drawings/rect/rect.component.spec.ts
@@ -0,0 +1,25 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { RectComponent } from './rect.component';
+
+describe('RectComponent', () => {
+ let component: RectComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ RectComponent ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(RectComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ // it('should create', () => {
+ // expect(component).toBeTruthy();
+ // });
+});
diff --git a/src/app/cartography/components/experimental-map/drawing/drawings/rect/rect.component.ts b/src/app/cartography/components/experimental-map/drawing/drawings/rect/rect.component.ts
new file mode 100644
index 00000000..42878aab
--- /dev/null
+++ b/src/app/cartography/components/experimental-map/drawing/drawings/rect/rect.component.ts
@@ -0,0 +1,41 @@
+import { Component, OnInit, Input } from '@angular/core';
+import { RectElement } from '../../../../../models/drawings/rect-element';
+import { QtDasharrayFixer } from '../../../../../helpers/qt-dasharray-fixer';
+
+@Component({
+ selector: '[app-rect]',
+ templateUrl: './rect.component.html',
+ styleUrls: ['./rect.component.scss']
+})
+export class RectComponent implements OnInit {
+ @Input('app-rect') rect: RectElement;
+
+ constructor(
+ private qtDasharrayFixer: QtDasharrayFixer
+ ) { }
+
+ ngOnInit() {
+ }
+
+ get fill_opacity() {
+ if(isFinite(this.rect.fill_opacity)) {
+ return this.rect.fill_opacity;
+ }
+ return null;
+ }
+
+ get stroke_width() {
+ if(isFinite(this.rect.stroke_width)) {
+ return this.rect.stroke_width;
+ }
+ return null
+ }
+
+ get stroke_dasharray() {
+ if(this.rect.stroke_dasharray) {
+ return this.qtDasharrayFixer.fix(this.rect.stroke_dasharray);
+ }
+ return null;
+ }
+
+}
diff --git a/src/app/cartography/components/experimental-map/drawing/drawings/text/text.component.html b/src/app/cartography/components/experimental-map/drawing/drawings/text/text.component.html
new file mode 100644
index 00000000..ad6d71c2
--- /dev/null
+++ b/src/app/cartography/components/experimental-map/drawing/drawings/text/text.component.html
@@ -0,0 +1,14 @@
+
+ {{line}}
+
\ No newline at end of file
diff --git a/src/app/cartography/components/experimental-map/drawing/drawings/text/text.component.scss b/src/app/cartography/components/experimental-map/drawing/drawings/text/text.component.scss
new file mode 100644
index 00000000..e69de29b
diff --git a/src/app/cartography/components/experimental-map/drawing/drawings/text/text.component.spec.ts b/src/app/cartography/components/experimental-map/drawing/drawings/text/text.component.spec.ts
new file mode 100644
index 00000000..845e947d
--- /dev/null
+++ b/src/app/cartography/components/experimental-map/drawing/drawings/text/text.component.spec.ts
@@ -0,0 +1,25 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { TextComponent } from './text.component';
+
+describe('TextComponent', () => {
+ let component: TextComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ TextComponent ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(TextComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ // it('should create', () => {
+ // expect(component).toBeTruthy();
+ // });
+});
diff --git a/src/app/cartography/components/experimental-map/drawing/drawings/text/text.component.ts b/src/app/cartography/components/experimental-map/drawing/drawings/text/text.component.ts
new file mode 100644
index 00000000..be113d5b
--- /dev/null
+++ b/src/app/cartography/components/experimental-map/drawing/drawings/text/text.component.ts
@@ -0,0 +1,68 @@
+import { Component, OnInit, Input, ViewChild, ElementRef, DoCheck } from '@angular/core';
+import { DomSanitizer } from '@angular/platform-browser';
+import { TextElement } from '../../../../../models/drawings/text-element';
+import { FontFixer } from '../../../../../helpers/font-fixer';
+
+@Component({
+ selector: '[app-text]',
+ templateUrl: './text.component.html',
+ styleUrls: ['./text.component.scss']
+})
+export class TextComponent implements OnInit, DoCheck {
+ static MARGIN = 4;
+
+ @Input('app-text') text: TextElement;
+
+ @ViewChild('text') textRef: ElementRef;
+
+ lines: string[] = [];
+
+ transformation = "";
+
+ constructor(
+ private fontFixer: FontFixer,
+ private sanitizer: DomSanitizer
+ ) { }
+
+ ngOnInit() {
+ this.lines = this.getLines(this.text.text);
+ }
+
+ ngDoCheck() {
+ this.transformation = this.calculateTransformation();
+ }
+
+ get style() {
+ const font = this.fontFixer.fix(this.text);
+
+ const styles: string[] = [];
+ if (font.font_family) {
+ styles.push(`font-family: "${this.text.font_family}"`);
+ }
+ if (font.font_size) {
+ styles.push(`font-size: ${this.text.font_size}pt`);
+ }
+ if (font.font_weight) {
+ styles.push(`font-weight: ${this.text.font_weight}`);
+ }
+ return this.sanitizer.bypassSecurityTrustStyle(styles.join("; "));
+ }
+
+ get textDecoration() {
+ return this.text.text_decoration;
+ }
+
+ calculateTransformation() {
+ const tspans = this.textRef.nativeElement.getElementsByTagName('tspan');
+ if(tspans.length > 0) {
+ const height = this.textRef.nativeElement.getBBox().height / tspans.length;
+ return `translate(${TextComponent.MARGIN}, ${height - TextComponent.MARGIN})`;
+ }
+ return '';
+ }
+
+ getLines(text: string) {
+ return text.split(/\r?\n/)
+ }
+
+}
diff --git a/src/app/cartography/components/experimental-map/experimental-map.component.html b/src/app/cartography/components/experimental-map/experimental-map.component.html
new file mode 100644
index 00000000..2a918534
--- /dev/null
+++ b/src/app/cartography/components/experimental-map/experimental-map.component.html
@@ -0,0 +1,41 @@
+
diff --git a/src/app/cartography/components/experimental-map/experimental-map.component.scss b/src/app/cartography/components/experimental-map/experimental-map.component.scss
new file mode 100644
index 00000000..7fb7062f
--- /dev/null
+++ b/src/app/cartography/components/experimental-map/experimental-map.component.scss
@@ -0,0 +1,5 @@
+svg {
+ display: block;
+}
+
+
diff --git a/src/app/cartography/components/experimental-map/experimental-map.component.spec.ts b/src/app/cartography/components/experimental-map/experimental-map.component.spec.ts
new file mode 100644
index 00000000..0d5db4bb
--- /dev/null
+++ b/src/app/cartography/components/experimental-map/experimental-map.component.spec.ts
@@ -0,0 +1,26 @@
+// import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+// import { MapComponent } from './map.component';
+
+// describe('MapComponent', () => {
+// let component: MapComponent;
+// let fixture: ComponentFixture;
+
+// beforeEach(async(() => {
+// TestBed.configureTestingModule({
+// declarations: [ MapComponent ]
+// })
+// .compileComponents();
+// }));
+
+// // beforeEach(() => {
+// // fixture = TestBed.createComponent(MapComponent);
+// // component = fixture.componentInstance;
+// // fixture.detectChanges();
+// // });
+// //
+// // it('should create', () => {
+// // expect(component).toBeTruthy();
+// // });
+// });
+// //
\ No newline at end of file
diff --git a/src/app/cartography/components/experimental-map/experimental-map.component.ts b/src/app/cartography/components/experimental-map/experimental-map.component.ts
new file mode 100644
index 00000000..21442474
--- /dev/null
+++ b/src/app/cartography/components/experimental-map/experimental-map.component.ts
@@ -0,0 +1,131 @@
+import {
+ Component, ElementRef, HostListener, Input, OnChanges, OnDestroy, OnInit,
+ SimpleChange, ChangeDetectionStrategy, ChangeDetectorRef, ViewChild
+} from '@angular/core';
+
+import { GraphLayout } from "../../widgets/graph-layout";
+import { Context } from "../../models/context";
+import { Size } from "../../models/size";
+import { Subscription } from 'rxjs';
+import { MapChangeDetectorRef } from '../../services/map-change-detector-ref';
+import { CanvasSizeDetector } from '../../helpers/canvas-size-detector';
+import { Node } from '../../models/node';
+import { Link } from '../../../models/link';
+import { Drawing } from '../../models/drawing';
+import { Symbol } from '../../../models/symbol';
+import { GraphDataManager } from '../../managers/graph-data-manager';
+import { LayersManager } from '../../managers/layers-manager';
+
+
+@Component({
+ selector: 'app-experimental-map',
+ templateUrl: './experimental-map.component.html',
+ styleUrls: ['./experimental-map.component.scss'],
+ changeDetection: ChangeDetectionStrategy.OnPush
+})
+export class ExperimentalMapComponent implements OnInit, OnChanges, OnDestroy {
+ @Input() nodes: Node[] = [];
+ @Input() links: Link[] = [];
+ @Input() drawings: Drawing[] = [];
+ @Input() symbols: Symbol[] = [];
+ // @Input() changed: EventEmitter;
+
+ // @Input('node-updated') nodeUpdated: EventEmitter;
+
+ @Input() width = 1500;
+ @Input() height = 600;
+
+ @ViewChild('svg') svg: ElementRef;
+
+ private changesDetected: Subscription;
+
+ protected settings = {
+ 'show_interface_labels': true
+ };
+
+ constructor(
+ private graphDataManager: GraphDataManager,
+ private context: Context,
+ private mapChangeDetectorRef: MapChangeDetectorRef,
+ private canvasSizeDetector: CanvasSizeDetector,
+ private changeDetectorRef: ChangeDetectorRef,
+ private layersManger: LayersManager,
+ public graphLayout: GraphLayout,
+ ) {
+ }
+
+ @Input('show-interface-labels')
+ set showInterfaceLabels(value) {
+ this.settings.show_interface_labels = value;
+ this.mapChangeDetectorRef.detectChanges();
+ }
+
+ @Input('moving-tool')
+ set movingTool(value) {
+ this.mapChangeDetectorRef.detectChanges();
+ }
+
+ @Input('selection-tool')
+ set selectionTool(value) {
+ this.mapChangeDetectorRef.detectChanges();
+ }
+
+ @Input('draw-link-tool') drawLinkTool: boolean;
+
+ @Input('readonly') set readonly(value) {
+ }
+
+ ngOnChanges(changes: { [propKey: string]: SimpleChange }) {
+ }
+
+ ngOnInit() {
+ // this.changeDetectorRef.detach();
+
+ this.changesDetected = this.mapChangeDetectorRef.changesDetected.subscribe(() => {
+ this.graphDataManager.setNodes(this.nodes);
+ this.graphDataManager.setLinks(this.links);
+ this.graphDataManager.setDrawings(this.drawings);
+ this.graphDataManager.setSymbols(this.symbols);
+
+ this.changeDetectorRef.detectChanges();
+ });
+
+
+ // this.changedSubscription = this.changed.subscribe(() => {
+ // this.changeDetectorRef.detectChanges();
+ // });
+
+ // this.nodeUpdated.subscribe((node: Node) => {
+ // this.nodeChanged.emit(node);
+ // });
+ }
+
+ ngOnDestroy() {
+ this.changesDetected.unsubscribe();
+ // this.changedSubscription.unsubscribe();
+ }
+
+ public getSize(): Size {
+ return this.canvasSizeDetector.getOptimalSize(this.width, this.height);
+ }
+
+ public get layers() {
+ return this.layersManger.getLayersList();
+ }
+
+ public get transform() {
+ const ctx = new Context();
+ ctx.size = this.getSize();
+
+ const xTrans = ctx.getZeroZeroTransformationPoint().x + ctx.transformation.x;
+ const yTrans = ctx.getZeroZeroTransformationPoint().y + ctx.transformation.y;
+ const kTrans = ctx.transformation.k;
+ return `translate(${xTrans}, ${yTrans}) scale(${kTrans})`;
+ }
+
+
+ @HostListener('window:resize', ['$event'])
+ onResize(event) {
+
+ }
+}
diff --git a/src/app/cartography/components/experimental-map/interface-label/interface-label.component.html b/src/app/cartography/components/experimental-map/interface-label/interface-label.component.html
new file mode 100644
index 00000000..2a2317ad
--- /dev/null
+++ b/src/app/cartography/components/experimental-map/interface-label/interface-label.component.html
@@ -0,0 +1,28 @@
+
+
+
+
+ {{ text }}
+
+
+
diff --git a/src/app/cartography/components/experimental-map/interface-label/interface-label.component.scss b/src/app/cartography/components/experimental-map/interface-label/interface-label.component.scss
new file mode 100644
index 00000000..e69de29b
diff --git a/src/app/cartography/components/experimental-map/interface-label/interface-label.component.spec.ts b/src/app/cartography/components/experimental-map/interface-label/interface-label.component.spec.ts
new file mode 100644
index 00000000..1e121d81
--- /dev/null
+++ b/src/app/cartography/components/experimental-map/interface-label/interface-label.component.spec.ts
@@ -0,0 +1,25 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { InterfaceLabelComponent } from './interface-label.component';
+
+describe('InterfaceLabelComponent', () => {
+ let component: InterfaceLabelComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ InterfaceLabelComponent ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(InterfaceLabelComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ // it('should create', () => {
+ // expect(component).toBeTruthy();
+ // });
+});
diff --git a/src/app/cartography/components/experimental-map/interface-label/interface-label.component.ts b/src/app/cartography/components/experimental-map/interface-label/interface-label.component.ts
new file mode 100644
index 00000000..d596cc3a
--- /dev/null
+++ b/src/app/cartography/components/experimental-map/interface-label/interface-label.component.ts
@@ -0,0 +1,98 @@
+import { Component, OnInit, Input, ChangeDetectorRef, ElementRef, ViewChild } from '@angular/core';
+import { DomSanitizer } from '@angular/platform-browser';
+import { CssFixer } from '../../../helpers/css-fixer';
+
+@Component({
+ selector: '[app-interface-label]',
+ templateUrl: './interface-label.component.html',
+ styleUrls: ['./interface-label.component.scss']
+})
+export class InterfaceLabelComponent implements OnInit {
+ @Input('app-interface-label') ignore: any;
+
+ @ViewChild('textSvg') textRef: ElementRef;
+
+ private label = {
+ 'x': 0,
+ 'y': 0,
+ 'text': '',
+ 'style': '',
+ 'rotation': 0
+ };
+
+ borderSize = 5;
+
+ textWidth = 0;
+ textHeight = 0;
+
+ constructor(
+ private elementRef: ElementRef,
+ private ref: ChangeDetectorRef,
+ private sanitizer: DomSanitizer,
+ private cssFixer: CssFixer
+ ) { }
+
+ ngOnInit() {
+ }
+
+ @Input('x')
+ set x(value) {
+ this.label['x'] = value;
+ this.ref.detectChanges();
+ }
+
+ @Input('y')
+ set y(value) {
+ this.label['y'] = value;
+ this.ref.detectChanges();
+ }
+
+ @Input('text')
+ set text(value) {
+ this.label['text'] = value;
+ this.ref.detectChanges();
+ }
+
+ @Input('style')
+ set style(value) {
+ this.label['style'] = this.cssFixer.fix(value);
+ this.ref.detectChanges();
+ }
+
+ @Input('rotation')
+ set rotation(value) {
+ this.label['rotation'] = value;
+ this.ref.detectChanges();
+ }
+
+ get text() {
+ return this.label.text;
+ }
+
+ get sanitizedStyle() {
+ return this.sanitizer.bypassSecurityTrustStyle(this.label.style);
+ }
+
+ get rectX() {
+ return 0;
+ }
+
+ get rectY() {
+ return -this.textRef.nativeElement.getBBox().height - this.borderSize;
+ }
+
+ get rectWidth() {
+ return this.textRef.nativeElement.getBBox().width + this.borderSize*2;
+ }
+
+ get rectHeight() {
+ return this.textRef.nativeElement.getBBox().height + this.borderSize;
+ }
+
+ get transform() {
+ const bbox = this.elementRef.nativeElement.getBBox();
+ const x = this.label.x;
+ const y = this.label.y + bbox.height;
+ return `translate(${x}, ${y}) rotate(${this.label.rotation}, ${x}, ${y})`;
+ }
+}
diff --git a/src/app/cartography/components/experimental-map/link/link.component.html b/src/app/cartography/components/experimental-map/link/link.component.html
new file mode 100644
index 00000000..c9201b75
--- /dev/null
+++ b/src/app/cartography/components/experimental-map/link/link.component.html
@@ -0,0 +1,59 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/app/cartography/components/experimental-map/link/link.component.scss b/src/app/cartography/components/experimental-map/link/link.component.scss
new file mode 100644
index 00000000..e69de29b
diff --git a/src/app/cartography/components/experimental-map/link/link.component.spec.ts b/src/app/cartography/components/experimental-map/link/link.component.spec.ts
new file mode 100644
index 00000000..3642d967
--- /dev/null
+++ b/src/app/cartography/components/experimental-map/link/link.component.spec.ts
@@ -0,0 +1,25 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { LinkComponent } from './link.component';
+
+describe('LinkComponent', () => {
+ let component: LinkComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ LinkComponent ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(LinkComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ // it('should create', () => {
+ // expect(component).toBeTruthy();
+ // });
+});
diff --git a/src/app/cartography/components/experimental-map/link/link.component.ts b/src/app/cartography/components/experimental-map/link/link.component.ts
new file mode 100644
index 00000000..8c0d8d60
--- /dev/null
+++ b/src/app/cartography/components/experimental-map/link/link.component.ts
@@ -0,0 +1,65 @@
+import {
+ Component, OnInit, Input, ViewChild,
+ ElementRef, EventEmitter, ChangeDetectorRef,
+ OnDestroy } from '@angular/core';
+import { Subscription } from 'rxjs';
+import { LinkStrategy } from './strategies/link-strategy';
+import { EthernetLinkStrategy } from './strategies/ethernet-link-strategy';
+import { SerialLinkStrategy } from './strategies/serial-link-strategy';
+import { MultiLinkCalculatorHelper } from '../../../helpers/multi-link-calculator-helper';
+import { Node } from '../../../models/node';
+import { MapLink } from '../../../models/map/map-link';
+
+
+@Component({
+ selector: '[app-link]',
+ templateUrl: './link.component.html',
+ styleUrls: ['./link.component.scss'],
+})
+export class LinkComponent implements OnInit, OnDestroy {
+ @Input('app-link') link: MapLink;
+ @Input('node-changed') nodeChanged: EventEmitter;
+ @Input('show-interface-labels') showInterfaceLabels: boolean;
+
+ @ViewChild('path') path: ElementRef;
+
+ private ethernetLinkStrategy = new EthernetLinkStrategy();
+ private serialLinkStrategy = new SerialLinkStrategy();
+
+ private nodeChangedSubscription: Subscription;
+
+ constructor(
+ private multiLinkCalculatorHelper: MultiLinkCalculatorHelper,
+ private ref: ChangeDetectorRef
+ ) {}
+
+ ngOnInit() {
+ this.ref.detectChanges();
+ // this.nodeChangedSubscription = this.nodeChanged.subscribe((node: Node) => {
+ // if (this.link.source.node_id === node.node_id || this.link.target.node_id === node.node_id) {
+ // this.ref.detectChanges();
+ // }
+ // });
+ }
+
+ ngOnDestroy() {
+ // this.nodeChangedSubscription.unsubscribe();
+ }
+
+ get strategy(): LinkStrategy {
+ if (this.link.linkType === 'serial') {
+ return this.serialLinkStrategy;
+ }
+ return this.ethernetLinkStrategy;
+ }
+
+ get transform() {
+ const translation = this.multiLinkCalculatorHelper.linkTranslation(this.link.distance, this.link.source, this.link.target);
+ return `translate (${translation.dx}, ${translation.dy})`;
+ }
+
+ get d() {
+ return this.strategy.d(this.link);
+ }
+
+}
diff --git a/src/app/cartography/components/experimental-map/link/strategies/ethernet-link-strategy.ts b/src/app/cartography/components/experimental-map/link/strategies/ethernet-link-strategy.ts
new file mode 100644
index 00000000..f4767e72
--- /dev/null
+++ b/src/app/cartography/components/experimental-map/link/strategies/ethernet-link-strategy.ts
@@ -0,0 +1,18 @@
+import { LinkStrategy } from "./link-strategy";
+import { path } from "d3-path";
+import { MapLink } from "../../../../models/map/map-link";
+
+
+export class EthernetLinkStrategy implements LinkStrategy {
+ public d(link: MapLink): string {
+ const points = [
+ [link.source.x + link.source.width / 2., link.source.y + link.source.height / 2.],
+ [link.target.x + link.target.width / 2., link.target.y + link.target.height / 2.]
+ ];
+
+ const line_generator = path();
+ line_generator.moveTo(points[0][0], points[0][1]);
+ line_generator.lineTo(points[1][0], points[1][1]);
+ return line_generator.toString();
+ }
+}
\ No newline at end of file
diff --git a/src/app/cartography/components/experimental-map/link/strategies/link-strategy.ts b/src/app/cartography/components/experimental-map/link/strategies/link-strategy.ts
new file mode 100644
index 00000000..511c9e7f
--- /dev/null
+++ b/src/app/cartography/components/experimental-map/link/strategies/link-strategy.ts
@@ -0,0 +1,5 @@
+import { MapLink } from "../../../../models/map/map-link";
+
+export interface LinkStrategy {
+ d(link: MapLink): string;
+}
diff --git a/src/app/cartography/components/experimental-map/link/strategies/serial-link-strategy.ts b/src/app/cartography/components/experimental-map/link/strategies/serial-link-strategy.ts
new file mode 100644
index 00000000..9dd64d2d
--- /dev/null
+++ b/src/app/cartography/components/experimental-map/link/strategies/serial-link-strategy.ts
@@ -0,0 +1,55 @@
+import { path } from "d3-path";
+import { LinkStrategy } from "./link-strategy";
+import { MapLink } from "../../../../models/map/map-link";
+
+
+export class SerialLinkStrategy implements LinkStrategy {
+ private linkToPoints(link: MapLink) {
+ const source = {
+ 'x': link.source.x + link.source.width / 2,
+ 'y': link.source.y + link.source.height / 2
+ };
+ const target = {
+ 'x': link.target.x + link.target.width / 2,
+ 'y': link.target.y + link.target.height / 2
+ };
+
+ const dx = target.x - source.x;
+ const dy = target.y - source.y;
+
+ const vector_angle = Math.atan2(dy, dx);
+ const rot_angle = -Math.PI / 4.0;
+ const vect_rot = [
+ Math.cos(vector_angle + rot_angle),
+ Math.sin(vector_angle + rot_angle)
+ ];
+
+ const angle_source: [number, number] = [
+ source.x + dx / 2.0 + 15 * vect_rot[0],
+ source.y + dy / 2.0 + 15 * vect_rot[1]
+ ];
+
+ const angle_target: [number, number] = [
+ target.x - dx / 2.0 - 15 * vect_rot[0],
+ target.y - dy / 2.0 - 15 * vect_rot[1]
+ ];
+
+ return [
+ [source.x, source.y],
+ angle_source,
+ angle_target,
+ [target.x, target.y]
+ ];
+ }
+
+ d(link: MapLink): string {
+ const points = this.linkToPoints(link);
+
+ const line_generator = path();
+ line_generator.moveTo(points[0][0], points[0][1]);
+ line_generator.lineTo(points[1][0], points[1][1]);
+ line_generator.lineTo(points[2][0], points[2][1]);
+ line_generator.lineTo(points[3][0], points[3][1]);
+ return line_generator.toString();
+ }
+}
diff --git a/src/app/cartography/components/experimental-map/node/node.component.html b/src/app/cartography/components/experimental-map/node/node.component.html
new file mode 100644
index 00000000..eabce9c7
--- /dev/null
+++ b/src/app/cartography/components/experimental-map/node/node.component.html
@@ -0,0 +1,25 @@
+
+
+
+ {{ node.label.text }}
+
+
\ No newline at end of file
diff --git a/src/app/cartography/components/experimental-map/node/node.component.scss b/src/app/cartography/components/experimental-map/node/node.component.scss
new file mode 100644
index 00000000..e69de29b
diff --git a/src/app/cartography/components/experimental-map/node/node.component.spec.ts b/src/app/cartography/components/experimental-map/node/node.component.spec.ts
new file mode 100644
index 00000000..4902d2ec
--- /dev/null
+++ b/src/app/cartography/components/experimental-map/node/node.component.spec.ts
@@ -0,0 +1,25 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { NodeComponent } from './node.component';
+
+describe('NodeComponent', () => {
+ let component: NodeComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ NodeComponent ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(NodeComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ // it('should create', () => {
+ // expect(component).toBeTruthy();
+ // });
+});
diff --git a/src/app/cartography/components/experimental-map/node/node.component.ts b/src/app/cartography/components/experimental-map/node/node.component.ts
new file mode 100644
index 00000000..2abc52b2
--- /dev/null
+++ b/src/app/cartography/components/experimental-map/node/node.component.ts
@@ -0,0 +1,119 @@
+import {
+ Component, OnInit, Input, ElementRef,
+ ViewChild, ChangeDetectorRef, ChangeDetectionStrategy, Output,
+ EventEmitter, OnDestroy, OnChanges, AfterViewInit } from '@angular/core';
+import { DomSanitizer } from '@angular/platform-browser';
+import { Subscription } from 'rxjs';
+import { CssFixer } from '../../../helpers/css-fixer';
+import { FontFixer } from '../../../helpers/font-fixer';
+import { Symbol } from '../../../../models/symbol';
+import { MapNode } from '../../../models/map/map-node';
+import { NodesEventSource } from '../../../events/nodes-event-source';
+import { DraggedDataEvent } from '../../../events/event-source';
+
+@Component({
+ selector: '[app-node]',
+ templateUrl: './node.component.html',
+ styleUrls: ['./node.component.scss'],
+ changeDetection: ChangeDetectionStrategy.OnPush
+})
+export class NodeComponent implements OnInit, OnDestroy, OnChanges, AfterViewInit {
+ static NODE_LABEL_MARGIN = 3;
+
+ @ViewChild('label') label: ElementRef;
+ @ViewChild('image') imageRef: ElementRef;
+
+ @Input('app-node') node: MapNode;
+ @Input('symbols') symbols: Symbol[];
+ @Input('node-changed') nodeChanged: EventEmitter;
+
+ // @Output() valueChange = new EventEmitter();
+
+ nodeChangedSubscription: Subscription;
+
+ private labelHeight = 0;
+
+ constructor(
+ private cssFixer: CssFixer,
+ private fontFixer: FontFixer,
+ private sanitizer: DomSanitizer,
+ protected element: ElementRef,
+ private cd: ChangeDetectorRef,
+ private nodesEventSource: NodesEventSource
+ ) { }
+
+ ngOnInit() {
+ // this.nodeChangedSubscription = this.nodeChanged.subscribe((node: Node) => {
+ // if (node.node_id === this.node.node_id) {
+ // this.cd.detectChanges();
+ // }
+ // });
+ }
+
+ ngOnDestroy() {
+ // this.nodeChangedSubscription.unsubscribe();
+ }
+
+ ngOnChanges(changes) {
+ this.cd.detectChanges();
+ }
+
+ ngAfterViewInit() {
+ this.labelHeight = this.getLabelHeight();
+ // reload BBox
+ this.cd.detectChanges();
+ }
+
+ OnDragging(evt) {
+ this.node.x = evt.x;
+ this.node.y = evt.y;
+ this.cd.detectChanges();
+ }
+
+ OnDragged(evt) {
+ this.cd.detectChanges();
+ this.nodesEventSource.dragged.emit(new DraggedDataEvent(this.node, evt.dx, evt.dy))
+ }
+
+
+ get symbol(): string {
+ const symbol = this.symbols.find((s: Symbol) => s.symbol_id === this.node.symbol);
+ if (symbol) {
+ return 'data:image/svg+xml;base64,' + btoa(symbol.raw);
+ }
+ // @todo; we need to have default image
+ return 'data:image/svg+xml;base64,none';
+ }
+
+ get label_style() {
+
+ let styles = this.cssFixer.fix(this.node.label.style);
+ styles = this.fontFixer.fixStyles(styles);
+ return this.sanitizer.bypassSecurityTrustStyle(styles);
+ }
+
+ get label_x(): number {
+ if (this.node.label.x === null) {
+ // center
+ const bbox = this.label.nativeElement.getBBox();
+
+ return -bbox.width / 2.;
+ }
+ return this.node.label.x + NodeComponent.NODE_LABEL_MARGIN;
+ }
+
+ get label_y(): number {
+ this.labelHeight = this.getLabelHeight();
+
+ if (this.node.label.x === null) {
+ // center
+ return - this.node.height / 2. - this.labelHeight ;
+ }
+ return this.node.label.y + this.labelHeight - NodeComponent.NODE_LABEL_MARGIN;
+ }
+
+ private getLabelHeight() {
+ const bbox = this.label.nativeElement.getBBox();
+ return bbox.height;
+ }
+}
diff --git a/src/app/cartography/components/experimental-map/status/status.component.html b/src/app/cartography/components/experimental-map/status/status.component.html
new file mode 100644
index 00000000..cfcef840
--- /dev/null
+++ b/src/app/cartography/components/experimental-map/status/status.component.html
@@ -0,0 +1,21 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/src/app/cartography/components/experimental-map/status/status.component.scss b/src/app/cartography/components/experimental-map/status/status.component.scss
new file mode 100644
index 00000000..e69de29b
diff --git a/src/app/cartography/components/experimental-map/status/status.component.spec.ts b/src/app/cartography/components/experimental-map/status/status.component.spec.ts
new file mode 100644
index 00000000..ddf4f677
--- /dev/null
+++ b/src/app/cartography/components/experimental-map/status/status.component.spec.ts
@@ -0,0 +1,25 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { StatusComponent } from './status.component';
+
+describe('StatusComponent', () => {
+ let component: StatusComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ StatusComponent ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(StatusComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/src/app/cartography/components/experimental-map/status/status.component.ts b/src/app/cartography/components/experimental-map/status/status.component.ts
new file mode 100644
index 00000000..05d58efc
--- /dev/null
+++ b/src/app/cartography/components/experimental-map/status/status.component.ts
@@ -0,0 +1,83 @@
+import { Component, ElementRef, Input, ChangeDetectorRef } from '@angular/core';
+
+
+@Component({
+ selector: '[app-status]',
+ templateUrl: './status.component.html',
+ styleUrls: ['./status.component.scss'],
+})
+export class StatusComponent {
+ static STOPPED_STATUS_RECT_WIDTH = 10;
+
+ data = {
+ 'status': '',
+ 'path': null,
+ 'direction': null,
+ 'd': null
+ };
+
+ constructor(
+ protected element: ElementRef,
+ private ref: ChangeDetectorRef
+ ) {}
+
+ @Input('app-status')
+ set status(value) {
+ this.data.status = value;
+ this.ref.markForCheck();
+ }
+
+ @Input('path')
+ set path(value) {
+ this.data.path = value;
+ this.ref.markForCheck();
+ }
+
+ @Input('direction')
+ set direction(value) {
+ this.data.direction = value;
+ this.ref.markForCheck();
+ }
+
+ @Input('d')
+ set d(value) {
+ if (this.data.d !== value) {
+ this.data.d = value;
+ this.ref.markForCheck();
+ }
+ }
+
+ get status() {
+ return this.data.status;
+ }
+
+ get direction() {
+ return this.data.direction;
+ }
+
+ get path() {
+ return this.data.path;
+ }
+
+ get sourceStatusPoint() {
+ if (!this.path) {
+ return null;
+ }
+ return this.path.nativeElement.getPointAtLength(45);
+ }
+
+ get targetStatusPoint() {
+ if (!this.path) {
+ return null;
+ }
+ return this.path.nativeElement.getPointAtLength(this.path.nativeElement.getTotalLength() - 45);
+ }
+
+ get point() {
+ if (this.direction === 'source') {
+ return this.sourceStatusPoint;
+ }
+ return this.targetStatusPoint;
+ }
+
+}
diff --git a/src/app/cartography/components/map/map.component.html b/src/app/cartography/components/map/map.component.html
deleted file mode 100644
index dc9747ac..00000000
--- a/src/app/cartography/components/map/map.component.html
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
\ No newline at end of file
diff --git a/src/app/cartography/components/selection-control/selection-control.component.html b/src/app/cartography/components/selection-control/selection-control.component.html
new file mode 100644
index 00000000..e69de29b
diff --git a/src/app/cartography/components/selection-control/selection-control.component.scss b/src/app/cartography/components/selection-control/selection-control.component.scss
new file mode 100644
index 00000000..e69de29b
diff --git a/src/app/cartography/components/selection-control/selection-control.component.spec.ts b/src/app/cartography/components/selection-control/selection-control.component.spec.ts
new file mode 100644
index 00000000..af1fecd6
--- /dev/null
+++ b/src/app/cartography/components/selection-control/selection-control.component.spec.ts
@@ -0,0 +1,72 @@
+import { fakeAsync, tick } from '@angular/core/testing';
+
+import { SelectionControlComponent } from './selection-control.component';
+import { SelectionManager } from '../../managers/selection-manager';
+import { SelectionEventSource } from '../../events/selection-event-source';
+import { mock, when, instance } from 'ts-mockito';
+import { GraphDataManager } from '../../managers/graph-data-manager';
+import { MapNode } from '../../models/map/map-node';
+import { MapLink } from '../../models/map/map-link';
+import { InRectangleHelper } from '../../helpers/in-rectangle-helper';
+import { Rectangle } from '../../models/rectangle';
+
+describe('SelectionControlComponent', () => {
+ let component: SelectionControlComponent;
+ let manager: SelectionManager;
+ let selectionEventSource: SelectionEventSource;
+
+ beforeEach(() => {
+
+ const mockedGraphData = mock(GraphDataManager);
+
+ const node_1 = new MapNode();
+ node_1.id = "test1";
+ node_1.name = "Node 1";
+ node_1.x = 150;
+ node_1.y = 150;
+
+ const node_2 = new MapNode();
+ node_2.id = "test2";
+ node_2.name = "Node 2";
+ node_2.x = 300;
+ node_2.y = 300;
+
+ const link_1 = new MapLink();
+ link_1.id = "test1";
+
+ when(mockedGraphData.getNodes()).thenReturn([node_1, node_2]);
+ when(mockedGraphData.getLinks()).thenReturn([link_1]);
+ when(mockedGraphData.getDrawings()).thenReturn([]);
+
+ const graphData = instance(mockedGraphData);
+ const inRectangleHelper = new InRectangleHelper();
+
+ selectionEventSource = new SelectionEventSource();
+ manager = new SelectionManager();
+
+ component = new SelectionControlComponent(selectionEventSource, graphData, inRectangleHelper, manager);
+ component.ngOnInit();
+ });
+
+ afterEach(() => {
+ component.ngOnDestroy();
+ })
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+
+ it('node should be selected', fakeAsync(() => {
+ selectionEventSource.selected.next(new Rectangle(100, 100, 100, 100));
+ tick();
+ expect(manager.getSelected().length).toEqual(1);
+ }));
+
+ it('node should be selected and deselected', fakeAsync(() => {
+ selectionEventSource.selected.next(new Rectangle(100, 100, 100, 100));
+ tick();
+ selectionEventSource.selected.next(new Rectangle(350, 350, 100, 100));
+ tick();
+ expect(manager.getSelected().length).toEqual(0);
+ }));
+});
diff --git a/src/app/cartography/components/selection-control/selection-control.component.ts b/src/app/cartography/components/selection-control/selection-control.component.ts
new file mode 100644
index 00000000..6d603cd7
--- /dev/null
+++ b/src/app/cartography/components/selection-control/selection-control.component.ts
@@ -0,0 +1,62 @@
+import { Component, OnInit, OnDestroy } from '@angular/core';
+import { Subscription } from 'rxjs';
+import { SelectionEventSource } from '../../events/selection-event-source';
+import { GraphDataManager } from '../../managers/graph-data-manager';
+import { InRectangleHelper } from '../../helpers/in-rectangle-helper';
+import { SelectionManager } from '../../managers/selection-manager';
+import { Rectangle } from '../../models/rectangle';
+
+@Component({
+ selector: 'app-selection-control',
+ templateUrl: './selection-control.component.html',
+ styleUrls: ['./selection-control.component.scss']
+})
+export class SelectionControlComponent implements OnInit, OnDestroy {
+ private onSelection: Subscription;
+
+ constructor(
+ private selectionEventSource: SelectionEventSource,
+ private graphDataManager: GraphDataManager,
+ private inRectangleHelper: InRectangleHelper,
+ private selectionManager: SelectionManager
+ ) { }
+
+ ngOnInit() {
+ this.onSelection = this.selectionEventSource.selected.subscribe((rectangle: Rectangle) => {
+ const selectedNodes = this.graphDataManager.getNodes().filter((node) => {
+ return this.inRectangleHelper.inRectangle(rectangle, node.x, node.y)
+ });
+
+ const selectedLinks = this.graphDataManager.getLinks().filter((link) => {
+ return this.inRectangleHelper.inRectangle(rectangle, link.x, link.y)
+ });
+
+ const selectedDrawings = this.graphDataManager.getDrawings().filter((drawing) => {
+ return this.inRectangleHelper.inRectangle(rectangle, drawing.x, drawing.y)
+ });
+
+ const selectedLabels = this.graphDataManager.getNodes().filter((node) => {
+ if (node.label === undefined) {
+ return false;
+ }
+ const labelX = node.x + node.label.x;
+ const labelY = node.y + node.label.y;
+ return this.inRectangleHelper.inRectangle(rectangle, labelX, labelY);
+ }).map((node) => node.label);
+
+ const selected = [
+ ...selectedNodes,
+ ...selectedLinks,
+ ...selectedDrawings,
+ ...selectedLabels
+ ];
+
+ this.selectionManager.setSelected(selected);
+ });
+ }
+
+ ngOnDestroy() {
+ this.onSelection.unsubscribe();
+ }
+
+}
diff --git a/src/app/cartography/components/selection-select/selection-select.component.html b/src/app/cartography/components/selection-select/selection-select.component.html
new file mode 100644
index 00000000..e69de29b
diff --git a/src/app/cartography/components/selection-select/selection-select.component.scss b/src/app/cartography/components/selection-select/selection-select.component.scss
new file mode 100644
index 00000000..e69de29b
diff --git a/src/app/cartography/components/selection-select/selection-select.component.spec.ts b/src/app/cartography/components/selection-select/selection-select.component.spec.ts
new file mode 100644
index 00000000..3af1b594
--- /dev/null
+++ b/src/app/cartography/components/selection-select/selection-select.component.spec.ts
@@ -0,0 +1,25 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { SelectionSelectComponent } from './selection-select.component';
+
+describe('SelectionSelectComponent', () => {
+ let component: SelectionSelectComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ SelectionSelectComponent ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(SelectionSelectComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ // it('should create', () => {
+ // expect(component).toBeTruthy();
+ // });
+});
diff --git a/src/app/cartography/listeners/selection-update-listener.ts b/src/app/cartography/components/selection-select/selection-select.component.ts
similarity index 50%
rename from src/app/cartography/listeners/selection-update-listener.ts
rename to src/app/cartography/components/selection-select/selection-select.component.ts
index 8272c282..fffba5d7 100644
--- a/src/app/cartography/listeners/selection-update-listener.ts
+++ b/src/app/cartography/components/selection-select/selection-select.component.ts
@@ -1,21 +1,23 @@
-import { Injectable } from "@angular/core";
-import { Subscription } from "rxjs";
-import { MapChangeDetectorRef } from "../services/map-change-detector-ref";
-import { SelectionManager } from "../managers/selection-manager";
+import { Component, OnInit, OnDestroy } from '@angular/core';
+import { Subscription } from 'rxjs';
+import { SelectionManager } from '../../managers/selection-manager';
+import { MapChangeDetectorRef } from '../../services/map-change-detector-ref';
-
-@Injectable()
-export class SelectionUpdateListener {
+@Component({
+ selector: 'app-selection-select',
+ templateUrl: './selection-select.component.html',
+ styleUrls: ['./selection-select.component.scss']
+})
+export class SelectionSelectComponent implements OnInit, OnDestroy {
private onSelected: Subscription;
private onUnselected: Subscription;
-
+
constructor(
private selectionManager: SelectionManager,
private mapChangeDetectorRef: MapChangeDetectorRef
- ) {
- }
+ ) { }
- public onInit(svg: any) {
+ ngOnInit() {
this.onSelected = this.selectionManager.selected.subscribe(() => {
this.mapChangeDetectorRef.detectChanges();
});
@@ -24,8 +26,9 @@ export class SelectionUpdateListener {
});
}
- public onDestroy() {
+ ngOnDestroy() {
this.onSelected.unsubscribe();
this.onUnselected.unsubscribe();
}
-}
\ No newline at end of file
+
+}
diff --git a/src/app/cartography/components/selection/selection.component.html b/src/app/cartography/components/selection/selection.component.html
new file mode 100644
index 00000000..8dee5ced
--- /dev/null
+++ b/src/app/cartography/components/selection/selection.component.html
@@ -0,0 +1,10 @@
+
+
+
+
diff --git a/src/app/cartography/components/selection/selection.component.scss b/src/app/cartography/components/selection/selection.component.scss
new file mode 100644
index 00000000..e69de29b
diff --git a/src/app/cartography/components/selection/selection.component.spec.ts b/src/app/cartography/components/selection/selection.component.spec.ts
new file mode 100644
index 00000000..111505c9
--- /dev/null
+++ b/src/app/cartography/components/selection/selection.component.spec.ts
@@ -0,0 +1,25 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { SelectionComponent } from './selection.component';
+
+describe('SelectionComponent', () => {
+ let component: SelectionComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ SelectionComponent ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(SelectionComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ // it('should create', () => {
+ // expect(component).toBeTruthy();
+ // });
+});
diff --git a/src/app/cartography/components/selection/selection.component.ts b/src/app/cartography/components/selection/selection.component.ts
new file mode 100644
index 00000000..b9589b29
--- /dev/null
+++ b/src/app/cartography/components/selection/selection.component.ts
@@ -0,0 +1,122 @@
+import { Component, OnInit, Input, AfterViewInit, ChangeDetectorRef, Output, EventEmitter } from '@angular/core';
+import { Observable, Subscription, Subject } from 'rxjs';
+import { Rectangle } from '../../models/rectangle';
+
+@Component({
+ selector: '[app-selection]',
+ templateUrl: './selection.component.html',
+ styleUrls: ['./selection.component.scss']
+})
+export class SelectionComponent implements OnInit, AfterViewInit {
+ @Input('app-selection') svg: SVGSVGElement;
+
+ private startX: number;
+ private startY: number;
+
+ private width: number;
+ private height: number;
+
+ started = false;
+ visible = false;
+ draggable: Subscription;
+
+
+ @Output('selected') rectangleSelected = new EventEmitter();
+
+ constructor(
+ private ref: ChangeDetectorRef
+ ) { }
+
+ ngOnInit() {
+ }
+
+
+ ngAfterViewInit() {
+ const down = Observable.fromEvent(this.svg, 'mousedown').do((e: MouseEvent) => e.preventDefault());
+
+ down.subscribe((e: MouseEvent) => {
+ if(e.target !== this.svg) {
+ return;
+ }
+
+ this.started = true;
+ this.startX = e.clientX + window.scrollX;
+ this.startY = e.clientY + window.scrollY;
+ this.width = 0;
+ this.height = 0;
+ this.visible = true;
+ this.ref.detectChanges();
+ });
+
+ const up = Observable.fromEvent(document, 'mouseup')
+ .do((e: MouseEvent) => {
+ e.preventDefault();
+ });
+
+ const mouseMove = Observable.fromEvent(document, 'mousemove')
+ .do((e: MouseEvent) => e.stopPropagation());
+
+ const scrollWindow = Observable.fromEvent(document, 'scroll')
+ .startWith({});
+
+ const move = Observable.combineLatest(mouseMove, scrollWindow);
+
+ const drag = down.mergeMap((md: MouseEvent) => {
+ return move
+ .map(([mm, s]) => mm)
+ .do((mm: MouseEvent) => {
+ if(!this.started) {
+ return;
+ }
+ this.visible = true;
+ this.width = mm.clientX - this.startX + window.scrollX;
+ this.height = mm.clientY - this.startY + window.scrollY;
+
+ this.ref.detectChanges();
+
+ this.selectedEvent([this.startX, this.startY], [this.width, this.height]);
+ })
+ .skipUntil(up
+ .take(1)
+ .do((e: MouseEvent) => {
+ if(!this.started) {
+ return;
+ }
+ this.visible = false;
+ this.started = false;
+
+ this.width = e.clientX - this.startX + window.scrollX;
+ this.height = e.clientY - this.startY + window.scrollY;
+
+ this.ref.detectChanges();
+
+ this.selectedEvent([this.startX, this.startY], [this.width, this.height]);
+ }))
+ .take(1);
+ });
+
+ this.draggable = drag.subscribe((e: MouseEvent) => {
+ // this.cd.detectChanges();
+ });
+ }
+
+ ngOnDestroy() {
+ this.draggable.unsubscribe();
+ }
+
+ get d() {
+ return this.rect(this.startX, this.startY, this.width, this.height);
+ }
+
+ private rect(x: number, y: number, w: number, h: number) {
+ return "M" + [x, y] + " l" + [w, 0] + " l" + [0, h] + " l" + [-w, 0] + "z";
+ }
+
+ private selectedEvent(start, end) {
+ const x = Math.min(start[0], end[0]);
+ const y = Math.min(start[1], end[1]);
+ const width = Math.abs(start[0] - end[0]);
+ const height = Math.abs(start[1] - end[1]);
+ this.rectangleSelected.emit(new Rectangle(x, y, width, height));
+ }
+}
diff --git a/src/app/cartography/converters/map/label-to-map-label-converter.ts b/src/app/cartography/converters/map/label-to-map-label-converter.ts
index 0501978f..3f19485b 100644
--- a/src/app/cartography/converters/map/label-to-map-label-converter.ts
+++ b/src/app/cartography/converters/map/label-to-map-label-converter.ts
@@ -7,13 +7,17 @@ import { MapLabel } from "../../models/map/map-label";
@Injectable()
export class LabelToMapLabelConverter implements Converter