mirror of
https://github.com/GNS3/gns3-web-ui.git
synced 2025-05-16 23:42:51 +00:00
Initial implementation
This commit is contained in:
parent
dea0f58ea0
commit
f469a8dbe1
@ -72,6 +72,7 @@ import { SnapshotMenuItemComponent } from './components/snapshots/snapshot-menu-
|
|||||||
import { MATERIAL_IMPORTS } from './material.imports';
|
import { MATERIAL_IMPORTS } from './material.imports';
|
||||||
import { DrawingService } from './services/drawing.service';
|
import { DrawingService } from './services/drawing.service';
|
||||||
import { ProjectNameValidator } from './components/projects/models/projectNameValidator';
|
import { ProjectNameValidator } from './components/projects/models/projectNameValidator';
|
||||||
|
import { MatSidenavModule } from '@angular/material';
|
||||||
|
|
||||||
|
|
||||||
if (environment.production) {
|
if (environment.production) {
|
||||||
@ -128,6 +129,7 @@ if (environment.production) {
|
|||||||
PersistenceModule,
|
PersistenceModule,
|
||||||
NgxElectronModule,
|
NgxElectronModule,
|
||||||
FileUploadModule,
|
FileUploadModule,
|
||||||
|
MatSidenavModule,
|
||||||
MATERIAL_IMPORTS
|
MATERIAL_IMPORTS
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
|
@ -5,6 +5,7 @@ import { MatMenuModule, MatIconModule } from '@angular/material';
|
|||||||
import { MapComponent } from './components/map/map.component';
|
import { MapComponent } from './components/map/map.component';
|
||||||
import { DrawLinkToolComponent } from './components/draw-link-tool/draw-link-tool.component';
|
import { DrawLinkToolComponent } from './components/draw-link-tool/draw-link-tool.component';
|
||||||
import { NodeSelectInterfaceComponent } from './components/node-select-interface/node-select-interface.component';
|
import { NodeSelectInterfaceComponent } from './components/node-select-interface/node-select-interface.component';
|
||||||
|
import { DrawingResizingComponent } from './components/drawing-resizing/drawing-resizing.components';
|
||||||
|
|
||||||
import { CssFixer } from './helpers/css-fixer';
|
import { CssFixer } from './helpers/css-fixer';
|
||||||
import { FontFixer } from './helpers/font-fixer';
|
import { FontFixer } from './helpers/font-fixer';
|
||||||
@ -20,6 +21,7 @@ import { MapListeners } from './listeners/map-listeners';
|
|||||||
import { DraggableListener } from './listeners/draggable-listener';
|
import { DraggableListener } from './listeners/draggable-listener';
|
||||||
import { DrawingsEventSource } from './events/drawings-event-source';
|
import { DrawingsEventSource } from './events/drawings-event-source';
|
||||||
import { NodesEventSource } from './events/nodes-event-source';
|
import { NodesEventSource } from './events/nodes-event-source';
|
||||||
|
import { MapDrawingToSvgConverter } from './converters/map/map-drawing-to-svg-converter';
|
||||||
import { DrawingToMapDrawingConverter } from './converters/map/drawing-to-map-drawing-converter';
|
import { DrawingToMapDrawingConverter } from './converters/map/drawing-to-map-drawing-converter';
|
||||||
import { LabelToMapLabelConverter } from './converters/map/label-to-map-label-converter';
|
import { LabelToMapLabelConverter } from './converters/map/label-to-map-label-converter';
|
||||||
import { LinkToMapLinkConverter } from './converters/map/link-to-map-link-converter';
|
import { LinkToMapLinkConverter } from './converters/map/link-to-map-link-converter';
|
||||||
@ -50,7 +52,8 @@ import { LinksEventSource } from './events/links-event-source';
|
|||||||
declarations: [
|
declarations: [
|
||||||
MapComponent,
|
MapComponent,
|
||||||
DrawLinkToolComponent,
|
DrawLinkToolComponent,
|
||||||
NodeSelectInterfaceComponent
|
NodeSelectInterfaceComponent,
|
||||||
|
DrawingResizingComponent
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
CssFixer,
|
CssFixer,
|
||||||
@ -69,6 +72,7 @@ import { LinksEventSource } from './events/links-event-source';
|
|||||||
DrawingsEventSource,
|
DrawingsEventSource,
|
||||||
NodesEventSource,
|
NodesEventSource,
|
||||||
LinksEventSource,
|
LinksEventSource,
|
||||||
|
MapDrawingToSvgConverter,
|
||||||
DrawingToMapDrawingConverter,
|
DrawingToMapDrawingConverter,
|
||||||
LabelToMapLabelConverter,
|
LabelToMapLabelConverter,
|
||||||
LinkToMapLinkConverter,
|
LinkToMapLinkConverter,
|
||||||
|
@ -0,0 +1,42 @@
|
|||||||
|
import { Component, OnInit, ElementRef, OnDestroy, Input, Output, EventEmitter } from '@angular/core';
|
||||||
|
import { Subscription } from 'rxjs';
|
||||||
|
import { DrawingsEventSource } from '../../events/drawings-event-source';
|
||||||
|
import { select } from 'd3-selection';
|
||||||
|
import { DrawingsWidget } from '../../widgets/drawings';
|
||||||
|
import { MapDrawing } from '../../models/map/map-drawing';
|
||||||
|
import { DraggedDataEvent } from '../../events/event-source';
|
||||||
|
import { ResizingEnd } from '../../events/resizing';
|
||||||
|
|
||||||
|
export class DrawingResizedEvent{
|
||||||
|
constructor() {};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-drawing-resizing',
|
||||||
|
template: `<ng-content></ng-content>`,
|
||||||
|
styleUrls: ['./drawing-resizing.component.scss']
|
||||||
|
})
|
||||||
|
export class DrawingResizingComponent implements OnInit, OnDestroy{
|
||||||
|
private resizingFinished: Subscription;
|
||||||
|
|
||||||
|
@Input('svg') svg: SVGSVGElement;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private drawingsWidget: DrawingsWidget,
|
||||||
|
private drawingsEventSource: DrawingsEventSource
|
||||||
|
) {}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
const svg = select(this.svg);
|
||||||
|
|
||||||
|
this.resizingFinished = this.drawingsWidget.resizingFinished.subscribe((evt: ResizingEnd<MapDrawing>) => {
|
||||||
|
console.log("inside component");
|
||||||
|
this.drawingsEventSource.resized.emit(new DraggedDataEvent<MapDrawing>(evt.datum, evt.x, evt.y));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy() {
|
||||||
|
this.resizingFinished.unsubscribe();
|
||||||
|
}
|
||||||
|
}
|
@ -8,3 +8,4 @@
|
|||||||
</svg>
|
</svg>
|
||||||
|
|
||||||
<app-draw-link-tool *ngIf="drawLinkTool"></app-draw-link-tool>
|
<app-draw-link-tool *ngIf="drawLinkTool"></app-draw-link-tool>
|
||||||
|
<app-drawing-resizing></app-drawing-resizing>
|
Before Width: | Height: | Size: 235 B After Width: | Height: | Size: 281 B |
@ -12,6 +12,7 @@ import { InterfaceLabelWidget } from '../../widgets/interface-label';
|
|||||||
import { SelectionTool } from '../../tools/selection-tool';
|
import { SelectionTool } from '../../tools/selection-tool';
|
||||||
import { MovingTool } from '../../tools/moving-tool';
|
import { MovingTool } from '../../tools/moving-tool';
|
||||||
import { MapChangeDetectorRef } from '../../services/map-change-detector-ref';
|
import { MapChangeDetectorRef } from '../../services/map-change-detector-ref';
|
||||||
|
import { MapLinkCreated } from '../../events/links';
|
||||||
import { CanvasSizeDetector } from '../../helpers/canvas-size-detector';
|
import { CanvasSizeDetector } from '../../helpers/canvas-size-detector';
|
||||||
import { MapListeners } from '../../listeners/map-listeners';
|
import { MapListeners } from '../../listeners/map-listeners';
|
||||||
import { DrawingsWidget } from '../../widgets/drawings';
|
import { DrawingsWidget } from '../../widgets/drawings';
|
||||||
@ -20,6 +21,7 @@ import { Link } from '../../../models/link';
|
|||||||
import { Drawing } from '../../models/drawing';
|
import { Drawing } from '../../models/drawing';
|
||||||
import { Symbol } from '../../../models/symbol';
|
import { Symbol } from '../../../models/symbol';
|
||||||
import { GraphDataManager } from '../../managers/graph-data-manager';
|
import { GraphDataManager } from '../../managers/graph-data-manager';
|
||||||
|
import { DraggedDataEvent } from '../../events/event-source';
|
||||||
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@ -36,6 +38,10 @@ export class MapComponent implements OnInit, OnChanges, OnDestroy {
|
|||||||
@Input() width = 1500;
|
@Input() width = 1500;
|
||||||
@Input() height = 600;
|
@Input() height = 600;
|
||||||
|
|
||||||
|
@Output() nodeDragged = new EventEmitter<DraggedDataEvent<Node>>();
|
||||||
|
@Output() drawingDragged = new EventEmitter<DraggedDataEvent<Drawing>>();
|
||||||
|
@Output() onLinkCreated = new EventEmitter<MapLinkCreated>();
|
||||||
|
|
||||||
private parentNativeElement: any;
|
private parentNativeElement: any;
|
||||||
private svg: Selection<SVGSVGElement, any, null, undefined>;
|
private svg: Selection<SVGSVGElement, any, null, undefined>;
|
||||||
|
|
||||||
@ -83,6 +89,8 @@ export class MapComponent implements OnInit, OnChanges, OnDestroy {
|
|||||||
|
|
||||||
@Input('draw-link-tool') drawLinkTool: boolean;
|
@Input('draw-link-tool') drawLinkTool: boolean;
|
||||||
|
|
||||||
|
@Input('is-rectangle-chosen') isRectangleChosen: boolean;
|
||||||
|
|
||||||
@Input('readonly') set readonly(value) {
|
@Input('readonly') set readonly(value) {
|
||||||
this.nodesWidget.draggingEnabled = !value;
|
this.nodesWidget.draggingEnabled = !value;
|
||||||
this.drawingsWidget.draggingEnabled = !value;
|
this.drawingsWidget.draggingEnabled = !value;
|
||||||
@ -95,12 +103,16 @@ export class MapComponent implements OnInit, OnChanges, OnDestroy {
|
|||||||
(changes['drawings'] && !changes['drawings'].isFirstChange()) ||
|
(changes['drawings'] && !changes['drawings'].isFirstChange()) ||
|
||||||
(changes['nodes'] && !changes['nodes'].isFirstChange()) ||
|
(changes['nodes'] && !changes['nodes'].isFirstChange()) ||
|
||||||
(changes['links'] && !changes['links'].isFirstChange()) ||
|
(changes['links'] && !changes['links'].isFirstChange()) ||
|
||||||
(changes['symbols'] && !changes['symbols'].isFirstChange())
|
(changes['symbols'] && !changes['symbols'].isFirstChange() ||
|
||||||
|
(changes['isRectangleChosen'] && !changes['isRectangleChosen'].isFirstChange()))
|
||||||
) {
|
) {
|
||||||
if (this.svg.empty && !this.svg.empty()) {
|
if (this.svg.empty && !this.svg.empty()) {
|
||||||
if (changes['symbols']) {
|
if (changes['symbols']) {
|
||||||
this.onSymbolsChange(changes['symbols']);
|
this.onSymbolsChange(changes['symbols']);
|
||||||
}
|
}
|
||||||
|
if (changes['isRectangleChosen']){
|
||||||
|
this.onDrawingRectangleActive();
|
||||||
|
}
|
||||||
this.changeLayout();
|
this.changeLayout();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -156,10 +168,46 @@ export class MapComponent implements OnInit, OnChanges, OnDestroy {
|
|||||||
this.graphDataManager.setNodes(this.nodes);
|
this.graphDataManager.setNodes(this.nodes);
|
||||||
this.graphDataManager.setLinks(this.links);
|
this.graphDataManager.setLinks(this.links);
|
||||||
this.graphDataManager.setDrawings(this.drawings);
|
this.graphDataManager.setDrawings(this.drawings);
|
||||||
|
|
||||||
this.graphLayout.draw(this.svg, this.context);
|
this.graphLayout.draw(this.svg, this.context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private onDrawingRectangleActive(){
|
||||||
|
var map = document.getElementsByClassName('map')[0];
|
||||||
|
console.log(this.drawings);
|
||||||
|
|
||||||
|
map.addEventListener('click', (event: MouseEvent) => {
|
||||||
|
console.log(event);
|
||||||
|
|
||||||
|
this.svg.select('g.drawings')
|
||||||
|
.append<SVGElement>('g')
|
||||||
|
.attr("class", 'drawing')
|
||||||
|
.append<SVGGElement>('g')
|
||||||
|
.attr("class", 'drawing_body')
|
||||||
|
.attr('transform', `translate(${event.clientX-1000},${event.clientY-500}) rotate(0)`)
|
||||||
|
.append<SVGRectElement>('rect')
|
||||||
|
.attr('class', 'rect_element noselect')
|
||||||
|
.attr('fill', '#ffffff')
|
||||||
|
.attr('fill-opacity', '1')
|
||||||
|
.attr('stroke', '#000000')
|
||||||
|
.attr('stroke-width', 2)
|
||||||
|
.attr('width', 200)
|
||||||
|
.attr('height', 100);
|
||||||
|
|
||||||
|
let newRectangle = new Drawing;
|
||||||
|
/*drawing_id: string;
|
||||||
|
project_id: string;
|
||||||
|
rotation: number;
|
||||||
|
svg: string;
|
||||||
|
x: number;
|
||||||
|
y: number;
|
||||||
|
z: number;
|
||||||
|
is_selected = false;
|
||||||
|
element: DrawingElement;*/
|
||||||
|
|
||||||
|
//this.onRectangleCreated.emit(null);
|
||||||
|
}, {once : true});
|
||||||
|
}
|
||||||
|
|
||||||
@HostListener('window:resize', ['$event'])
|
@HostListener('window:resize', ['$event'])
|
||||||
onResize(event) {
|
onResize(event) {
|
||||||
this.changeLayout();
|
this.changeLayout();
|
||||||
|
@ -0,0 +1,15 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
|
||||||
|
import { Converter } from '../converter';
|
||||||
|
import { MapDrawing } from '../../models/map/map-drawing';
|
||||||
|
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class MapDrawingToSvgConverter implements Converter<MapDrawing, string> {
|
||||||
|
constructor(
|
||||||
|
) {}
|
||||||
|
|
||||||
|
convert(mapDrawing: MapDrawing) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
@ -6,4 +6,5 @@ import { MapDrawing } from "../models/map/map-drawing";
|
|||||||
@Injectable()
|
@Injectable()
|
||||||
export class DrawingsEventSource {
|
export class DrawingsEventSource {
|
||||||
public dragged = new EventEmitter<DraggedDataEvent<MapDrawing>>();
|
public dragged = new EventEmitter<DraggedDataEvent<MapDrawing>>();
|
||||||
|
public resized = new EventEmitter<DraggedDataEvent<MapDrawing>>();
|
||||||
}
|
}
|
||||||
|
@ -7,3 +7,13 @@ export class DataEventSource<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class DraggedDataEvent<T> extends DataEventSource<T> {}
|
export class DraggedDataEvent<T> extends DataEventSource<T> {}
|
||||||
|
|
||||||
|
export class ResizedDataEvent<T> {
|
||||||
|
constructor(
|
||||||
|
public datum: T,
|
||||||
|
public x: number,
|
||||||
|
public y: number,
|
||||||
|
public width: number,
|
||||||
|
public height: number) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
7
src/app/cartography/events/resizing.ts
Normal file
7
src/app/cartography/events/resizing.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
export class ResizingEnd<T> {
|
||||||
|
public datum: T;
|
||||||
|
public x: number;
|
||||||
|
public y: number;
|
||||||
|
public width: number;
|
||||||
|
public height: number;
|
||||||
|
}
|
@ -9,7 +9,9 @@ import { RectDrawingWidget } from "./drawings/rect-drawing";
|
|||||||
import { LineDrawingWidget } from "./drawings/line-drawing";
|
import { LineDrawingWidget } from "./drawings/line-drawing";
|
||||||
import { EllipseDrawingWidget } from "./drawings/ellipse-drawing";
|
import { EllipseDrawingWidget } from "./drawings/ellipse-drawing";
|
||||||
import { MapDrawing } from "../models/map/map-drawing";
|
import { MapDrawing } from "../models/map/map-drawing";
|
||||||
|
import { drag } from "d3-drag";
|
||||||
|
import { event } from "d3-selection";
|
||||||
|
import { SelectionManager } from "../managers/selection-manager";
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class DrawingWidget implements Widget {
|
export class DrawingWidget implements Widget {
|
||||||
@ -20,7 +22,8 @@ export class DrawingWidget implements Widget {
|
|||||||
private imageDrawingWidget: ImageDrawingWidget,
|
private imageDrawingWidget: ImageDrawingWidget,
|
||||||
private rectDrawingWidget: RectDrawingWidget,
|
private rectDrawingWidget: RectDrawingWidget,
|
||||||
private lineDrawingWidget: LineDrawingWidget,
|
private lineDrawingWidget: LineDrawingWidget,
|
||||||
private ellipseDrawingWidget: EllipseDrawingWidget
|
private ellipseDrawingWidget: EllipseDrawingWidget,
|
||||||
|
private selectionManager: SelectionManager
|
||||||
) {
|
) {
|
||||||
this.drawingWidgets = [
|
this.drawingWidgets = [
|
||||||
this.textDrawingWidget,
|
this.textDrawingWidget,
|
||||||
@ -33,17 +36,88 @@ export class DrawingWidget implements Widget {
|
|||||||
|
|
||||||
public draw(view: SVGSelection) {
|
public draw(view: SVGSelection) {
|
||||||
const drawing_body = view.selectAll<SVGGElement, MapDrawing>("g.drawing_body")
|
const drawing_body = view.selectAll<SVGGElement, MapDrawing>("g.drawing_body")
|
||||||
.data((l) => [l]);
|
.data((l:MapDrawing) => [l]);
|
||||||
|
|
||||||
const drawing_body_enter = drawing_body.enter()
|
const drawing_body_enter = drawing_body.enter()
|
||||||
.append<SVGGElement>('g')
|
.append<SVGGElement>('g')
|
||||||
.attr("class", "drawing_body");
|
.attr("class", "drawing_body")
|
||||||
|
|
||||||
|
drawing_body_enter
|
||||||
|
.append<SVGAElement>('line')
|
||||||
|
.attr("class", "top");
|
||||||
|
|
||||||
|
drawing_body_enter
|
||||||
|
.append<SVGAElement>('line')
|
||||||
|
.attr("class", "bottom");
|
||||||
|
|
||||||
|
drawing_body_enter
|
||||||
|
.append<SVGAElement>('line')
|
||||||
|
.attr("class", "right");
|
||||||
|
|
||||||
|
drawing_body_enter
|
||||||
|
.append<SVGAElement>('line')
|
||||||
|
.attr("class", "left");
|
||||||
|
|
||||||
const drawing_body_merge = drawing_body.merge(drawing_body_enter)
|
const drawing_body_merge = drawing_body.merge(drawing_body_enter)
|
||||||
.attr('transform', (d: MapDrawing) => {
|
.attr('transform', (d: MapDrawing) => {
|
||||||
return `translate(${d.x},${d.y}) rotate(${d.rotation})`;
|
return `translate(${d.x},${d.y}) rotate(${d.rotation})`;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
drawing_body_merge
|
||||||
|
.select<SVGAElement>('line.top')
|
||||||
|
.attr('stroke', 'transparent')
|
||||||
|
.attr('stroke-width', '8px')
|
||||||
|
// .attr('stroke-dashoffset', '0')
|
||||||
|
// .attr('stroke-dasharray', '3')
|
||||||
|
.attr('x1', '0')
|
||||||
|
.attr('x2', (drawing) => drawing.element.width)
|
||||||
|
.attr('y1', '0')
|
||||||
|
.attr('y2', '0')
|
||||||
|
.attr('draggable', 'true')
|
||||||
|
.attr("cursor", "ns-resize");
|
||||||
|
|
||||||
|
drawing_body_merge
|
||||||
|
.select<SVGAElement>('line.bottom')
|
||||||
|
.attr('stroke', 'transparent')
|
||||||
|
.attr('stroke-width', '8px')
|
||||||
|
// .attr('stroke-dashoffset', '0')
|
||||||
|
// .attr('stroke-dasharray', '3')
|
||||||
|
.attr('x1', '0')
|
||||||
|
.attr('x2', (drawing) => drawing.element.width)
|
||||||
|
.attr('y1', (drawing) => drawing.element.height)
|
||||||
|
.attr('y2', (drawing) => drawing.element.height)
|
||||||
|
.attr('draggable', 'true')
|
||||||
|
.attr("cursor", "ns-resize");
|
||||||
|
|
||||||
|
drawing_body_merge
|
||||||
|
.select<SVGAElement>('line.right')
|
||||||
|
.attr('stroke', 'transparent')
|
||||||
|
.attr('stroke-width', '8px')
|
||||||
|
// .attr('stroke-dashoffset', '0')
|
||||||
|
// .attr('stroke-dasharray', '3')
|
||||||
|
.attr('x1', '0')
|
||||||
|
.attr('x2', '0')
|
||||||
|
.attr('y1', '0')
|
||||||
|
.attr('y2', (drawing) => drawing.element.height)
|
||||||
|
.attr('draggable', 'true')
|
||||||
|
.attr("cursor", "ew-resize");
|
||||||
|
|
||||||
|
drawing_body_merge
|
||||||
|
.select<SVGAElement>('line.left')
|
||||||
|
.attr('stroke', 'transparent')
|
||||||
|
.attr('stroke-width', '8px')
|
||||||
|
// .attr('stroke-dashoffset', '0')
|
||||||
|
// .attr('stroke-dasharray', '3')
|
||||||
|
.attr('x1', (drawing) => drawing.element.width)
|
||||||
|
.attr('x2', (drawing) => drawing.element.width)
|
||||||
|
.attr('y1', '0')
|
||||||
|
.attr('y2', (drawing) => drawing.element.height)
|
||||||
|
.attr('draggable', 'true')
|
||||||
|
.attr("cursor", "ew-resize");
|
||||||
|
|
||||||
|
drawing_body_merge
|
||||||
|
.classed('selected', (n: MapDrawing) => this.selectionManager.isSelected(n));
|
||||||
|
|
||||||
this.drawingWidgets.forEach((widget) => {
|
this.drawingWidgets.forEach((widget) => {
|
||||||
widget.draw(drawing_body_merge);
|
widget.draw(drawing_body_merge);
|
||||||
});
|
});
|
||||||
|
@ -1,18 +1,24 @@
|
|||||||
import { Injectable } from "@angular/core";
|
import { Injectable, EventEmitter } from "@angular/core";
|
||||||
|
|
||||||
import { Widget } from "./widget";
|
import { Widget } from "./widget";
|
||||||
import { SVGSelection } from "../models/types";
|
import { SVGSelection } from "../models/types";
|
||||||
import { Layer } from "../models/layer";
|
import { Layer } from "../models/layer";
|
||||||
import { SvgToDrawingConverter } from "../helpers/svg-to-drawing-converter";
|
import { SvgToDrawingConverter } from "../helpers/svg-to-drawing-converter";
|
||||||
import { Draggable } from "../events/draggable";
|
import { Draggable, DraggableDrag, DraggableStart, DraggableEnd } from "../events/draggable";
|
||||||
import { DrawingWidget } from "./drawing";
|
import { DrawingWidget } from "./drawing";
|
||||||
|
import { drag, D3DragEvent } from "d3-drag";
|
||||||
|
import { event } from "d3-selection";
|
||||||
import { MapDrawing } from "../models/map/map-drawing";
|
import { MapDrawing } from "../models/map/map-drawing";
|
||||||
|
import { Context } from "../models/context";
|
||||||
|
import { EllipseElement } from "../models/drawings/ellipse-element";
|
||||||
|
import { ResizingEnd } from "../events/resizing";
|
||||||
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class DrawingsWidget implements Widget {
|
export class DrawingsWidget implements Widget {
|
||||||
public draggable = new Draggable<SVGGElement, MapDrawing>();
|
public draggable = new Draggable<SVGGElement, MapDrawing>();
|
||||||
public draggingEnabled = false;
|
public draggingEnabled = false;
|
||||||
|
public resizingFinished = new EventEmitter<ResizingEnd<MapDrawing>>();
|
||||||
|
|
||||||
// public onContextMenu = new EventEmitter<NodeContextMenu>();
|
// public onContextMenu = new EventEmitter<NodeContextMenu>();
|
||||||
// public onDrawingClicked = new EventEmitter<NodeClicked>();
|
// public onDrawingClicked = new EventEmitter<NodeClicked>();
|
||||||
@ -22,6 +28,7 @@ export class DrawingsWidget implements Widget {
|
|||||||
constructor(
|
constructor(
|
||||||
private drawingWidget: DrawingWidget,
|
private drawingWidget: DrawingWidget,
|
||||||
private svgToDrawingConverter: SvgToDrawingConverter,
|
private svgToDrawingConverter: SvgToDrawingConverter,
|
||||||
|
private context: Context
|
||||||
) {
|
) {
|
||||||
this.svgToDrawingConverter = new SvgToDrawingConverter();
|
this.svgToDrawingConverter = new SvgToDrawingConverter();
|
||||||
}
|
}
|
||||||
@ -62,6 +69,123 @@ export class DrawingsWidget implements Widget {
|
|||||||
if (this.draggingEnabled) {
|
if (this.draggingEnabled) {
|
||||||
this.draggable.call(merge);
|
this.draggable.call(merge);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let bottom = drag()
|
||||||
|
.on('start', (datum: MapDrawing) => {
|
||||||
|
document.body.style.cursor = "ns-resize";
|
||||||
|
})
|
||||||
|
.on('drag', (datum: MapDrawing) => {
|
||||||
|
const evt = event;
|
||||||
|
|
||||||
|
if (datum.element instanceof EllipseElement){
|
||||||
|
(datum.element as EllipseElement).cy = (datum.element as EllipseElement).cy + evt.dy/2 < 0 ? 1 : (datum.element as EllipseElement).cy += evt.dy/2;
|
||||||
|
(datum.element as EllipseElement).ry = (datum.element as EllipseElement).ry + evt.dy/2 < 0 ? 1 : (datum.element as EllipseElement).ry += evt.dy/2;
|
||||||
|
}
|
||||||
|
datum.element.height = (datum.element.height + evt.dy) < 0 ? 1: datum.element.height += evt.dy;
|
||||||
|
this.redrawDrawing(view, datum);
|
||||||
|
})
|
||||||
|
.on('end', (datum: MapDrawing) => {
|
||||||
|
document.body.style.cursor = "initial";
|
||||||
|
|
||||||
|
const evt = new ResizingEnd<MapDrawing>();
|
||||||
|
evt.x = datum.x;
|
||||||
|
evt.y = datum. y;
|
||||||
|
evt.width = datum.element.width;
|
||||||
|
evt.height = datum.element.height;
|
||||||
|
evt.datum = datum;
|
||||||
|
|
||||||
|
this.resizingFinished.emit(evt);
|
||||||
|
});
|
||||||
|
|
||||||
|
let y: number;
|
||||||
|
let dy: number;
|
||||||
|
let top = drag()
|
||||||
|
.on('start', () => {
|
||||||
|
y = event.sourceEvent.clientY - this.context.getZeroZeroTransformationPoint().y;
|
||||||
|
document.body.style.cursor = "ns-resize";
|
||||||
|
})
|
||||||
|
.on('drag', (datum: MapDrawing) => {
|
||||||
|
const evt = event;
|
||||||
|
dy = y - (evt.sourceEvent.clientY - this.context.getZeroZeroTransformationPoint().y);
|
||||||
|
y = evt.sourceEvent.clientY - this.context.getZeroZeroTransformationPoint().y;
|
||||||
|
|
||||||
|
if ((datum.element.height + dy) < 0){
|
||||||
|
datum.element.height = 1;
|
||||||
|
} else {
|
||||||
|
datum.y = evt.sourceEvent.clientY - this.context.getZeroZeroTransformationPoint().y;
|
||||||
|
datum.element.height += dy;
|
||||||
|
if (datum.element instanceof EllipseElement) {
|
||||||
|
(datum.element as EllipseElement).cy = (datum.element as EllipseElement).cy + dy/2 < 0 ? 1 : (datum.element as EllipseElement).cy += dy/2;
|
||||||
|
(datum.element as EllipseElement).ry = (datum.element as EllipseElement).ry + dy/2 < 0 ? 1 : (datum.element as EllipseElement).ry += dy/2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.redrawDrawing(view, datum);
|
||||||
|
})
|
||||||
|
.on('end', (datum: MapDrawing) => {
|
||||||
|
document.body.style.cursor = "initial";
|
||||||
|
});
|
||||||
|
|
||||||
|
let x: number;
|
||||||
|
let dx: number;
|
||||||
|
let right = drag()
|
||||||
|
.on('start', () => {
|
||||||
|
x = event.sourceEvent.clientX - this.context.getZeroZeroTransformationPoint().x;
|
||||||
|
document.body.style.cursor = "ew-resize";
|
||||||
|
})
|
||||||
|
.on('drag', (datum: MapDrawing) => {
|
||||||
|
const evt = event;
|
||||||
|
dx = x - (evt.sourceEvent.clientX - this.context.getZeroZeroTransformationPoint().x);
|
||||||
|
x = evt.sourceEvent.clientX - this.context.getZeroZeroTransformationPoint().x;
|
||||||
|
|
||||||
|
if ((datum.element.width + dx) < 0){
|
||||||
|
datum.element.width = 1;
|
||||||
|
} else {
|
||||||
|
datum.x = evt.sourceEvent.clientX - this.context.getZeroZeroTransformationPoint().x;
|
||||||
|
datum.element.width += dx;
|
||||||
|
if (datum.element instanceof EllipseElement) {
|
||||||
|
(datum.element as EllipseElement).cx = (datum.element as EllipseElement).cx + dx/2 < 0 ? 1 : (datum.element as EllipseElement).cx += dx/2;
|
||||||
|
(datum.element as EllipseElement).rx = (datum.element as EllipseElement).rx + dx/2 < 0 ? 1 : (datum.element as EllipseElement).rx += dx/2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.redrawDrawing(view, datum);
|
||||||
|
})
|
||||||
|
.on('end', (datum: MapDrawing) => {
|
||||||
|
document.body.style.cursor = "initial";
|
||||||
|
});
|
||||||
|
|
||||||
|
let left = drag()
|
||||||
|
.on('start', () => {
|
||||||
|
document.body.style.cursor = "ew-resize";
|
||||||
|
})
|
||||||
|
.on('drag', (datum: MapDrawing) => {
|
||||||
|
const evt = event;
|
||||||
|
|
||||||
|
if (datum.element instanceof EllipseElement){
|
||||||
|
(datum.element as EllipseElement).cx = (datum.element as EllipseElement).cx + evt.dx/2 < 0 ? 1 : (datum.element as EllipseElement).cx += evt.dx/2;
|
||||||
|
(datum.element as EllipseElement).rx = (datum.element as EllipseElement).rx + evt.dx/2 < 0 ? 1 : (datum.element as EllipseElement).rx += evt.dx/2;
|
||||||
|
}
|
||||||
|
datum.element.width = (datum.element.width + evt.dx) < 0 ? 1 : datum.element.width += evt.dx;
|
||||||
|
this.redrawDrawing(view, datum);
|
||||||
|
})
|
||||||
|
.on('end', (datum: MapDrawing) => {
|
||||||
|
document.body.style.cursor = "initial";
|
||||||
|
});
|
||||||
|
|
||||||
|
merge
|
||||||
|
.select<SVGAElement>('line.bottom')
|
||||||
|
.call(bottom);
|
||||||
|
|
||||||
|
merge
|
||||||
|
.select<SVGAElement>('line.top')
|
||||||
|
.call(top);
|
||||||
|
|
||||||
|
merge
|
||||||
|
.select<SVGAElement>('line.right')
|
||||||
|
.call(right);
|
||||||
|
|
||||||
|
merge
|
||||||
|
.select<SVGAElement>('line.left')
|
||||||
|
.call(left);
|
||||||
}
|
}
|
||||||
|
|
||||||
private selectDrawing(view: SVGSelection, drawing: MapDrawing) {
|
private selectDrawing(view: SVGSelection, drawing: MapDrawing) {
|
||||||
|
@ -18,6 +18,69 @@ g.node:hover {
|
|||||||
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
|
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.draw-menu{
|
||||||
|
position: fixed;
|
||||||
|
background: transparent;
|
||||||
|
top: 20px;
|
||||||
|
left: 92px;
|
||||||
|
width: 320px !important;
|
||||||
|
height: 72px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.draw-menu2{
|
||||||
|
position: fixed;
|
||||||
|
background: transparent;
|
||||||
|
top: 20px;
|
||||||
|
left: 92px;
|
||||||
|
width: 320px !important;
|
||||||
|
height: 72px !important;
|
||||||
|
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
|
||||||
|
}
|
||||||
|
|
||||||
|
.draw-menu button{
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.drawer-container{
|
||||||
|
height: 72px !important;
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.drawer{
|
||||||
|
width: 320px !important;
|
||||||
|
height: 72px !important;
|
||||||
|
background:#263238;
|
||||||
|
}
|
||||||
|
|
||||||
|
.drawer-content{
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.drawer-button{
|
||||||
|
height: 72px;
|
||||||
|
width: 64px!important;
|
||||||
|
background: #263238;
|
||||||
|
padding: 0;
|
||||||
|
border: none;
|
||||||
|
outline: none;
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.drawer-arrow-button{
|
||||||
|
width: 40px;
|
||||||
|
height: 72px;
|
||||||
|
padding-top: 16px;
|
||||||
|
background:#263238;
|
||||||
|
position: fixed;
|
||||||
|
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
|
||||||
|
}
|
||||||
|
|
||||||
|
.drawer-buttons{
|
||||||
|
background:#263238;
|
||||||
|
padding-top: 16px;
|
||||||
|
height: 72px;
|
||||||
|
}
|
||||||
|
|
||||||
.project-toolbar .mat-toolbar-multiple-rows {
|
.project-toolbar .mat-toolbar-multiple-rows {
|
||||||
width: auto !important;
|
width: auto !important;
|
||||||
}
|
}
|
||||||
@ -41,6 +104,10 @@ svg.map image:hover, svg.map image.chosen, g.selected {
|
|||||||
filter: url("#grayscale"); /* Chrome doesn't support CSS filters on SVG */
|
filter: url("#grayscale"); /* Chrome doesn't support CSS filters on SVG */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
g.selected line {
|
||||||
|
stroke: black;
|
||||||
|
}
|
||||||
|
|
||||||
path.selected {
|
path.selected {
|
||||||
stroke: darkred;
|
stroke: darkred;
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,11 @@
|
|||||||
[moving-tool]="tools.moving"
|
[moving-tool]="tools.moving"
|
||||||
[draw-link-tool]="tools.draw_link"
|
[draw-link-tool]="tools.draw_link"
|
||||||
[readonly]="inReadOnlyMode"
|
[readonly]="inReadOnlyMode"
|
||||||
|
[is-rectangle-chosen]="drawTools.isRectangleChosen"
|
||||||
|
(nodeDragged)="onNodeDragged($event)"
|
||||||
|
(drawingDragged)="onDrawingDragged($event)"
|
||||||
|
(onLinkCreated)="onLinkCreated($event)"
|
||||||
|
(onDrawingResized)="onDrawingResized($event)"
|
||||||
></app-map>
|
></app-map>
|
||||||
<div class="project-toolbar">
|
<div class="project-toolbar">
|
||||||
<mat-toolbar color="primary" class="project-toolbar">
|
<mat-toolbar color="primary" class="project-toolbar">
|
||||||
@ -77,6 +82,42 @@
|
|||||||
</mat-toolbar>
|
</mat-toolbar>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="draw-menu">
|
||||||
|
<mat-drawer-container class="drawer-container">
|
||||||
|
<mat-drawer #drawer class="drawer">
|
||||||
|
<div class="drawer-buttons">
|
||||||
|
<button mat-icon-button class="drawer-button">
|
||||||
|
<mat-icon>picture_in_picture</mat-icon>
|
||||||
|
</button>
|
||||||
|
<button mat-icon-button class="drawer-button" (click)="drawRectangle()">
|
||||||
|
<mat-icon>crop_3_2</mat-icon>
|
||||||
|
</button>
|
||||||
|
<button mat-icon-button class="drawer-button">
|
||||||
|
<mat-icon>panorama_fish_eye</mat-icon>
|
||||||
|
<!-- <svg height="72" width="64">
|
||||||
|
<circle cx="32" cy="36" r="20" stroke="white" stroke-width="2" fill="transparent"/>
|
||||||
|
</svg> -->
|
||||||
|
</button>
|
||||||
|
<button mat-icon-button class="drawer-button">
|
||||||
|
<svg height="40" width="40">
|
||||||
|
<line x1="30" y1="10" x2="10" y2="30" style="stroke:white;stroke-width:2" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
<button mat-icon-button class="drawer-arrow-button" (click)="drawer.toggle()">
|
||||||
|
<mat-icon>keyboard_arrow_left</mat-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</mat-drawer>
|
||||||
|
<mat-drawer-content class="drawer-content">
|
||||||
|
<div class="drawer-arrow-button">
|
||||||
|
<button mat-icon-button (click)="drawer.toggle()">
|
||||||
|
<mat-icon>keyboard_arrow_right</mat-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</mat-drawer-content>
|
||||||
|
</mat-drawer-container>
|
||||||
|
</div>
|
||||||
|
|
||||||
<app-node-context-menu [project]="project" [server]="server"></app-node-context-menu>
|
<app-node-context-menu [project]="project" [server]="server"></app-node-context-menu>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -37,6 +37,7 @@ import { MapNode } from '../../cartography/models/map/map-node';
|
|||||||
import { LinksEventSource } from '../../cartography/events/links-event-source';
|
import { LinksEventSource } from '../../cartography/events/links-event-source';
|
||||||
import { MapDrawing } from '../../cartography/models/map/map-drawing';
|
import { MapDrawing } from '../../cartography/models/map/map-drawing';
|
||||||
import { MapPortToPortConverter } from '../../cartography/converters/map/map-port-to-port-converter';
|
import { MapPortToPortConverter } from '../../cartography/converters/map/map-port-to-port-converter';
|
||||||
|
import { MapDrawingToSvgConverter } from '../../cartography/converters/map/map-drawing-to-svg-converter';
|
||||||
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@ -62,6 +63,10 @@ export class ProjectMapComponent implements OnInit, OnDestroy {
|
|||||||
'draw_link': false
|
'draw_link': false
|
||||||
};
|
};
|
||||||
|
|
||||||
|
protected drawTools = {
|
||||||
|
'isRectangleChosen': false
|
||||||
|
};
|
||||||
|
|
||||||
private inReadOnlyMode = false;
|
private inReadOnlyMode = false;
|
||||||
|
|
||||||
@ViewChild(MapComponent) mapChild: MapComponent;
|
@ViewChild(MapComponent) mapChild: MapComponent;
|
||||||
@ -89,7 +94,8 @@ export class ProjectMapComponent implements OnInit, OnDestroy {
|
|||||||
private drawingsDataSource: DrawingsDataSource,
|
private drawingsDataSource: DrawingsDataSource,
|
||||||
private nodesEventSource: NodesEventSource,
|
private nodesEventSource: NodesEventSource,
|
||||||
private drawingsEventSource: DrawingsEventSource,
|
private drawingsEventSource: DrawingsEventSource,
|
||||||
private linksEventSource: LinksEventSource
|
private linksEventSource: LinksEventSource,
|
||||||
|
private mapDrawingToSvgConverter: MapDrawingToSvgConverter
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
@ -164,6 +170,10 @@ export class ProjectMapComponent implements OnInit, OnDestroy {
|
|||||||
this.drawingsEventSource.dragged.subscribe((evt) => this.onDrawingDragged(evt))
|
this.drawingsEventSource.dragged.subscribe((evt) => this.onDrawingDragged(evt))
|
||||||
);
|
);
|
||||||
|
|
||||||
|
this.subscriptions.push(
|
||||||
|
this.drawingsEventSource.resized.subscribe((evt) => this.onDrawingResized(evt))
|
||||||
|
);
|
||||||
|
|
||||||
this.subscriptions.push(
|
this.subscriptions.push(
|
||||||
this.linksEventSource.created.subscribe((evt) => this.onLinkCreated(evt))
|
this.linksEventSource.created.subscribe((evt) => this.onLinkCreated(evt))
|
||||||
);
|
);
|
||||||
@ -272,6 +282,25 @@ export class ProjectMapComponent implements OnInit, OnDestroy {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private onDrawingResized(resizedEvent: DraggedDataEvent<MapDrawing>) {
|
||||||
|
console.log("ready to save");
|
||||||
|
|
||||||
|
const drawing = this.drawingsDataSource.get(resizedEvent.datum.id);
|
||||||
|
console.log(resizedEvent.datum.svg);
|
||||||
|
|
||||||
|
let svgString = this.mapDrawingToSvgConverter.convert(resizedEvent.datum);
|
||||||
|
console.log(resizedEvent.datum);
|
||||||
|
|
||||||
|
/*
|
||||||
|
this.drawingService
|
||||||
|
.updatePosition(this.server, drawing, drawing.x, drawing.y)
|
||||||
|
.subscribe((serverDrawing: Drawing) => {
|
||||||
|
//this.drawingsDataSource.update(serverDrawing);
|
||||||
|
//<svg height="100" width="198"><rect fill="#ffffff" fill-opacity="1.0" height="100" stroke="#000000" stroke-width="2" width="198" /></svg>
|
||||||
|
console.log(serverDrawing.svg);
|
||||||
|
});*/
|
||||||
|
}
|
||||||
|
|
||||||
public set readonly(value) {
|
public set readonly(value) {
|
||||||
this.inReadOnlyMode = value;
|
this.inReadOnlyMode = value;
|
||||||
if (value) {
|
if (value) {
|
||||||
@ -296,10 +325,18 @@ export class ProjectMapComponent implements OnInit, OnDestroy {
|
|||||||
this.tools.draw_link = !this.tools.draw_link;
|
this.tools.draw_link = !this.tools.draw_link;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public onRectangleCreated(rectangleCreated: any) {
|
||||||
|
this.drawTools.isRectangleChosen = false;
|
||||||
|
}
|
||||||
|
|
||||||
public toggleShowInterfaceLabels(enabled: boolean) {
|
public toggleShowInterfaceLabels(enabled: boolean) {
|
||||||
this.project.show_interface_labels = enabled;
|
this.project.show_interface_labels = enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public drawRectangle() {
|
||||||
|
this.drawTools.isRectangleChosen = !this.drawTools.isRectangleChosen;
|
||||||
|
}
|
||||||
|
|
||||||
public ngOnDestroy() {
|
public ngOnDestroy() {
|
||||||
this.drawingsDataSource.clear();
|
this.drawingsDataSource.clear();
|
||||||
this.nodesDataSource.clear();
|
this.nodesDataSource.clear();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user