mirror of
https://github.com/GNS3/gns3-web-ui.git
synced 2024-12-23 14:52:22 +00:00
Merge branch 'master' into Fit-in-view-option
This commit is contained in:
commit
92b9163bf3
@ -1,5 +1,19 @@
|
||||
<svg #svg class="map" preserveAspectRatio="none" movingCanvas zoomingCanvas>
|
||||
<filter id="grayscale"><feColorMatrix id="feGrayscale" type="saturate" values="0" /></filter>
|
||||
<defs>
|
||||
<pattern id="gridDrawing" attr.width="{{project.drawing_grid_size}}" attr.height="{{project.drawing_grid_size}}" patternUnits="userSpaceOnUse">
|
||||
<path attr.d="M {{project.drawing_grid_size}} 0 L 0 0 0 {{project.drawing_grid_size}}" fill="none" stroke="silver" attr.stroke-width="{{gridVisibility}}"/>
|
||||
</pattern>
|
||||
</defs>
|
||||
|
||||
<defs>
|
||||
<pattern id="gridNode" attr.width="{{project.grid_size}}" attr.height="{{project.grid_size}}" patternUnits="userSpaceOnUse">
|
||||
<path attr.d="M {{project.grid_size}} 0 L 0 0 0 {{project.grid_size}}" fill="none" stroke="DarkSlateGray" attr.stroke-width="{{gridVisibility}}"/>
|
||||
</pattern>
|
||||
</defs>
|
||||
|
||||
<rect width="100%" height="100%" fill="url(#gridDrawing)" />
|
||||
<rect width="100%" height="100%" fill="url(#gridNode)" />
|
||||
</svg>
|
||||
|
||||
<app-drawing-adding [svg]="svg"></app-drawing-adding>
|
||||
|
Before Width: | Height: | Size: 517 B After Width: | Height: | Size: 1.3 KiB |
@ -32,6 +32,7 @@ import { Server } from '../../../models/server';
|
||||
import { ToolsService } from '../../../services/tools.service';
|
||||
import { TextEditorComponent } from '../text-editor/text-editor.component';
|
||||
import { MapScaleService } from '../../../services/mapScale.service';
|
||||
import { Project } from '../../../models/project';
|
||||
|
||||
@Component({
|
||||
selector: 'app-d3-map',
|
||||
@ -43,6 +44,7 @@ export class D3MapComponent implements OnInit, OnChanges, OnDestroy {
|
||||
@Input() links: Link[] = [];
|
||||
@Input() drawings: Drawing[] = [];
|
||||
@Input() symbols: Symbol[] = [];
|
||||
@Input() project: Project;
|
||||
@Input() server: Server;
|
||||
|
||||
@Input() width = 1500;
|
||||
@ -53,14 +55,13 @@ export class D3MapComponent implements OnInit, OnChanges, OnDestroy {
|
||||
|
||||
private parentNativeElement: any;
|
||||
private svg: Selection<SVGSVGElement, any, null, undefined>;
|
||||
|
||||
private onChangesDetected: Subscription;
|
||||
private subscriptions: Subscription[] = [];
|
||||
private drawLinkTool: boolean;
|
||||
|
||||
protected settings = {
|
||||
show_interface_labels: true
|
||||
};
|
||||
public gridVisibility: number = 0;
|
||||
|
||||
constructor(
|
||||
private graphDataManager: GraphDataManager,
|
||||
@ -142,6 +143,8 @@ export class D3MapComponent implements OnInit, OnChanges, OnDestroy {
|
||||
this.drawLinkTool = value;
|
||||
})
|
||||
);
|
||||
|
||||
this.gridVisibility = localStorage.getItem('gridVisibility') === 'true' ? 1 : 0;
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
|
@ -31,6 +31,7 @@ export class MapNodeToNodeConverter implements Converter<MapNode, Node> {
|
||||
node.status = mapNode.status;
|
||||
node.symbol = mapNode.symbol;
|
||||
node.symbol_url = mapNode.symbolUrl;
|
||||
node.usage = mapNode.usage;
|
||||
node.width = mapNode.width;
|
||||
node.x = mapNode.x;
|
||||
node.y = mapNode.y;
|
||||
|
@ -40,6 +40,7 @@ export class NodeToMapNodeConverter implements Converter<Node, MapNode> {
|
||||
mapNode.status = node.status;
|
||||
mapNode.symbol = node.symbol;
|
||||
mapNode.symbolUrl = node.symbol_url;
|
||||
mapNode.usage = node.usage;
|
||||
mapNode.width = node.width;
|
||||
mapNode.x = node.x;
|
||||
mapNode.y = node.y;
|
||||
|
@ -23,6 +23,7 @@ export class MapNode implements Indexed {
|
||||
status: string;
|
||||
symbol: string;
|
||||
symbolUrl: string;
|
||||
usage?: string;
|
||||
width: number;
|
||||
x: number;
|
||||
y: number;
|
||||
|
@ -82,6 +82,7 @@ export class Node {
|
||||
status: string;
|
||||
symbol: string;
|
||||
symbol_url: string; // @TODO: full URL to symbol, move to MapNode once converters are moved to app module
|
||||
usage?: string;
|
||||
width: number;
|
||||
x: number;
|
||||
y: number;
|
||||
|
@ -7,6 +7,7 @@ import { DraggedDataEvent } from '../../../cartography/events/event-source';
|
||||
import { MapDrawing } from '../../../cartography/models/map/map-drawing';
|
||||
import { Drawing } from '../../../cartography/models/drawing';
|
||||
import { DrawingsEventSource } from '../../../cartography/events/drawings-event-source';
|
||||
import { Project } from '../../../models/project';
|
||||
|
||||
@Component({
|
||||
selector: 'app-drawing-dragged',
|
||||
@ -15,6 +16,7 @@ import { DrawingsEventSource } from '../../../cartography/events/drawings-event-
|
||||
})
|
||||
export class DrawingDraggedComponent implements OnInit, OnDestroy {
|
||||
@Input() server: Server;
|
||||
@Input() project: Project;
|
||||
private drawingDragged: Subscription;
|
||||
|
||||
constructor(
|
||||
@ -33,7 +35,7 @@ export class DrawingDraggedComponent implements OnInit, OnDestroy {
|
||||
drawing.y += draggedEvent.dy;
|
||||
|
||||
this.drawingService
|
||||
.updatePosition(this.server, drawing, drawing.x, drawing.y)
|
||||
.updatePosition(this.server, this.project, drawing, drawing.x, drawing.y)
|
||||
.subscribe((serverDrawing: Drawing) => {
|
||||
this.drawingsDataSource.update(serverDrawing);
|
||||
});
|
||||
|
@ -7,6 +7,7 @@ import { Server } from '../../../models/server';
|
||||
import { NodesEventSource } from '../../../cartography/events/nodes-event-source';
|
||||
import { MapNode } from '../../../cartography/models/map/map-node';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { Project } from '../../../models/project';
|
||||
|
||||
@Component({
|
||||
selector: 'app-node-dragged',
|
||||
@ -15,6 +16,7 @@ import { Subscription } from 'rxjs';
|
||||
})
|
||||
export class NodeDraggedComponent implements OnInit, OnDestroy {
|
||||
@Input() server: Server;
|
||||
@Input() project: Project
|
||||
private nodeDragged: Subscription;
|
||||
|
||||
constructor(
|
||||
@ -32,7 +34,7 @@ export class NodeDraggedComponent implements OnInit, OnDestroy {
|
||||
node.x += draggedEvent.dx;
|
||||
node.y += draggedEvent.dy;
|
||||
|
||||
this.nodeService.updatePosition(this.server, node, node.x, node.y).subscribe((serverNode: Node) => {
|
||||
this.nodeService.updatePosition(this.server, this.project, node, node.x, node.y).subscribe((serverNode: Node) => {
|
||||
this.nodesDataSource.update(serverNode);
|
||||
});
|
||||
}
|
||||
|
@ -9,6 +9,11 @@
|
||||
</div>
|
||||
</div>
|
||||
</mat-tab>
|
||||
<mat-tab label="Usage instructions">
|
||||
<div class="textBox">
|
||||
{{usage}}
|
||||
</div>
|
||||
</mat-tab>
|
||||
<mat-tab label="Command line">
|
||||
<div class="textBox">
|
||||
{{commandLine}}
|
||||
|
@ -13,6 +13,7 @@ export class InfoDialogComponent implements OnInit {
|
||||
@Input() server: Server;
|
||||
@Input() node: Node;
|
||||
infoList: string[] = [];
|
||||
usage: string = '';
|
||||
commandLine: string = '';
|
||||
|
||||
constructor(
|
||||
@ -23,6 +24,7 @@ export class InfoDialogComponent implements OnInit {
|
||||
ngOnInit() {
|
||||
this.infoList = this.infoService.getInfoAboutNode(this.node, this.server);
|
||||
this.commandLine = this.infoService.getCommandLine(this.node);
|
||||
this.usage = this.node.usage ? this.node.usage : `No usage information has been provided for this node.`;
|
||||
}
|
||||
|
||||
onCloseClick() {
|
||||
|
@ -2,6 +2,7 @@
|
||||
<app-d3-map
|
||||
*ngIf="!settings.angular_map"
|
||||
[server]="server"
|
||||
[project]="project"
|
||||
[symbols]="symbols"
|
||||
[nodes]="nodes"
|
||||
[links]="links"
|
||||
@ -96,6 +97,12 @@
|
||||
</mat-checkbox>
|
||||
<mat-checkbox [ngModel]="layersVisibility" (change)="toggleLayers($event.checked)">
|
||||
Show layers
|
||||
</mat-checkbox><br/>
|
||||
<mat-checkbox [ngModel]="gridVisibility" (change)="toggleGrid($event.checked)">
|
||||
Show grid
|
||||
</mat-checkbox><br/>
|
||||
<mat-checkbox [ngModel]="project.snap_to_grid" (change)="toggleSnapToGrid($event.checked)">
|
||||
Snap to grid
|
||||
</mat-checkbox>
|
||||
</div>
|
||||
</mat-menu>
|
||||
@ -158,11 +165,11 @@
|
||||
<app-project-map-shortcuts *ngIf="project" [project]="project" [server]="server"></app-project-map-shortcuts>
|
||||
<app-draw-link-tool [links]="links" *ngIf="tools.draw_link"></app-draw-link-tool>
|
||||
|
||||
<app-drawing-dragged [server]="server"></app-drawing-dragged>
|
||||
<app-drawing-dragged [server]="server" [project]="project"></app-drawing-dragged>
|
||||
<app-drawing-resized [server]="server"></app-drawing-resized>
|
||||
<app-interface-label-dragged [server]="server"></app-interface-label-dragged>
|
||||
<app-link-created [server]="server" [project]="project"></app-link-created>
|
||||
<app-node-dragged [server]="server"></app-node-dragged>
|
||||
<app-node-dragged [server]="server" [project]="project"></app-node-dragged>
|
||||
<app-node-label-dragged [server]="server"></app-node-label-dragged>
|
||||
<app-text-added [server]="server" [project]="project" (drawingSaved)="onDrawingSaved()"> </app-text-added>
|
||||
<app-text-edited [server]="server"></app-text-edited>
|
||||
|
@ -144,7 +144,7 @@ export class MockedDrawingService {
|
||||
return of(drawing);
|
||||
}
|
||||
|
||||
updatePosition(_server: Server, _drawing: Drawing, _x: number, _y: number) {
|
||||
updatePosition(_server: Server, _project: Project, _drawing: Drawing, _x: number, _y: number) {
|
||||
return of(this.drawing);
|
||||
}
|
||||
|
||||
|
@ -84,6 +84,7 @@ export class ProjectMapComponent implements OnInit, OnDestroy {
|
||||
public isInterfaceLabelVisible: boolean = false;
|
||||
public notificationsVisibility: boolean = false;
|
||||
public layersVisibility: boolean = false;
|
||||
public gridVisibility: boolean = false;
|
||||
|
||||
tools = {
|
||||
selection: true,
|
||||
@ -240,6 +241,7 @@ export class ProjectMapComponent implements OnInit, OnDestroy {
|
||||
|
||||
this.notificationsVisibility = localStorage.getItem('notificationsVisibility') === 'true' ? true : false;
|
||||
this.layersVisibility = localStorage.getItem('layersVisibility') === 'true' ? true : false;
|
||||
this.gridVisibility = localStorage.getItem('gridVisibility') === 'true' ? true : false;
|
||||
this.addKeyboardListeners();
|
||||
}
|
||||
|
||||
@ -617,6 +619,20 @@ export class ProjectMapComponent implements OnInit, OnDestroy {
|
||||
this.mapChild.applyMapSettingsChanges();
|
||||
}
|
||||
|
||||
public toggleGrid(visible: boolean) {
|
||||
this.gridVisibility = visible;
|
||||
if (this.gridVisibility) {
|
||||
localStorage.setItem('gridVisibility', 'true');
|
||||
} else {
|
||||
localStorage.removeItem('gridVisibility');
|
||||
}
|
||||
this.mapChild.gridVisibility = this.gridVisibility ? 1 : 0;
|
||||
}
|
||||
|
||||
public toggleSnapToGrid(enabled: boolean) {
|
||||
this.project.snap_to_grid = enabled;
|
||||
}
|
||||
|
||||
private showMessage(msg) {
|
||||
if (this.notificationsVisibility) {
|
||||
if (msg.type === 'error') this.toasterService.error(msg.message);
|
||||
|
@ -8,17 +8,20 @@ import { Drawing } from '../cartography/models/drawing';
|
||||
import { getTestServer } from './testing';
|
||||
import { DrawingService } from './drawing.service';
|
||||
import { AppTestingModule } from '../testing/app-testing/app-testing.module';
|
||||
import { Project } from '../models/project';
|
||||
import { SvgToDrawingConverter } from '../cartography/helpers/svg-to-drawing-converter';
|
||||
|
||||
describe('DrawingService', () => {
|
||||
let httpClient: HttpClient;
|
||||
let httpTestingController: HttpTestingController;
|
||||
let httpServer: HttpServer;
|
||||
let server: Server;
|
||||
let project: Project = new Project();
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [HttpClientTestingModule, AppTestingModule],
|
||||
providers: [HttpServer, DrawingService]
|
||||
providers: [HttpServer, SvgToDrawingConverter, DrawingService]
|
||||
});
|
||||
|
||||
httpClient = TestBed.get(HttpClient);
|
||||
@ -40,7 +43,7 @@ describe('DrawingService', () => {
|
||||
drawing.project_id = 'myproject';
|
||||
drawing.drawing_id = 'id';
|
||||
|
||||
service.updatePosition(server, drawing, 10, 20).subscribe();
|
||||
service.updatePosition(server, project, drawing, 10, 20).subscribe();
|
||||
|
||||
const req = httpTestingController.expectOne('http://127.0.0.1:3080/v2/projects/myproject/drawings/id');
|
||||
expect(req.request.method).toEqual('PUT');
|
||||
@ -55,7 +58,7 @@ describe('DrawingService', () => {
|
||||
drawing.project_id = 'myproject';
|
||||
drawing.drawing_id = 'id';
|
||||
|
||||
service.updatePosition(server, drawing, 10.1, 20.6).subscribe();
|
||||
service.updatePosition(server, project, drawing, 10.1, 20.6).subscribe();
|
||||
|
||||
const req = httpTestingController.expectOne('http://127.0.0.1:3080/v2/projects/myproject/drawings/id');
|
||||
expect(req.request.method).toEqual('PUT');
|
||||
|
@ -5,10 +5,15 @@ import { Observable } from 'rxjs';
|
||||
import 'rxjs/add/operator/map';
|
||||
import { Server } from '../models/server';
|
||||
import { HttpServer } from './http-server.service';
|
||||
import { Project } from '../models/project';
|
||||
import { SvgToDrawingConverter } from '../cartography/helpers/svg-to-drawing-converter';
|
||||
|
||||
@Injectable()
|
||||
export class DrawingService {
|
||||
constructor(private httpServer: HttpServer) {}
|
||||
constructor(
|
||||
private httpServer: HttpServer,
|
||||
private svgToDrawingConverter: SvgToDrawingConverter
|
||||
) {}
|
||||
|
||||
add(server: Server, project_id: string, x: number, y: number, svg: string) {
|
||||
return this.httpServer.post<Drawing>(server, `/projects/${project_id}/drawings`, {
|
||||
@ -29,10 +34,23 @@ export class DrawingService {
|
||||
});
|
||||
}
|
||||
|
||||
updatePosition(server: Server, drawing: Drawing, x: number, y: number): Observable<Drawing> {
|
||||
updatePosition(server: Server, project: Project, drawing: Drawing, x: number, y: number): Observable<Drawing> {
|
||||
let xPosition: number = Math.round(x);
|
||||
let yPosition: number = Math.round(y);
|
||||
|
||||
if (project.snap_to_grid) {
|
||||
drawing.element = this.svgToDrawingConverter.convert(drawing.svg);
|
||||
|
||||
xPosition = Math.round((xPosition + drawing.element.width/2) / project.drawing_grid_size) * project.drawing_grid_size;
|
||||
yPosition = Math.round((yPosition + drawing.element.width/2) / project.drawing_grid_size) * project.drawing_grid_size;
|
||||
|
||||
xPosition = Math.round(xPosition - drawing.element.width/2);
|
||||
yPosition = Math.round(yPosition - drawing.element.height/2);
|
||||
}
|
||||
|
||||
return this.httpServer.put<Drawing>(server, `/projects/${drawing.project_id}/drawings/${drawing.drawing_id}`, {
|
||||
x: Math.round(x),
|
||||
y: Math.round(y)
|
||||
x: xPosition,
|
||||
y: yPosition
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -154,11 +154,14 @@ describe('NodeService', () => {
|
||||
}));
|
||||
|
||||
it('should updatePosition of node', inject([NodeService], (service: NodeService) => {
|
||||
let project = {
|
||||
project_id: '1'
|
||||
} as Project;
|
||||
const node = new Node();
|
||||
node.project_id = 'myproject';
|
||||
node.node_id = 'id';
|
||||
|
||||
service.updatePosition(server, node, 10, 20).subscribe();
|
||||
service.updatePosition(server, project, node, 10, 20).subscribe();
|
||||
|
||||
const req = httpTestingController.expectOne('http://127.0.0.1:3080/v2/projects/myproject/nodes/id');
|
||||
expect(req.request.method).toEqual('PUT');
|
||||
@ -169,11 +172,14 @@ describe('NodeService', () => {
|
||||
}));
|
||||
|
||||
it('should updatePosition of node and round to integer', inject([NodeService], (service: NodeService) => {
|
||||
let project = {
|
||||
project_id: '1'
|
||||
} as Project;
|
||||
const node = new Node();
|
||||
node.project_id = 'myproject';
|
||||
node.node_id = 'id';
|
||||
|
||||
service.updatePosition(server, node, 10.1, 20.6).subscribe();
|
||||
service.updatePosition(server, project, node, 10.1, 20.6).subscribe();
|
||||
|
||||
const req = httpTestingController.expectOne('http://127.0.0.1:3080/v2/projects/myproject/nodes/id');
|
||||
expect(req.request.method).toEqual('PUT');
|
||||
|
@ -53,10 +53,21 @@ export class NodeService {
|
||||
});
|
||||
}
|
||||
|
||||
updatePosition(server: Server, node: Node, x: number, y: number): Observable<Node> {
|
||||
updatePosition(server: Server, project: Project, node: Node, x: number, y: number): Observable<Node> {
|
||||
let xPosition: number = Math.round(x);
|
||||
let yPosition: number = Math.round(y);
|
||||
|
||||
if (project.snap_to_grid) {
|
||||
xPosition = Math.round((xPosition + node.width/2) / project.grid_size) * project.grid_size;
|
||||
yPosition = Math.round((yPosition + node.width/2) / project.grid_size) * project.grid_size;
|
||||
|
||||
xPosition = Math.round(xPosition - node.width/2);
|
||||
yPosition = Math.round(yPosition - node.height/2);
|
||||
}
|
||||
|
||||
return this.httpServer.put<Node>(server, `/projects/${node.project_id}/nodes/${node.node_id}`, {
|
||||
x: Math.round(x),
|
||||
y: Math.round(y)
|
||||
x: xPosition,
|
||||
y: yPosition
|
||||
});
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user