Code optimization

This commit is contained in:
piotrpekala7
2021-04-12 13:15:45 +02:00
parent 1dc4887071
commit bba7d8b221
730 changed files with 21307 additions and 19956 deletions

View File

@ -1,5 +1,5 @@
import { TestHelper } from "./common.po" import { TestHelper } from './common.po';
import { browser, by } from "protractor"; import { browser, by } from 'protractor';
export class ProjectMapPage { export class ProjectMapPage {
helper = new TestHelper(); helper = new TestHelper();

View File

@ -1,5 +1,5 @@
import { TestHelper } from "./common.po" import { TestHelper } from './common.po';
import { browser, by } from "protractor"; import { browser, by } from 'protractor';
export class ProjectsPage { export class ProjectsPage {
helper = new TestHelper(); helper = new TestHelper();

View File

@ -2,7 +2,7 @@ import { browser, by, element } from 'protractor';
import { TestHelper } from './common.po'; import { TestHelper } from './common.po';
export class ServersPage { export class ServersPage {
helper = new TestHelper; helper = new TestHelper();
maximizeWindow() { maximizeWindow() {
browser.driver.manage().window().maximize(); browser.driver.manage().window().maximize();
@ -32,7 +32,7 @@ export class ServersPage {
this.helper.sleep(2000); this.helper.sleep(2000);
let hyperlinks = await browser.driver.findElements(by.css('a.table-link')); let hyperlinks = await browser.driver.findElements(by.css('a.table-link'));
let serverLink; let serverLink;
await this.helper.asyncForEach(hyperlinks, async element => { await this.helper.asyncForEach(hyperlinks, async (element) => {
let text = await element.getText(); let text = await element.getText();
if (text === '127.0.0.1') serverLink = element; if (text === '127.0.0.1') serverLink = element;
}); });

View File

@ -33,7 +33,7 @@ describe('Servers page', () => {
// act // act
let firstRowOfServersTable = await page.checkServersTable(); let firstRowOfServersTable = await page.checkServersTable();
let serverData = []; let serverData = [];
await helper.asyncForEach(firstRowOfServersTable, async element => { await helper.asyncForEach(firstRowOfServersTable, async (element) => {
serverData.push(await element.getText()); serverData.push(await element.getText());
}); });

View File

@ -77,7 +77,7 @@ const routes: Routes = [
{ {
path: 'server/:server_id/projects', path: 'server/:server_id/projects',
component: ProjectsComponent, component: ProjectsComponent,
resolve: { server : ServerResolve } resolve: { server: ServerResolve },
}, },
{ path: 'help', component: HelpComponent }, { path: 'help', component: HelpComponent },
{ path: 'help/reportissue', component: ReportIssueComponent }, { path: 'help/reportissue', component: ReportIssueComponent },
@ -86,54 +86,87 @@ const routes: Routes = [
{ path: 'installed-software', component: InstalledSoftwareComponent }, { path: 'installed-software', component: InstalledSoftwareComponent },
{ path: 'server/:server_id/systemstatus', component: SystemStatusComponent }, { path: 'server/:server_id/systemstatus', component: SystemStatusComponent },
{ path: 'server/:server_ip/:server_port/project/:project_id', component: DirectLinkComponent}, { path: 'server/:server_ip/:server_port/project/:project_id', component: DirectLinkComponent },
{ {
path: 'server/:server_id/project/:project_id/snapshots', path: 'server/:server_id/project/:project_id/snapshots',
component: ListOfSnapshotsComponent, component: ListOfSnapshotsComponent,
resolve: { server : ServerResolve } resolve: { server: ServerResolve },
}, },
{ path: 'server/:server_id/preferences', component: PreferencesComponent }, { path: 'server/:server_id/preferences', component: PreferencesComponent },
{ path: 'server/:server_id/preferences/gns3vm', component: Gns3vmComponent }, { path: 'server/:server_id/preferences/gns3vm', component: Gns3vmComponent },
// { path: 'server/:server_id/preferences/general', component: GeneralPreferencesComponent }, // { path: 'server/:server_id/preferences/general', component: GeneralPreferencesComponent },
{ path: 'server/:server_id/preferences/builtin', component: BuiltInPreferencesComponent}, { path: 'server/:server_id/preferences/builtin', component: BuiltInPreferencesComponent },
{ path: 'server/:server_id/preferences/builtin/ethernet-hubs', component: EthernetHubsTemplatesComponent }, { path: 'server/:server_id/preferences/builtin/ethernet-hubs', component: EthernetHubsTemplatesComponent },
{ path: 'server/:server_id/preferences/builtin/ethernet-hubs/addtemplate', component: EthernetHubsAddTemplateComponent }, {
{ path: 'server/:server_id/preferences/builtin/ethernet-hubs/:template_id', component: EthernetHubsTemplateDetailsComponent }, path: 'server/:server_id/preferences/builtin/ethernet-hubs/addtemplate',
component: EthernetHubsAddTemplateComponent,
},
{
path: 'server/:server_id/preferences/builtin/ethernet-hubs/:template_id',
component: EthernetHubsTemplateDetailsComponent,
},
{ path: 'server/:server_id/preferences/builtin/ethernet-switches', component: EthernetSwitchesTemplatesComponent }, {
{ path: 'server/:server_id/preferences/builtin/ethernet-switches/addtemplate', component: EthernetSwitchesAddTemplateComponent }, path: 'server/:server_id/preferences/builtin/ethernet-switches',
{ path: 'server/:server_id/preferences/builtin/ethernet-switches/:template_id', component: EthernetSwitchesTemplateDetailsComponent }, component: EthernetSwitchesTemplatesComponent,
},
{
path: 'server/:server_id/preferences/builtin/ethernet-switches/addtemplate',
component: EthernetSwitchesAddTemplateComponent,
},
{
path: 'server/:server_id/preferences/builtin/ethernet-switches/:template_id',
component: EthernetSwitchesTemplateDetailsComponent,
},
{ path: 'server/:server_id/preferences/builtin/cloud-nodes', component: CloudNodesTemplatesComponent }, { path: 'server/:server_id/preferences/builtin/cloud-nodes', component: CloudNodesTemplatesComponent },
{ path: 'server/:server_id/preferences/builtin/cloud-nodes/addtemplate', component: CloudNodesAddTemplateComponent }, {
{ path: 'server/:server_id/preferences/builtin/cloud-nodes/:template_id', component: CloudNodesTemplateDetailsComponent }, path: 'server/:server_id/preferences/builtin/cloud-nodes/addtemplate',
component: CloudNodesAddTemplateComponent,
},
{
path: 'server/:server_id/preferences/builtin/cloud-nodes/:template_id',
component: CloudNodesTemplateDetailsComponent,
},
//{ path: 'server/:server_id/preferences/dynamips', component: DynamipsPreferencesComponent }, //{ path: 'server/:server_id/preferences/dynamips', component: DynamipsPreferencesComponent },
{ path: 'server/:server_id/preferences/dynamips/templates', component: IosTemplatesComponent }, { path: 'server/:server_id/preferences/dynamips/templates', component: IosTemplatesComponent },
{ path: 'server/:server_id/preferences/dynamips/templates/addtemplate', component: AddIosTemplateComponent }, { path: 'server/:server_id/preferences/dynamips/templates/addtemplate', component: AddIosTemplateComponent },
{ path: 'server/:server_id/preferences/dynamips/templates/:template_id', component: IosTemplateDetailsComponent }, { path: 'server/:server_id/preferences/dynamips/templates/:template_id', component: IosTemplateDetailsComponent },
{ path: 'server/:server_id/preferences/dynamips/templates/:template_id/copy', component: CopyIosTemplateComponent }, {
path: 'server/:server_id/preferences/dynamips/templates/:template_id/copy',
component: CopyIosTemplateComponent,
},
// { path: 'server/:server_id/preferences/qemu', component: QemuPreferencesComponent }, // { path: 'server/:server_id/preferences/qemu', component: QemuPreferencesComponent },
{ path: 'server/:server_id/preferences/qemu/templates', component: QemuVmTemplatesComponent }, { path: 'server/:server_id/preferences/qemu/templates', component: QemuVmTemplatesComponent },
{ path: 'server/:server_id/preferences/qemu/templates/:template_id/copy', component: CopyQemuVmTemplateComponent }, {
path: 'server/:server_id/preferences/qemu/templates/:template_id/copy',
component: CopyQemuVmTemplateComponent,
},
{ path: 'server/:server_id/preferences/qemu/templates/:template_id', component: QemuVmTemplateDetailsComponent }, { path: 'server/:server_id/preferences/qemu/templates/:template_id', component: QemuVmTemplateDetailsComponent },
{ path: 'server/:server_id/preferences/qemu/addtemplate', component: AddQemuVmTemplateComponent }, { path: 'server/:server_id/preferences/qemu/addtemplate', component: AddQemuVmTemplateComponent },
// { path: 'server/:server_id/preferences/vpcs', component: VpcsPreferencesComponent }, // { path: 'server/:server_id/preferences/vpcs', component: VpcsPreferencesComponent },
{ path: 'server/:server_id/preferences/vpcs/templates', component: VpcsTemplatesComponent }, { path: 'server/:server_id/preferences/vpcs/templates', component: VpcsTemplatesComponent },
{ path: 'server/:server_id/preferences/vpcs/templates/:template_id', component: VpcsTemplateDetailsComponent}, { path: 'server/:server_id/preferences/vpcs/templates/:template_id', component: VpcsTemplateDetailsComponent },
{ path: 'server/:server_id/preferences/vpcs/addtemplate', component: AddVpcsTemplateComponent }, { path: 'server/:server_id/preferences/vpcs/addtemplate', component: AddVpcsTemplateComponent },
// { path: 'server/:server_id/preferences/virtualbox', component: VirtualBoxPreferencesComponent }, // { path: 'server/:server_id/preferences/virtualbox', component: VirtualBoxPreferencesComponent },
{ path: 'server/:server_id/preferences/virtualbox/templates', component: VirtualBoxTemplatesComponent }, { path: 'server/:server_id/preferences/virtualbox/templates', component: VirtualBoxTemplatesComponent },
{ path: 'server/:server_id/preferences/virtualbox/templates/:template_id', component: VirtualBoxTemplateDetailsComponent }, {
path: 'server/:server_id/preferences/virtualbox/templates/:template_id',
component: VirtualBoxTemplateDetailsComponent,
},
{ path: 'server/:server_id/preferences/virtualbox/addtemplate', component: AddVirtualBoxTemplateComponent }, { path: 'server/:server_id/preferences/virtualbox/addtemplate', component: AddVirtualBoxTemplateComponent },
// { path: 'server/:server_id/preferences/vmware', component: VmwarePreferencesComponent }, // { path: 'server/:server_id/preferences/vmware', component: VmwarePreferencesComponent },
{ path: 'server/:server_id/preferences/vmware/templates', component: VmwareTemplatesComponent }, { path: 'server/:server_id/preferences/vmware/templates', component: VmwareTemplatesComponent },
{ path: 'server/:server_id/preferences/vmware/templates/:template_id', component: VmwareTemplateDetailsComponent }, {
path: 'server/:server_id/preferences/vmware/templates/:template_id',
component: VmwareTemplateDetailsComponent,
},
{ path: 'server/:server_id/preferences/vmware/addtemplate', component: AddVmwareTemplateComponent }, { path: 'server/:server_id/preferences/vmware/addtemplate', component: AddVmwareTemplateComponent },
// { path: 'server/:server_id/preferences/traceng', component: TracengPreferencesComponent }, // { path: 'server/:server_id/preferences/traceng', component: TracengPreferencesComponent },
@ -142,37 +175,49 @@ const routes: Routes = [
// { path: 'server/:server_id/preferences/traceng/addtemplate', component: AddTracengTemplateComponent }, // { path: 'server/:server_id/preferences/traceng/addtemplate', component: AddTracengTemplateComponent },
{ path: 'server/:server_id/preferences/docker/templates', component: DockerTemplatesComponent }, { path: 'server/:server_id/preferences/docker/templates', component: DockerTemplatesComponent },
{ path: 'server/:server_id/preferences/docker/templates/:template_id', component: DockerTemplateDetailsComponent }, {
{ path: 'server/:server_id/preferences/docker/templates/:template_id/copy', component: CopyDockerTemplateComponent }, path: 'server/:server_id/preferences/docker/templates/:template_id',
component: DockerTemplateDetailsComponent,
},
{
path: 'server/:server_id/preferences/docker/templates/:template_id/copy',
component: CopyDockerTemplateComponent,
},
{ path: 'server/:server_id/preferences/docker/addtemplate', component: AddDockerTemplateComponent }, { path: 'server/:server_id/preferences/docker/addtemplate', component: AddDockerTemplateComponent },
{ path: 'server/:server_id/preferences/iou/templates', component: IouTemplatesComponent }, { path: 'server/:server_id/preferences/iou/templates', component: IouTemplatesComponent },
{ path: 'server/:server_id/preferences/iou/templates/:template_id', component: IouTemplateDetailsComponent }, { path: 'server/:server_id/preferences/iou/templates/:template_id', component: IouTemplateDetailsComponent },
{ path: 'server/:server_id/preferences/iou/templates/:template_id/copy', component: CopyIouTemplateComponent }, { path: 'server/:server_id/preferences/iou/templates/:template_id/copy', component: CopyIouTemplateComponent },
{ path: 'server/:server_id/preferences/iou/addtemplate', component: AddIouTemplateComponent } { path: 'server/:server_id/preferences/iou/addtemplate', component: AddIouTemplateComponent },
] ],
}, },
{ {
path: 'server/:server_id/project/:project_id', path: 'server/:server_id/project/:project_id',
component: ProjectMapComponent, component: ProjectMapComponent,
canDeactivate: [ConsoleGuard] canDeactivate: [ConsoleGuard],
}, },
{ {
path: 'server/:server_id/project/:project_id/nodes/:node_id', path: 'server/:server_id/project/:project_id/nodes/:node_id',
component: WebConsoleFullWindowComponent component: WebConsoleFullWindowComponent,
}, },
{ {
path: 'static/web-ui/server/:server_id/project/:project_id/nodes/:node_id', path: 'static/web-ui/server/:server_id/project/:project_id/nodes/:node_id',
component: WebConsoleFullWindowComponent component: WebConsoleFullWindowComponent,
}, },
{ {
path: '**', path: '**',
component: PageNotFoundComponent component: PageNotFoundComponent,
} },
]; ];
@NgModule({ @NgModule({
imports: [RouterModule.forRoot(routes, { anchorScrolling: 'enabled', enableTracing: false, scrollPositionRestoration: 'enabled'})], imports: [
exports: [RouterModule] RouterModule.forRoot(routes, {
anchorScrolling: 'enabled',
enableTracing: false,
scrollPositionRestoration: 'enabled',
}),
],
exports: [RouterModule],
}) })
export class AppRoutingModule {} export class AppRoutingModule {}

View File

@ -1,4 +1,4 @@
<div [ngClass]="{dark: darkThemeEnabled, light: !darkThemeEnabled}"> <div [ngClass]="{ dark: darkThemeEnabled, light: !darkThemeEnabled }">
<router-outlet></router-outlet> <router-outlet></router-outlet>
<app-adbutler></app-adbutler> <app-adbutler></app-adbutler>
</div> </div>

View File

@ -3,9 +3,9 @@ mat-menu-panel {
} }
.dark { .dark {
background: #263238!important; background: #263238 !important;
} }
.light { .light {
background: white!important; background: white !important;
} }

View File

@ -22,7 +22,7 @@ describe('AppComponent', () => {
declarations: [AppComponent], declarations: [AppComponent],
imports: [RouterTestingModule, MatIconModule, NgxElectronModule], imports: [RouterTestingModule, MatIconModule, NgxElectronModule],
providers: [SettingsService, PersistenceService, ProgressService], providers: [SettingsService, PersistenceService, ProgressService],
schemas: [NO_ERRORS_SCHEMA] schemas: [NO_ERRORS_SCHEMA],
}).compileComponents(); }).compileComponents();
electronService = TestBed.get(ElectronService); electronService = TestBed.get(ElectronService);

View File

@ -6,12 +6,12 @@ import { SettingsService } from './services/settings.service';
import { ThemeService } from './services/theme.service'; import { ThemeService } from './services/theme.service';
import { Router, NavigationStart, NavigationEnd, NavigationCancel, NavigationError } from '@angular/router'; import { Router, NavigationStart, NavigationEnd, NavigationCancel, NavigationError } from '@angular/router';
import { ProgressService } from './common/progress/progress.service'; import { ProgressService } from './common/progress/progress.service';
import { OverlayContainer} from '@angular/cdk/overlay'; import { OverlayContainer } from '@angular/cdk/overlay';
@Component({ @Component({
selector: 'app-root', selector: 'app-root',
templateUrl: './app.component.html', templateUrl: './app.component.html',
styleUrls: ['./app.component.scss'] styleUrls: ['./app.component.scss'],
}) })
export class AppComponent implements OnInit { export class AppComponent implements OnInit {
public darkThemeEnabled: boolean = false; public darkThemeEnabled: boolean = false;
@ -38,7 +38,7 @@ export class AppComponent implements OnInit {
ngOnInit(): void { ngOnInit(): void {
if (this.electronService.isElectronApp) { if (this.electronService.isElectronApp) {
this.settingsService.subscribe(settings => { this.settingsService.subscribe((settings) => {
this.electronService.ipcRenderer.send('settings.changed', settings); this.electronService.ipcRenderer.send('settings.changed', settings);
}); });
} }
@ -59,14 +59,14 @@ export class AppComponent implements OnInit {
this.componentCssClass = theme; this.componentCssClass = theme;
} }
checkEvent(routerEvent) : void { checkEvent(routerEvent): void {
if (routerEvent instanceof NavigationStart) { if (routerEvent instanceof NavigationStart) {
this.progressService.activate(); this.progressService.activate();
} } else if (
routerEvent instanceof NavigationEnd ||
else if (routerEvent instanceof NavigationEnd ||
routerEvent instanceof NavigationCancel || routerEvent instanceof NavigationCancel ||
routerEvent instanceof NavigationError) { routerEvent instanceof NavigationError
) {
this.progressService.deactivate(); this.progressService.deactivate();
} }
} }

View File

@ -470,7 +470,7 @@ import { OverlayContainer, OverlayModule } from '@angular/cdk/overlay';
TemplateNameDialogComponent, TemplateNameDialogComponent,
ConfigureCustomAdaptersDialogComponent, ConfigureCustomAdaptersDialogComponent,
EditNetworkConfigurationDialogComponent, EditNetworkConfigurationDialogComponent,
ReportIssueComponent ReportIssueComponent,
], ],
imports: [ imports: [
AngularReactBrowserModule, AngularReactBrowserModule,
@ -492,7 +492,7 @@ import { OverlayContainer, OverlayModule } from '@angular/cdk/overlay';
NgxChildProcessModule, NgxChildProcessModule,
MATERIAL_IMPORTS, MATERIAL_IMPORTS,
NgCircleProgressModule.forRoot(), NgCircleProgressModule.forRoot(),
OverlayModule OverlayModule,
], ],
providers: [ providers: [
SettingsService, SettingsService,
@ -567,7 +567,7 @@ import { OverlayContainer, OverlayModule } from '@angular/cdk/overlay';
ConsoleGuard, ConsoleGuard,
Title, Title,
ApplianceService, ApplianceService,
UpdatesService UpdatesService,
], ],
entryComponents: [ entryComponents: [
AddServerDialogComponent, AddServerDialogComponent,
@ -615,10 +615,10 @@ import { OverlayContainer, OverlayModule } from '@angular/cdk/overlay';
ChangeHostnameDialogComponent, ChangeHostnameDialogComponent,
ApplianceInfoDialogComponent, ApplianceInfoDialogComponent,
ConfigureCustomAdaptersDialogComponent, ConfigureCustomAdaptersDialogComponent,
EditNetworkConfigurationDialogComponent EditNetworkConfigurationDialogComponent,
], ],
bootstrap: [AppComponent] bootstrap: [AppComponent],
}) })
export class AppModule { export class AppModule {
constructor(protected _googleAnalyticsService: GoogleAnalyticsService) { } constructor(protected _googleAnalyticsService: GoogleAnalyticsService) {}
} }

View File

@ -23,5 +23,5 @@ export const ANGULAR_MAP_DECLARATIONS = [
TextComponent, TextComponent,
DraggableComponent, DraggableComponent,
SelectionComponent, SelectionComponent,
InterfaceLabelComponent InterfaceLabelComponent,
]; ];

View File

@ -37,7 +37,7 @@ import {
MapNodesDataSource, MapNodesDataSource,
MapLinksDataSource, MapLinksDataSource,
MapDrawingsDataSource, MapDrawingsDataSource,
MapSymbolsDataSource MapSymbolsDataSource,
} from './datasources/map-datasource'; } from './datasources/map-datasource';
import { LinksEventSource } from './events/links-event-source'; import { LinksEventSource } from './events/links-event-source';
import { D3MapComponent } from './components/d3-map/d3-map.component'; import { D3MapComponent } from './components/d3-map/d3-map.component';
@ -75,7 +75,7 @@ import { SerialLinkWidget } from './widgets/links/serial-link';
SelectionSelectComponent, SelectionSelectComponent,
DraggableSelectionComponent, DraggableSelectionComponent,
MovingCanvasDirective, MovingCanvasDirective,
ZoomingCanvasDirective ZoomingCanvasDirective,
], ],
providers: [ providers: [
CssFixer, CssFixer,
@ -122,8 +122,8 @@ import { SerialLinkWidget } from './widgets/links/serial-link';
StylesToFontConverter, StylesToFontConverter,
EthernetLinkWidget, EthernetLinkWidget,
SerialLinkWidget, SerialLinkWidget,
...D3_MAP_IMPORTS ...D3_MAP_IMPORTS,
], ],
exports: [D3MapComponent, ExperimentalMapComponent] exports: [D3MapComponent, ExperimentalMapComponent],
}) })
export class CartographyModule {} export class CartographyModule {}

View File

@ -1,14 +1,38 @@
<svg id="map" #svg class="map" preserveAspectRatio="none" movingCanvas zoomingCanvas> <svg id="map" #svg class="map" preserveAspectRatio="none" movingCanvas zoomingCanvas>
<filter id="grayscale"><feColorMatrix id="feGrayscale" type="saturate" values="0" /></filter> <filter id="grayscale"><feColorMatrix id="feGrayscale" type="saturate" values="0" /></filter>
<defs> <defs>
<pattern attr.x="{{drawingGridX}}" attr.y="{{drawingGridY}}" id="gridDrawing" attr.width="{{project.drawing_grid_size}}" attr.height="{{project.drawing_grid_size}}" patternUnits="userSpaceOnUse"> <pattern
<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}}"/> attr.x="{{ drawingGridX }}"
attr.y="{{ drawingGridY }}"
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> </pattern>
</defs> </defs>
<defs> <defs>
<pattern attr.x="{{nodeGridX}}" attr.y="{{nodeGridY}}" id="gridNode" attr.width="{{project.grid_size}}" attr.height="{{project.grid_size}}" patternUnits="userSpaceOnUse"> <pattern
<path attr.d="M {{project.grid_size}} 0 L 0 0 0 {{project.grid_size}}" fill="none" stroke="DarkSlateGray" attr.stroke-width="{{gridVisibility}}"/> attr.x="{{ nodeGridX }}"
attr.y="{{ nodeGridY }}"
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> </pattern>
</defs> </defs>

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -8,7 +8,7 @@ describe('D3MapComponent', () => {
beforeEach(async(() => { beforeEach(async(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [D3MapComponent] declarations: [D3MapComponent],
}).compileComponents(); }).compileComponents();
})); }));

View File

@ -9,7 +9,7 @@ import {
SimpleChange, SimpleChange,
EventEmitter, EventEmitter,
Output, Output,
ViewChild ViewChild,
} from '@angular/core'; } from '@angular/core';
import { Selection, select } from 'd3-selection'; import { Selection, select } from 'd3-selection';
@ -38,7 +38,7 @@ import { MapSettingsService } from '../../../services/mapsettings.service';
@Component({ @Component({
selector: 'app-d3-map', selector: 'app-d3-map',
templateUrl: './d3-map.component.html', templateUrl: './d3-map.component.html',
styleUrls: ['./d3-map.component.scss'] styleUrls: ['./d3-map.component.scss'],
}) })
export class D3MapComponent implements OnInit, OnChanges, OnDestroy { export class D3MapComponent implements OnInit, OnChanges, OnDestroy {
@Input() nodes: Node[] = []; @Input() nodes: Node[] = [];
@ -60,7 +60,7 @@ export class D3MapComponent implements OnInit, OnChanges, OnDestroy {
private subscriptions: Subscription[] = []; private subscriptions: Subscription[] = [];
private drawLinkTool: boolean; private drawLinkTool: boolean;
protected settings = { protected settings = {
show_interface_labels: true show_interface_labels: true,
}; };
public gridVisibility: number = 0; public gridVisibility: number = 0;
@ -148,9 +148,7 @@ export class D3MapComponent implements OnInit, OnChanges, OnDestroy {
} }
}); });
this.subscriptions.push( this.subscriptions.push(this.mapScaleService.scaleChangeEmitter.subscribe((value: number) => this.redraw()));
this.mapScaleService.scaleChangeEmitter.subscribe((value: number) => this.redraw())
);
this.subscriptions.push( this.subscriptions.push(
this.toolsService.isMovingToolActivated.subscribe((value: boolean) => { this.toolsService.isMovingToolActivated.subscribe((value: boolean) => {
@ -172,7 +170,7 @@ export class D3MapComponent implements OnInit, OnChanges, OnDestroy {
); );
this.gridVisibility = localStorage.getItem('gridVisibility') === 'true' ? 1 : 0; this.gridVisibility = localStorage.getItem('gridVisibility') === 'true' ? 1 : 0;
this.mapSettingsService.isScrollDisabled.subscribe(val => this.resize(val)); this.mapSettingsService.isScrollDisabled.subscribe((val) => this.resize(val));
} }
ngOnDestroy() { ngOnDestroy() {
@ -190,10 +188,7 @@ export class D3MapComponent implements OnInit, OnChanges, OnDestroy {
public createGraph(domElement: HTMLElement) { public createGraph(domElement: HTMLElement) {
const rootElement = select(domElement); const rootElement = select(domElement);
this.svg = rootElement.select<SVGSVGElement>('svg'); this.svg = rootElement.select<SVGSVGElement>('svg');
this.graphLayout.connect( this.graphLayout.connect(this.svg, this.context);
this.svg,
this.context
);
this.graphLayout.draw(this.svg, this.context); this.graphLayout.draw(this.svg, this.context);
this.mapChangeDetectorRef.hasBeenDrawn = true; this.mapChangeDetectorRef.hasBeenDrawn = true;
} }
@ -227,11 +222,23 @@ export class D3MapComponent implements OnInit, OnChanges, OnDestroy {
} }
updateGrid() { updateGrid() {
if (this.project.grid_size && this.project.grid_size > 0) this.nodeGridX = (this.project.scene_width/2 - (Math.floor(this.project.scene_width/2 / this.project.grid_size) * this.project.grid_size)); if (this.project.grid_size && this.project.grid_size > 0)
if (this.project.grid_size && this.project.grid_size > 0) this.nodeGridY = (this.project.scene_height/2 - (Math.floor(this.project.scene_height/2 / this.project.grid_size) * this.project.grid_size)); this.nodeGridX =
this.project.scene_width / 2 -
Math.floor(this.project.scene_width / 2 / this.project.grid_size) * this.project.grid_size;
if (this.project.grid_size && this.project.grid_size > 0)
this.nodeGridY =
this.project.scene_height / 2 -
Math.floor(this.project.scene_height / 2 / this.project.grid_size) * this.project.grid_size;
if (this.project.drawing_grid_size && this.project.drawing_grid_size > 0) this.drawingGridX = (this.project.scene_width/2 - (Math.floor(this.project.scene_width/2 / this.project.drawing_grid_size) * this.project.drawing_grid_size)); if (this.project.drawing_grid_size && this.project.drawing_grid_size > 0)
if (this.project.drawing_grid_size && this.project.drawing_grid_size > 0) this.drawingGridY = (this.project.scene_height/2 - (Math.floor(this.project.scene_height/2 / this.project.drawing_grid_size) * this.project.drawing_grid_size)); this.drawingGridX =
this.project.scene_width / 2 -
Math.floor(this.project.scene_width / 2 / this.project.drawing_grid_size) * this.project.drawing_grid_size;
if (this.project.drawing_grid_size && this.project.drawing_grid_size > 0)
this.drawingGridY =
this.project.scene_height / 2 -
Math.floor(this.project.scene_height / 2 / this.project.drawing_grid_size) * this.project.drawing_grid_size;
} }
@HostListener('window:resize', ['$event']) @HostListener('window:resize', ['$event'])

View File

@ -67,8 +67,8 @@ describe('DraggableSelectionComponent', () => {
draggable: { draggable: {
start: nodesStartEventEmitter, start: nodesStartEventEmitter,
drag: nodesDragEventEmitter, drag: nodesDragEventEmitter,
end: nodesEndEventEmitter end: nodesEndEventEmitter,
} },
}; };
const drawingsWidgetStub = { const drawingsWidgetStub = {
@ -76,11 +76,11 @@ describe('DraggableSelectionComponent', () => {
draggable: { draggable: {
start: drawingsStartEventEmitter, start: drawingsStartEventEmitter,
drag: drawingsDragEventEmitter, drag: drawingsDragEventEmitter,
end: drawingsEndEventEmitter end: drawingsEndEventEmitter,
} },
}; };
const linksWidgetStub = { const linksWidgetStub = {
redrawLink: () => {} redrawLink: () => {},
}; };
const labelWidgetStub = { const labelWidgetStub = {
@ -88,27 +88,27 @@ describe('DraggableSelectionComponent', () => {
draggable: { draggable: {
start: labelStartEventEmitter, start: labelStartEventEmitter,
drag: labelDragEventEmitter, drag: labelDragEventEmitter,
end: labelEndEventEmitter end: labelEndEventEmitter,
} },
}; };
const interfaceLabelWidgetStub = { const interfaceLabelWidgetStub = {
draggable: { draggable: {
start: interfaceLabelStartEventEmitter, start: interfaceLabelStartEventEmitter,
drag: interfaceLabelDragEventEmitter, drag: interfaceLabelDragEventEmitter,
end: interfaceLabelEndEventEmitter end: interfaceLabelEndEventEmitter,
} },
}; };
const nodesEventSourceStub = { const nodesEventSourceStub = {
dragged: { emit: () => {} }, dragged: { emit: () => {} },
labelDragged: { emit: () => {} } labelDragged: { emit: () => {} },
}; };
const drawingsEventSourceStub = { const drawingsEventSourceStub = {
dragged: { emit: () => {} } dragged: { emit: () => {} },
}; };
const linksEventSourceStub = { const linksEventSourceStub = {
interfaceDragged: { emit: () => {} } interfaceDragged: { emit: () => {} },
}; };
TestBed.configureTestingModule({ TestBed.configureTestingModule({
@ -123,9 +123,9 @@ describe('DraggableSelectionComponent', () => {
{ provide: DrawingsEventSource, useValue: drawingsEventSourceStub }, { provide: DrawingsEventSource, useValue: drawingsEventSourceStub },
{ provide: GraphDataManager, useValue: mockedGraphDataManager }, { provide: GraphDataManager, useValue: mockedGraphDataManager },
{ provide: LinksEventSource, useValue: linksEventSourceStub }, { provide: LinksEventSource, useValue: linksEventSourceStub },
{ provide: MapSettingsService, useClass: MapSettingsService } { provide: MapSettingsService, useClass: MapSettingsService },
], ],
declarations: [DraggableSelectionComponent] declarations: [DraggableSelectionComponent],
}).compileComponents(); }).compileComponents();
})); }));

View File

@ -22,7 +22,7 @@ import { MapSettingsService } from '../../../services/mapsettings.service';
@Component({ @Component({
selector: 'app-draggable-selection', selector: 'app-draggable-selection',
templateUrl: './draggable-selection.component.html', templateUrl: './draggable-selection.component.html',
styleUrls: ['./draggable-selection.component.scss'] styleUrls: ['./draggable-selection.component.scss'],
}) })
export class DraggableSelectionComponent implements OnInit, OnDestroy { export class DraggableSelectionComponent implements OnInit, OnDestroy {
private start: Subscription; private start: Subscription;
@ -62,25 +62,25 @@ export class DraggableSelectionComponent implements OnInit, OnDestroy {
).subscribe((evt: DraggableStart<any>) => { ).subscribe((evt: DraggableStart<any>) => {
const selected = this.selectionManager.getSelected(); const selected = this.selectionManager.getSelected();
if (evt.datum instanceof MapNode) { if (evt.datum instanceof MapNode) {
if (selected.filter(item => item instanceof MapNode && item.id === evt.datum.id).length === 0) { if (selected.filter((item) => item instanceof MapNode && item.id === evt.datum.id).length === 0) {
this.selectionManager.setSelected([evt.datum]); this.selectionManager.setSelected([evt.datum]);
} }
} }
if (evt.datum instanceof MapDrawing) { if (evt.datum instanceof MapDrawing) {
if (selected.filter(item => item instanceof MapDrawing && item.id === evt.datum.id).length === 0) { if (selected.filter((item) => item instanceof MapDrawing && item.id === evt.datum.id).length === 0) {
this.selectionManager.setSelected([evt.datum]); this.selectionManager.setSelected([evt.datum]);
} }
} }
if (evt.datum instanceof MapLabel) { if (evt.datum instanceof MapLabel) {
if (selected.filter(item => item instanceof MapLabel && item.id === evt.datum.id).length === 0) { if (selected.filter((item) => item instanceof MapLabel && item.id === evt.datum.id).length === 0) {
this.selectionManager.setSelected([evt.datum]); this.selectionManager.setSelected([evt.datum]);
} }
} }
if (evt.datum instanceof MapLinkNode) { if (evt.datum instanceof MapLinkNode) {
if (selected.filter(item => item instanceof MapLinkNode && item.id === evt.datum.id).length === 0) { if (selected.filter((item) => item instanceof MapLinkNode && item.id === evt.datum.id).length === 0) {
this.selectionManager.setSelected([evt.datum]); this.selectionManager.setSelected([evt.datum]);
} }
} }
@ -95,7 +95,7 @@ export class DraggableSelectionComponent implements OnInit, OnDestroy {
if (!this.isMapLocked) { if (!this.isMapLocked) {
const selected = this.selectionManager.getSelected(); const selected = this.selectionManager.getSelected();
// update nodes // update nodes
let mapNodes = selected.filter(item => item instanceof MapNode); let mapNodes = selected.filter((item) => item instanceof MapNode);
const lockedNodes = mapNodes.filter((item: MapNode) => item.locked); const lockedNodes = mapNodes.filter((item: MapNode) => item.locked);
const selectedNodes = mapNodes.filter((item: MapNode) => !item.locked); const selectedNodes = mapNodes.filter((item: MapNode) => !item.locked);
selectedNodes.forEach((node: MapNode) => { selectedNodes.forEach((node: MapNode) => {
@ -107,18 +107,18 @@ export class DraggableSelectionComponent implements OnInit, OnDestroy {
const links = this.graphDataManager const links = this.graphDataManager
.getLinks() .getLinks()
.filter( .filter(
link => (link) =>
(link.target !== undefined && link.target.id === node.id) || (link.target !== undefined && link.target.id === node.id) ||
(link.source !== undefined && link.source.id === node.id) (link.source !== undefined && link.source.id === node.id)
); );
links.forEach(link => { links.forEach((link) => {
this.linksWidget.redrawLink(svg, link); this.linksWidget.redrawLink(svg, link);
}); });
}); });
// update drawings // update drawings
let mapDrawings = selected.filter(item => item instanceof MapDrawing); let mapDrawings = selected.filter((item) => item instanceof MapDrawing);
const selectedDrawings = mapDrawings.filter((item: MapDrawing) => !item.locked); const selectedDrawings = mapDrawings.filter((item: MapDrawing) => !item.locked);
selectedDrawings.forEach((drawing: MapDrawing) => { selectedDrawings.forEach((drawing: MapDrawing) => {
drawing.x += evt.dx; drawing.x += evt.dx;
@ -127,32 +127,36 @@ export class DraggableSelectionComponent implements OnInit, OnDestroy {
}); });
// update labels // update labels
let mapLabels = selected.filter(item => item instanceof MapLabel); let mapLabels = selected.filter((item) => item instanceof MapLabel);
const selectedLabels = mapLabels.filter((item: MapLabel) => lockedNodes.filter((node) => node.id === item.nodeId).length === 0); const selectedLabels = mapLabels.filter(
(item: MapLabel) => lockedNodes.filter((node) => node.id === item.nodeId).length === 0
);
selectedLabels.forEach((label: MapLabel) => { selectedLabels.forEach((label: MapLabel) => {
const isParentNodeSelected = selectedNodes.filter(node => node.id === label.nodeId).length > 0; const isParentNodeSelected = selectedNodes.filter((node) => node.id === label.nodeId).length > 0;
if (isParentNodeSelected) { if (isParentNodeSelected) {
return; return;
} }
const node = this.graphDataManager.getNodes().filter(node => node.id === label.nodeId)[0]; const node = this.graphDataManager.getNodes().filter((node) => node.id === label.nodeId)[0];
node.label.x += evt.dx; node.label.x += evt.dx;
node.label.y += evt.dy; node.label.y += evt.dy;
this.labelWidget.redrawLabel(svg, label); this.labelWidget.redrawLabel(svg, label);
}); });
// update interface labels // update interface labels
let mapLinkNodes = selected.filter(item => item instanceof MapLinkNode); let mapLinkNodes = selected.filter((item) => item instanceof MapLinkNode);
const selectedLinkNodes = mapLinkNodes.filter((item: MapLinkNode) => lockedNodes.filter((node) => node.id === item.nodeId).length === 0); const selectedLinkNodes = mapLinkNodes.filter(
(item: MapLinkNode) => lockedNodes.filter((node) => node.id === item.nodeId).length === 0
);
selectedLinkNodes.forEach((interfaceLabel: MapLinkNode) => { selectedLinkNodes.forEach((interfaceLabel: MapLinkNode) => {
const isParentNodeSelected = selectedNodes.filter(node => node.id === interfaceLabel.nodeId).length > 0; const isParentNodeSelected = selectedNodes.filter((node) => node.id === interfaceLabel.nodeId).length > 0;
if (isParentNodeSelected) { if (isParentNodeSelected) {
return; return;
} }
const link = this.graphDataManager const link = this.graphDataManager
.getLinks() .getLinks()
.filter(link => link.nodes[0].id === interfaceLabel.id || link.nodes[1].id === interfaceLabel.id)[0]; .filter((link) => link.nodes[0].id === interfaceLabel.id || link.nodes[1].id === interfaceLabel.id)[0];
if (link.nodes[0].id === interfaceLabel.id) { if (link.nodes[0].id === interfaceLabel.id) {
link.nodes[0].label.x += evt.dx; link.nodes[0].label.x += evt.dx;
link.nodes[0].label.y += evt.dy; link.nodes[0].label.y += evt.dy;
@ -176,23 +180,25 @@ export class DraggableSelectionComponent implements OnInit, OnDestroy {
if (!this.isMapLocked) { if (!this.isMapLocked) {
const selected = this.selectionManager.getSelected(); const selected = this.selectionManager.getSelected();
let mapNodes = selected.filter(item => item instanceof MapNode); let mapNodes = selected.filter((item) => item instanceof MapNode);
const lockedNodes = mapNodes.filter((item: MapNode) => item.locked); const lockedNodes = mapNodes.filter((item: MapNode) => item.locked);
const selectedNodes = mapNodes.filter((item: MapNode) => !item.locked); const selectedNodes = mapNodes.filter((item: MapNode) => !item.locked);
selectedNodes.forEach((item: MapNode) => { selectedNodes.forEach((item: MapNode) => {
this.nodesEventSource.dragged.emit(new DraggedDataEvent<MapNode>(item, evt.dx, evt.dy)); this.nodesEventSource.dragged.emit(new DraggedDataEvent<MapNode>(item, evt.dx, evt.dy));
}); });
let mapDrawings = selected.filter(item => item instanceof MapDrawing); let mapDrawings = selected.filter((item) => item instanceof MapDrawing);
const selectedDrawings = mapDrawings.filter((item: MapDrawing) => !item.locked); const selectedDrawings = mapDrawings.filter((item: MapDrawing) => !item.locked);
selectedDrawings.forEach((item: MapDrawing) => { selectedDrawings.forEach((item: MapDrawing) => {
this.drawingsEventSource.dragged.emit(new DraggedDataEvent<MapDrawing>(item, evt.dx, evt.dy)); this.drawingsEventSource.dragged.emit(new DraggedDataEvent<MapDrawing>(item, evt.dx, evt.dy));
}); });
let mapLabels = selected.filter(item => item instanceof MapLabel); let mapLabels = selected.filter((item) => item instanceof MapLabel);
const selectedLabels = mapLabels.filter((item: MapLabel) => lockedNodes.filter((node) => node.id === item.nodeId).length === 0); const selectedLabels = mapLabels.filter(
(item: MapLabel) => lockedNodes.filter((node) => node.id === item.nodeId).length === 0
);
selectedLabels.forEach((label: MapLabel) => { selectedLabels.forEach((label: MapLabel) => {
const isParentNodeSelected = selectedNodes.filter(node => node.id === label.nodeId).length > 0; const isParentNodeSelected = selectedNodes.filter((node) => node.id === label.nodeId).length > 0;
if (isParentNodeSelected) { if (isParentNodeSelected) {
return; return;
} }
@ -200,10 +206,12 @@ export class DraggableSelectionComponent implements OnInit, OnDestroy {
this.nodesEventSource.labelDragged.emit(new DraggedDataEvent<MapLabel>(label, evt.dx, evt.dy)); this.nodesEventSource.labelDragged.emit(new DraggedDataEvent<MapLabel>(label, evt.dx, evt.dy));
}); });
let mapLinkNodes = selected.filter(item => item instanceof MapLinkNode); let mapLinkNodes = selected.filter((item) => item instanceof MapLinkNode);
const selectedLinkNodes = mapLinkNodes.filter((item: MapLinkNode) => lockedNodes.filter((node) => node.id === item.nodeId).length === 0) const selectedLinkNodes = mapLinkNodes.filter(
(item: MapLinkNode) => lockedNodes.filter((node) => node.id === item.nodeId).length === 0
);
selectedLinkNodes.forEach((label: MapLinkNode) => { selectedLinkNodes.forEach((label: MapLinkNode) => {
const isParentNodeSelected = selectedNodes.filter(node => node.id === label.nodeId).length > 0; const isParentNodeSelected = selectedNodes.filter((node) => node.id === label.nodeId).length > 0;
if (isParentNodeSelected) { if (isParentNodeSelected) {
return; return;
} }

View File

@ -14,9 +14,9 @@ describe('DrawingAddingComponent', () => {
imports: [NoopAnimationsModule], imports: [NoopAnimationsModule],
providers: [ providers: [
{ provide: DrawingsEventSource, useValue: drawingsEventSource }, { provide: DrawingsEventSource, useValue: drawingsEventSource },
{ provide: Context, useClass: Context } { provide: Context, useClass: Context },
], ],
declarations: [DrawingAddingComponent] declarations: [DrawingAddingComponent],
}).compileComponents(); }).compileComponents();
})); }));

View File

@ -7,7 +7,7 @@ import { Subscription } from 'rxjs';
@Component({ @Component({
selector: 'app-drawing-adding', selector: 'app-drawing-adding',
templateUrl: './drawing-adding.component.html', templateUrl: './drawing-adding.component.html',
styleUrls: ['./drawing-adding.component.scss'] styleUrls: ['./drawing-adding.component.scss'],
}) })
export class DrawingAddingComponent implements OnInit, OnDestroy { export class DrawingAddingComponent implements OnInit, OnDestroy {
@Input('svg') svg: SVGSVGElement; @Input('svg') svg: SVGSVGElement;
@ -18,15 +18,19 @@ export class DrawingAddingComponent implements OnInit, OnDestroy {
constructor(private drawingsEventSource: DrawingsEventSource, private context: Context) {} constructor(private drawingsEventSource: DrawingsEventSource, private context: Context) {}
ngOnInit() { ngOnInit() {
this.drawingSelected = this.drawingsEventSource.selected.subscribe(evt => { this.drawingSelected = this.drawingsEventSource.selected.subscribe((evt) => {
evt === '' ? this.deactivate() : this.activate(); evt === '' ? this.deactivate() : this.activate();
}); });
} }
activate() { activate() {
let listener = (event: MouseEvent) => { let listener = (event: MouseEvent) => {
let x = (event.pageX - (this.context.getZeroZeroTransformationPoint().x + this.context.transformation.x))/this.context.transformation.k; let x =
let y = (event.pageY - (this.context.getZeroZeroTransformationPoint().y + this.context.transformation.y))/this.context.transformation.k; (event.pageX - (this.context.getZeroZeroTransformationPoint().x + this.context.transformation.x)) /
this.context.transformation.k;
let y =
(event.pageY - (this.context.getZeroZeroTransformationPoint().y + this.context.transformation.y)) /
this.context.transformation.k;
this.drawingsEventSource.pointToAddSelected.emit(new AddedDataEvent(x, y)); this.drawingsEventSource.pointToAddSelected.emit(new AddedDataEvent(x, y));
this.deactivate(); this.deactivate();

View File

@ -36,9 +36,9 @@ describe('DrawingResizingComponent', () => {
imports: [NoopAnimationsModule], imports: [NoopAnimationsModule],
providers: [ providers: [
{ provide: DrawingsWidget, useValue: drawingsWidgetMock }, { provide: DrawingsWidget, useValue: drawingsWidgetMock },
{ provide: DrawingsEventSource, useValue: drawingsEventSource } { provide: DrawingsEventSource, useValue: drawingsEventSource },
], ],
declarations: [DrawingResizingComponent] declarations: [DrawingResizingComponent],
}).compileComponents(); }).compileComponents();
})); }));

View File

@ -8,10 +8,8 @@ import { ResizingEnd } from '../../events/resizing';
@Component({ @Component({
selector: 'app-drawing-resizing', selector: 'app-drawing-resizing',
template: ` template: ` <ng-content></ng-content> `,
<ng-content></ng-content> styleUrls: ['./drawing-resizing.component.scss'],
`,
styleUrls: ['./drawing-resizing.component.scss']
}) })
export class DrawingResizingComponent implements OnInit, OnDestroy { export class DrawingResizingComponent implements OnInit, OnDestroy {
resizingFinished: Subscription; resizingFinished: Subscription;

View File

@ -8,7 +8,7 @@ describe('DraggableComponent', () => {
beforeEach(async(() => { beforeEach(async(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [DraggableComponent] declarations: [DraggableComponent],
}).compileComponents(); }).compileComponents();
})); }));

View File

@ -8,10 +8,8 @@ export class DraggableDraggedEvent {
@Component({ @Component({
selector: '[app-draggable]', selector: '[app-draggable]',
template: ` template: ` <ng-content></ng-content> `,
<ng-content></ng-content> styleUrls: ['./draggable.component.scss'],
`,
styleUrls: ['./draggable.component.scss']
}) })
export class DraggableComponent implements OnInit, AfterViewInit, OnDestroy { export class DraggableComponent implements OnInit, AfterViewInit, OnDestroy {
@Input('app-draggable') item: Point; @Input('app-draggable') item: Point;

View File

@ -8,7 +8,7 @@ describe('DrawingComponent', () => {
beforeEach(async(() => { beforeEach(async(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [DrawingComponent] declarations: [DrawingComponent],
}).compileComponents(); }).compileComponents();
})); }));

View File

@ -12,7 +12,7 @@ import { DrawingsEventSource } from '../../../events/drawings-event-source';
@Component({ @Component({
selector: '[app-drawing]', selector: '[app-drawing]',
templateUrl: './drawing.component.html', templateUrl: './drawing.component.html',
styleUrls: ['./drawing.component.scss'] styleUrls: ['./drawing.component.scss'],
}) })
export class DrawingComponent implements OnInit { export class DrawingComponent implements OnInit {
@Input('app-drawing') drawing: MapDrawing; @Input('app-drawing') drawing: MapDrawing;

View File

@ -8,7 +8,7 @@ describe('EllipseComponent', () => {
beforeEach(async(() => { beforeEach(async(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [EllipseComponent] declarations: [EllipseComponent],
}).compileComponents(); }).compileComponents();
})); }));

View File

@ -5,7 +5,7 @@ import { QtDasharrayFixer } from '../../../../../helpers/qt-dasharray-fixer';
@Component({ @Component({
selector: '[app-ellipse]', selector: '[app-ellipse]',
templateUrl: './ellipse.component.html', templateUrl: './ellipse.component.html',
styleUrls: ['./ellipse.component.scss'] styleUrls: ['./ellipse.component.scss'],
}) })
export class EllipseComponent implements OnInit { export class EllipseComponent implements OnInit {
@Input('app-ellipse') ellipse: EllipseElement; @Input('app-ellipse') ellipse: EllipseElement;

View File

@ -8,7 +8,7 @@ describe('ImageComponent', () => {
beforeEach(async(() => { beforeEach(async(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ImageComponent] declarations: [ImageComponent],
}).compileComponents(); }).compileComponents();
})); }));

View File

@ -4,7 +4,7 @@ import { ImageElement } from '../../../../../models/drawings/image-element';
@Component({ @Component({
selector: '[app-image]', selector: '[app-image]',
templateUrl: './image.component.html', templateUrl: './image.component.html',
styleUrls: ['./image.component.scss'] styleUrls: ['./image.component.scss'],
}) })
export class ImageComponent implements OnInit { export class ImageComponent implements OnInit {
@Input('app-image') image: ImageElement; @Input('app-image') image: ImageElement;

View File

@ -8,7 +8,7 @@ describe('LineComponent', () => {
beforeEach(async(() => { beforeEach(async(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [LineComponent] declarations: [LineComponent],
}).compileComponents(); }).compileComponents();
})); }));

View File

@ -5,7 +5,7 @@ import { LineElement } from '../../../../../models/drawings/line-element';
@Component({ @Component({
selector: '[app-line]', selector: '[app-line]',
templateUrl: './line.component.html', templateUrl: './line.component.html',
styleUrls: ['./line.component.scss'] styleUrls: ['./line.component.scss'],
}) })
export class LineComponent implements OnInit { export class LineComponent implements OnInit {
@Input('app-line') line: LineElement; @Input('app-line') line: LineElement;

View File

@ -8,7 +8,7 @@ describe('RectComponent', () => {
beforeEach(async(() => { beforeEach(async(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [RectComponent] declarations: [RectComponent],
}).compileComponents(); }).compileComponents();
})); }));

View File

@ -5,7 +5,7 @@ import { QtDasharrayFixer } from '../../../../../helpers/qt-dasharray-fixer';
@Component({ @Component({
selector: '[app-rect]', selector: '[app-rect]',
templateUrl: './rect.component.html', templateUrl: './rect.component.html',
styleUrls: ['./rect.component.scss'] styleUrls: ['./rect.component.scss'],
}) })
export class RectComponent implements OnInit { export class RectComponent implements OnInit {
@Input('app-rect') rect: RectElement; @Input('app-rect') rect: RectElement;

View File

@ -8,7 +8,7 @@ describe('TextComponent', () => {
beforeEach(async(() => { beforeEach(async(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [TextComponent] declarations: [TextComponent],
}).compileComponents(); }).compileComponents();
})); }));

View File

@ -6,7 +6,7 @@ import { FontFixer } from '../../../../../helpers/font-fixer';
@Component({ @Component({
selector: '[app-text]', selector: '[app-text]',
templateUrl: './text.component.html', templateUrl: './text.component.html',
styleUrls: ['./text.component.scss'] styleUrls: ['./text.component.scss'],
}) })
export class TextComponent implements OnInit, DoCheck { export class TextComponent implements OnInit, DoCheck {
static MARGIN = 4; static MARGIN = 4;

View File

@ -9,7 +9,7 @@ import {
SimpleChange, SimpleChange,
ChangeDetectionStrategy, ChangeDetectionStrategy,
ChangeDetectorRef, ChangeDetectorRef,
ViewChild ViewChild,
} from '@angular/core'; } from '@angular/core';
import { GraphLayout } from '../../widgets/graph-layout'; import { GraphLayout } from '../../widgets/graph-layout';
@ -29,7 +29,7 @@ import { LayersManager } from '../../managers/layers-manager';
selector: 'app-experimental-map', selector: 'app-experimental-map',
templateUrl: './experimental-map.component.html', templateUrl: './experimental-map.component.html',
styleUrls: ['./experimental-map.component.scss'], styleUrls: ['./experimental-map.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush changeDetection: ChangeDetectionStrategy.OnPush,
}) })
export class ExperimentalMapComponent implements OnInit, OnChanges, OnDestroy { export class ExperimentalMapComponent implements OnInit, OnChanges, OnDestroy {
@Input() nodes: Node[] = []; @Input() nodes: Node[] = [];
@ -48,7 +48,7 @@ export class ExperimentalMapComponent implements OnInit, OnChanges, OnDestroy {
private changesDetected: Subscription; private changesDetected: Subscription;
protected settings = { protected settings = {
show_interface_labels: true show_interface_labels: true,
}; };
constructor( constructor(

View File

@ -8,7 +8,7 @@ describe('InterfaceLabelComponent', () => {
beforeEach(async(() => { beforeEach(async(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [InterfaceLabelComponent] declarations: [InterfaceLabelComponent],
}).compileComponents(); }).compileComponents();
})); }));

View File

@ -5,7 +5,7 @@ import { CssFixer } from '../../../helpers/css-fixer';
@Component({ @Component({
selector: '[app-interface-label]', selector: '[app-interface-label]',
templateUrl: './interface-label.component.html', templateUrl: './interface-label.component.html',
styleUrls: ['./interface-label.component.scss'] styleUrls: ['./interface-label.component.scss'],
}) })
export class InterfaceLabelComponent implements OnInit { export class InterfaceLabelComponent implements OnInit {
@Input('app-interface-label') ignore: any; @Input('app-interface-label') ignore: any;
@ -17,7 +17,7 @@ export class InterfaceLabelComponent implements OnInit {
y: 0, y: 0,
text: '', text: '',
style: '', style: '',
rotation: 0 rotation: 0,
}; };
borderSize = 5; borderSize = 5;

View File

@ -8,7 +8,7 @@ describe('LinkComponent', () => {
beforeEach(async(() => { beforeEach(async(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [LinkComponent] declarations: [LinkComponent],
}).compileComponents(); }).compileComponents();
})); }));

View File

@ -6,7 +6,7 @@ import {
ElementRef, ElementRef,
EventEmitter, EventEmitter,
ChangeDetectorRef, ChangeDetectorRef,
OnDestroy OnDestroy,
} from '@angular/core'; } from '@angular/core';
import { Subscription } from 'rxjs'; import { Subscription } from 'rxjs';
import { LinkStrategy } from './strategies/link-strategy'; import { LinkStrategy } from './strategies/link-strategy';
@ -19,7 +19,7 @@ import { MapLink } from '../../../models/map/map-link';
@Component({ @Component({
selector: '[app-link]', selector: '[app-link]',
templateUrl: './link.component.html', templateUrl: './link.component.html',
styleUrls: ['./link.component.scss'] styleUrls: ['./link.component.scss'],
}) })
export class LinkComponent implements OnInit, OnDestroy { export class LinkComponent implements OnInit, OnDestroy {
@Input('app-link') link: MapLink; @Input('app-link') link: MapLink;

View File

@ -6,7 +6,7 @@ export class EthernetLinkStrategy implements LinkStrategy {
public d(link: MapLink): string { public d(link: MapLink): string {
const points = [ const points = [
[link.source.x + link.source.width / 2, link.source.y + link.source.height / 2], [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] [link.target.x + link.target.width / 2, link.target.y + link.target.height / 2],
]; ];
const line_generator = path(); const line_generator = path();

View File

@ -6,11 +6,11 @@ export class SerialLinkStrategy implements LinkStrategy {
private linkToPoints(link: MapLink) { private linkToPoints(link: MapLink) {
const source = { const source = {
x: link.source.x + link.source.width / 2, x: link.source.x + link.source.width / 2,
y: link.source.y + link.source.height / 2 y: link.source.y + link.source.height / 2,
}; };
const target = { const target = {
x: link.target.x + link.target.width / 2, x: link.target.x + link.target.width / 2,
y: link.target.y + link.target.height / 2 y: link.target.y + link.target.height / 2,
}; };
const dx = target.x - source.x; const dx = target.x - source.x;
@ -22,12 +22,12 @@ export class SerialLinkStrategy implements LinkStrategy {
const angle_source: [number, number] = [ const angle_source: [number, number] = [
source.x + dx / 2.0 + 15 * vect_rot[0], source.x + dx / 2.0 + 15 * vect_rot[0],
source.y + dy / 2.0 + 15 * vect_rot[1] source.y + dy / 2.0 + 15 * vect_rot[1],
]; ];
const angle_target: [number, number] = [ const angle_target: [number, number] = [
target.x - dx / 2.0 - 15 * vect_rot[0], target.x - dx / 2.0 - 15 * vect_rot[0],
target.y - dy / 2.0 - 15 * vect_rot[1] target.y - dy / 2.0 - 15 * vect_rot[1],
]; ];
return [[source.x, source.y], angle_source, angle_target, [target.x, target.y]]; return [[source.x, source.y], angle_source, angle_target, [target.x, target.y]];

View File

@ -8,7 +8,7 @@ describe('NodeComponent', () => {
beforeEach(async(() => { beforeEach(async(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [NodeComponent] declarations: [NodeComponent],
}).compileComponents(); }).compileComponents();
})); }));

View File

@ -10,7 +10,7 @@ import {
EventEmitter, EventEmitter,
OnDestroy, OnDestroy,
OnChanges, OnChanges,
AfterViewInit AfterViewInit,
} from '@angular/core'; } from '@angular/core';
import { DomSanitizer } from '@angular/platform-browser'; import { DomSanitizer } from '@angular/platform-browser';
import { Subscription } from 'rxjs'; import { Subscription } from 'rxjs';
@ -25,7 +25,7 @@ import { DraggedDataEvent } from '../../../events/event-source';
selector: '[app-node]', selector: '[app-node]',
templateUrl: './node.component.html', templateUrl: './node.component.html',
styleUrls: ['./node.component.scss'], styleUrls: ['./node.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush changeDetection: ChangeDetectionStrategy.OnPush,
}) })
export class NodeComponent implements OnInit, OnDestroy, OnChanges, AfterViewInit { export class NodeComponent implements OnInit, OnDestroy, OnChanges, AfterViewInit {
static NODE_LABEL_MARGIN = 3; static NODE_LABEL_MARGIN = 3;

View File

@ -8,7 +8,7 @@ describe('SelectionComponent', () => {
beforeEach(async(() => { beforeEach(async(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [SelectionComponent] declarations: [SelectionComponent],
}).compileComponents(); }).compileComponents();
})); }));

View File

@ -5,7 +5,7 @@ import { Rectangle } from '../../../models/rectangle';
@Component({ @Component({
selector: '[app-selection]', selector: '[app-selection]',
templateUrl: './selection.component.html', templateUrl: './selection.component.html',
styleUrls: ['./selection.component.scss'] styleUrls: ['./selection.component.scss'],
}) })
export class SelectionComponent implements OnInit, AfterViewInit { export class SelectionComponent implements OnInit, AfterViewInit {
@Input('app-selection') svg: SVGSVGElement; @Input('app-selection') svg: SVGSVGElement;

View File

@ -8,7 +8,7 @@ describe('StatusComponent', () => {
beforeEach(async(() => { beforeEach(async(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [StatusComponent] declarations: [StatusComponent],
}).compileComponents(); }).compileComponents();
})); }));

View File

@ -3,7 +3,7 @@ import { Component, ElementRef, Input, ChangeDetectorRef } from '@angular/core';
@Component({ @Component({
selector: '[app-status]', selector: '[app-status]',
templateUrl: './status.component.html', templateUrl: './status.component.html',
styleUrls: ['./status.component.scss'] styleUrls: ['./status.component.scss'],
}) })
export class StatusComponent { export class StatusComponent {
static STOPPED_STATUS_RECT_WIDTH = 10; static STOPPED_STATUS_RECT_WIDTH = 10;
@ -12,7 +12,7 @@ export class StatusComponent {
status: '', status: '',
path: null, path: null,
direction: null, direction: null,
d: null d: null,
}; };
constructor(protected element: ElementRef, private ref: ChangeDetectorRef) {} constructor(protected element: ElementRef, private ref: ChangeDetectorRef) {}

View File

@ -9,7 +9,7 @@ import { Rectangle } from '../../models/rectangle';
@Component({ @Component({
selector: 'app-selection-control', selector: 'app-selection-control',
templateUrl: './selection-control.component.html', templateUrl: './selection-control.component.html',
styleUrls: ['./selection-control.component.scss'] styleUrls: ['./selection-control.component.scss'],
}) })
export class SelectionControlComponent implements OnInit, OnDestroy { export class SelectionControlComponent implements OnInit, OnDestroy {
private onSelection: Subscription; private onSelection: Subscription;
@ -23,21 +23,21 @@ export class SelectionControlComponent implements OnInit, OnDestroy {
ngOnInit() { ngOnInit() {
this.onSelection = this.selectionEventSource.selected.subscribe((rectangle: Rectangle) => { this.onSelection = this.selectionEventSource.selected.subscribe((rectangle: Rectangle) => {
const selectedNodes = this.graphDataManager.getNodes().filter(node => { const selectedNodes = this.graphDataManager.getNodes().filter((node) => {
return this.inRectangleHelper.inRectangle(rectangle, node.x, node.y); return this.inRectangleHelper.inRectangle(rectangle, node.x, node.y);
}); });
const selectedLinks = this.graphDataManager.getLinks().filter(link => { const selectedLinks = this.graphDataManager.getLinks().filter((link) => {
return this.inRectangleHelper.inRectangle(rectangle, link.x, link.y); return this.inRectangleHelper.inRectangle(rectangle, link.x, link.y);
}); });
const selectedDrawings = this.graphDataManager.getDrawings().filter(drawing => { const selectedDrawings = this.graphDataManager.getDrawings().filter((drawing) => {
return this.inRectangleHelper.inRectangle(rectangle, drawing.x, drawing.y); return this.inRectangleHelper.inRectangle(rectangle, drawing.x, drawing.y);
}); });
const selectedLabels = this.graphDataManager const selectedLabels = this.graphDataManager
.getNodes() .getNodes()
.filter(node => { .filter((node) => {
if (node.label === undefined) { if (node.label === undefined) {
return false; return false;
} }
@ -45,11 +45,11 @@ export class SelectionControlComponent implements OnInit, OnDestroy {
const labelY = node.y + node.label.y; const labelY = node.y + node.label.y;
return this.inRectangleHelper.inRectangle(rectangle, labelX, labelY); return this.inRectangleHelper.inRectangle(rectangle, labelX, labelY);
}) })
.map(node => node.label); .map((node) => node.label);
const selectedInterfacesLabelsSources = this.graphDataManager const selectedInterfacesLabelsSources = this.graphDataManager
.getLinks() .getLinks()
.filter(link => { .filter((link) => {
if (link.source === undefined || link.nodes.length != 2 || link.nodes[0].label === undefined) { if (link.source === undefined || link.nodes.length != 2 || link.nodes[0].label === undefined) {
return false; return false;
} }
@ -57,11 +57,11 @@ export class SelectionControlComponent implements OnInit, OnDestroy {
const interfaceLabelY = link.source.y + link.nodes[0].label.y; const interfaceLabelY = link.source.y + link.nodes[0].label.y;
return this.inRectangleHelper.inRectangle(rectangle, interfaceLabelX, interfaceLabelY); return this.inRectangleHelper.inRectangle(rectangle, interfaceLabelX, interfaceLabelY);
}) })
.map(link => link.nodes[0]); .map((link) => link.nodes[0]);
const selectedInterfacesLabelsTargets = this.graphDataManager const selectedInterfacesLabelsTargets = this.graphDataManager
.getLinks() .getLinks()
.filter(link => { .filter((link) => {
if (link.target === undefined || link.nodes.length != 2 || link.nodes[1].label === undefined) { if (link.target === undefined || link.nodes.length != 2 || link.nodes[1].label === undefined) {
return false; return false;
} }
@ -69,7 +69,7 @@ export class SelectionControlComponent implements OnInit, OnDestroy {
const interfaceLabelY = link.target.y + link.nodes[1].label.y; const interfaceLabelY = link.target.y + link.nodes[1].label.y;
return this.inRectangleHelper.inRectangle(rectangle, interfaceLabelX, interfaceLabelY); return this.inRectangleHelper.inRectangle(rectangle, interfaceLabelX, interfaceLabelY);
}) })
.map(link => link.nodes[1]); .map((link) => link.nodes[1]);
const selectedInterfaces = [...selectedInterfacesLabelsSources, ...selectedInterfacesLabelsTargets]; const selectedInterfaces = [...selectedInterfacesLabelsSources, ...selectedInterfacesLabelsTargets];
@ -78,7 +78,7 @@ export class SelectionControlComponent implements OnInit, OnDestroy {
...selectedLinks, ...selectedLinks,
...selectedDrawings, ...selectedDrawings,
...selectedLabels, ...selectedLabels,
...selectedInterfaces ...selectedInterfaces,
]; ];
this.selectionManager.setSelected(selected); this.selectionManager.setSelected(selected);

View File

@ -8,7 +8,7 @@ describe('SelectionSelectComponent', () => {
beforeEach(async(() => { beforeEach(async(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [SelectionSelectComponent] declarations: [SelectionSelectComponent],
}).compileComponents(); }).compileComponents();
})); }));

View File

@ -6,16 +6,13 @@ import { MapChangeDetectorRef } from '../../services/map-change-detector-ref';
@Component({ @Component({
selector: 'app-selection-select', selector: 'app-selection-select',
templateUrl: './selection-select.component.html', templateUrl: './selection-select.component.html',
styleUrls: ['./selection-select.component.scss'] styleUrls: ['./selection-select.component.scss'],
}) })
export class SelectionSelectComponent implements OnInit, OnDestroy { export class SelectionSelectComponent implements OnInit, OnDestroy {
private onSelected: Subscription; private onSelected: Subscription;
private onUnselected: Subscription; private onUnselected: Subscription;
constructor( constructor(private selectionManager: SelectionManager, private mapChangeDetectorRef: MapChangeDetectorRef) {}
private selectionManager: SelectionManager,
private mapChangeDetectorRef: MapChangeDetectorRef
) {}
ngOnInit() { ngOnInit() {
this.onSelected = this.selectionManager.selected.subscribe(() => { this.onSelected = this.selectionManager.selected.subscribe(() => {

View File

@ -31,9 +31,9 @@ describe('TextEditorComponent', () => {
{ provide: NodesDataSource, useClass: NodesDataSource }, { provide: NodesDataSource, useClass: NodesDataSource },
{ provide: LinksDataSource, useClass: LinksDataSource }, { provide: LinksDataSource, useClass: LinksDataSource },
{ provide: SelectionManager, useClass: SelectionManager }, { provide: SelectionManager, useClass: SelectionManager },
{ provide: FontFixer, useClass: FontFixer } { provide: FontFixer, useClass: FontFixer },
], ],
declarations: [TextEditorComponent] declarations: [TextEditorComponent],
}).compileComponents(); }).compileComponents();
})); }));

View File

@ -1,4 +1,14 @@
import { Component, ViewChild, ElementRef, OnInit, Input, EventEmitter, OnDestroy, Renderer2, NgZone } from '@angular/core'; import {
Component,
ViewChild,
ElementRef,
OnInit,
Input,
EventEmitter,
OnDestroy,
Renderer2,
NgZone,
} from '@angular/core';
import { DrawingsEventSource } from '../../events/drawings-event-source'; import { DrawingsEventSource } from '../../events/drawings-event-source';
import { TextAddedDataEvent, TextEditedDataEvent } from '../../events/event-source'; import { TextAddedDataEvent, TextEditedDataEvent } from '../../events/event-source';
import { ToolsService } from '../../../services/tools.service'; import { ToolsService } from '../../../services/tools.service';
@ -24,7 +34,7 @@ import { Font } from '../../models/font';
@Component({ @Component({
selector: 'app-text-editor', selector: 'app-text-editor',
templateUrl: './text-editor.component.html', templateUrl: './text-editor.component.html',
styleUrls: ['./text-editor.component.scss'] styleUrls: ['./text-editor.component.scss'],
}) })
export class TextEditorComponent implements OnInit, OnDestroy { export class TextEditorComponent implements OnInit, OnDestroy {
@ViewChild('temporaryTextElement') temporaryTextElement: ElementRef; @ViewChild('temporaryTextElement') temporaryTextElement: ElementRef;
@ -73,7 +83,11 @@ export class TextEditorComponent implements OnInit, OnDestroy {
this.leftPosition = event.pageX.toString() + 'px'; this.leftPosition = event.pageX.toString() + 'px';
this.topPosition = event.pageY.toString() + 'px'; this.topPosition = event.pageY.toString() + 'px';
this.renderer.setStyle(this.temporaryTextElement.nativeElement, 'display', 'initial'); this.renderer.setStyle(this.temporaryTextElement.nativeElement, 'display', 'initial');
this.renderer.setStyle(this.temporaryTextElement.nativeElement, 'transform', `scale(${this.mapScaleService.getScale()})`); this.renderer.setStyle(
this.temporaryTextElement.nativeElement,
'transform',
`scale(${this.mapScaleService.getScale()})`
);
this.temporaryTextElement.nativeElement.focus(); this.temporaryTextElement.nativeElement.focus();
let textListener = () => { let textListener = () => {
@ -113,7 +127,11 @@ export class TextEditorComponent implements OnInit, OnDestroy {
this.selectionManager.setSelected([]); this.selectionManager.setSelected([]);
this.renderer.setStyle(this.temporaryTextElement.nativeElement, 'display', 'initial'); this.renderer.setStyle(this.temporaryTextElement.nativeElement, 'display', 'initial');
this.renderer.setStyle(this.temporaryTextElement.nativeElement, 'transform', `scale(${this.mapScaleService.getScale()})`); this.renderer.setStyle(
this.temporaryTextElement.nativeElement,
'transform',
`scale(${this.mapScaleService.getScale()})`
);
this.editedLink = elem; this.editedLink = elem;
select(textElements[index]).attr('visibility', 'hidden'); select(textElements[index]).attr('visibility', 'hidden');
@ -121,26 +139,44 @@ export class TextEditorComponent implements OnInit, OnDestroy {
this.editedNode = this.nodesDataSource.get(elem.nodeId); this.editedNode = this.nodesDataSource.get(elem.nodeId);
this.editedLink = elem; this.editedLink = elem;
let x = ((elem.label.originalX + this.editedNode.x - 1) * this.context.transformation.k) + this.context.getZeroZeroTransformationPoint().x + this.context.transformation.x; let x =
let y = ((elem.label.originalY + this.editedNode.y + 4) * this.context.transformation.k) + this.context.getZeroZeroTransformationPoint().y + this.context.transformation.y; (elem.label.originalX + this.editedNode.x - 1) * this.context.transformation.k +
this.context.getZeroZeroTransformationPoint().x +
this.context.transformation.x;
let y =
(elem.label.originalY + this.editedNode.y + 4) * this.context.transformation.k +
this.context.getZeroZeroTransformationPoint().y +
this.context.transformation.y;
this.leftPosition = x.toString() + 'px'; this.leftPosition = x.toString() + 'px';
this.topPosition = y.toString() + 'px'; this.topPosition = y.toString() + 'px';
this.temporaryTextElement.nativeElement.innerText = elem.label.text; this.temporaryTextElement.nativeElement.innerText = elem.label.text;
let styleProperties: StyleProperty[] = []; let styleProperties: StyleProperty[] = [];
for (let property of elem.label.style.split(";")){ for (let property of elem.label.style.split(';')) {
styleProperties.push({ styleProperties.push({
property: property.split(": ")[0], property: property.split(': ')[0],
value: property.split(": ")[1] value: property.split(': ')[1],
}); });
} }
let font: Font = { let font: Font = {
font_family: styleProperties.find(p => p.property === 'font-family') ? styleProperties.find(p => p.property === 'font-family').value : 'TypeWriter', font_family: styleProperties.find((p) => p.property === 'font-family')
font_size: styleProperties.find(p => p.property === 'font-size') ? Number(styleProperties.find(p => p.property === 'font-size').value) : 10.0, ? styleProperties.find((p) => p.property === 'font-family').value
font_weight: styleProperties.find(p => p.property === 'font-weight') ? styleProperties.find(p => p.property === 'font-weight').value : 'normal' : 'TypeWriter',
font_size: styleProperties.find((p) => p.property === 'font-size')
? Number(styleProperties.find((p) => p.property === 'font-size').value)
: 10.0,
font_weight: styleProperties.find((p) => p.property === 'font-weight')
? styleProperties.find((p) => p.property === 'font-weight').value
: 'normal',
}; };
font = this.fontFixer.fix(font); font = this.fontFixer.fix(font);
this.renderer.setStyle(this.temporaryTextElement.nativeElement, 'color', styleProperties.find(p => p.property === 'fill') ? styleProperties.find(p => p.property === 'fill').value : '#000000'); this.renderer.setStyle(
this.temporaryTextElement.nativeElement,
'color',
styleProperties.find((p) => p.property === 'fill')
? styleProperties.find((p) => p.property === 'fill').value
: '#000000'
);
this.renderer.setStyle(this.temporaryTextElement.nativeElement, 'font-family', font.font_family); this.renderer.setStyle(this.temporaryTextElement.nativeElement, 'font-family', font.font_family);
this.renderer.setStyle(this.temporaryTextElement.nativeElement, 'font-size', `${font.font_size}pt`); this.renderer.setStyle(this.temporaryTextElement.nativeElement, 'font-size', `${font.font_size}pt`);
this.renderer.setStyle(this.temporaryTextElement.nativeElement, 'font-weight', font.font_weight); this.renderer.setStyle(this.temporaryTextElement.nativeElement, 'font-weight', font.font_weight);
@ -148,7 +184,7 @@ export class TextEditorComponent implements OnInit, OnDestroy {
let listener = () => { let listener = () => {
let innerText = this.temporaryTextElement.nativeElement.innerText; let innerText = this.temporaryTextElement.nativeElement.innerText;
let link: Link = this.linksDataSource.get(this.editedLink.linkId); let link: Link = this.linksDataSource.get(this.editedLink.linkId);
link.nodes.find(n => n.node_id === this.editedNode.node_id).label.text = innerText; link.nodes.find((n) => n.node_id === this.editedNode.node_id).label.text = innerText;
this.linkService.updateLink(this.server, link).subscribe((link: Link) => { this.linkService.updateLink(this.server, link).subscribe((link: Link) => {
rootElement rootElement
@ -177,7 +213,11 @@ export class TextEditorComponent implements OnInit, OnDestroy {
.selectAll<SVGTextElement, TextElement>('text.text_element') .selectAll<SVGTextElement, TextElement>('text.text_element')
.on('dblclick', (elem, index, textElements) => { .on('dblclick', (elem, index, textElements) => {
this.renderer.setStyle(this.temporaryTextElement.nativeElement, 'display', 'initial'); this.renderer.setStyle(this.temporaryTextElement.nativeElement, 'display', 'initial');
this.renderer.setStyle(this.temporaryTextElement.nativeElement, 'transform', `scale(${this.mapScaleService.getScale()})`); this.renderer.setStyle(
this.temporaryTextElement.nativeElement,
'transform',
`scale(${this.mapScaleService.getScale()})`
);
this.editedElement = elem; this.editedElement = elem;
select(textElements[index]).attr('visibility', 'hidden'); select(textElements[index]).attr('visibility', 'hidden');
@ -185,8 +225,14 @@ export class TextEditorComponent implements OnInit, OnDestroy {
this.editingDrawingId = textElements[index].parentElement.parentElement.getAttribute('drawing_id'); this.editingDrawingId = textElements[index].parentElement.parentElement.getAttribute('drawing_id');
var transformData = textElements[index].parentElement.getAttribute('transform').split(/\(|\)/); var transformData = textElements[index].parentElement.getAttribute('transform').split(/\(|\)/);
var x = (Number(transformData[1].split(/,/)[0]) * this.context.transformation.k) + this.context.getZeroZeroTransformationPoint().x + this.context.transformation.x; var x =
var y = (Number(transformData[1].split(/,/)[1]) * this.context.transformation.k) + this.context.getZeroZeroTransformationPoint().y + this.context.transformation.y; Number(transformData[1].split(/,/)[0]) * this.context.transformation.k +
this.context.getZeroZeroTransformationPoint().x +
this.context.transformation.x;
var y =
Number(transformData[1].split(/,/)[1]) * this.context.transformation.k +
this.context.getZeroZeroTransformationPoint().y +
this.context.transformation.y;
this.leftPosition = x.toString() + 'px'; this.leftPosition = x.toString() + 'px';
this.topPosition = y.toString() + 'px'; this.topPosition = y.toString() + 'px';
this.temporaryTextElement.nativeElement.innerText = elem.text; this.temporaryTextElement.nativeElement.innerText = elem.text;

View File

@ -17,7 +17,9 @@ export class LinkToMapLinkConverter implements Converter<Link, MapLink> {
mapLink.capturing = link.capturing; mapLink.capturing = link.capturing;
mapLink.filters = link.filters; mapLink.filters = link.filters;
mapLink.linkType = link.link_type; mapLink.linkType = link.link_type;
mapLink.nodes = link.nodes.map(linkNode => this.linkNodeToMapLinkNode.convert(linkNode, { link_id: link.link_id })); mapLink.nodes = link.nodes.map((linkNode) =>
this.linkNodeToMapLinkNode.convert(linkNode, { link_id: link.link_id })
);
mapLink.projectId = link.project_id; mapLink.projectId = link.project_id;
mapLink.suspend = link.suspend; mapLink.suspend = link.suspend;
return mapLink; return mapLink;

View File

@ -15,27 +15,13 @@ export class MapDrawingToSvgConverter implements Converter<MapDrawing, string> {
let elem = ``; let elem = ``;
if (mapDrawing.element instanceof RectElement) { if (mapDrawing.element instanceof RectElement) {
elem = `<rect fill=\"${mapDrawing.element.fill}\" fill-opacity=\"${mapDrawing.element.fill_opacity}\" height=\"${ elem = `<rect fill=\"${mapDrawing.element.fill}\" fill-opacity=\"${mapDrawing.element.fill_opacity}\" height=\"${mapDrawing.element.height}\" width=\"${mapDrawing.element.width}\" stroke=\"${mapDrawing.element.stroke}\" stroke-width=\"${mapDrawing.element.stroke_width}\" />`;
mapDrawing.element.height
}\" width=\"${mapDrawing.element.width}\" stroke=\"${mapDrawing.element.stroke}\" stroke-width=\"${
mapDrawing.element.stroke_width
}\" />`;
} else if (mapDrawing.element instanceof EllipseElement) { } else if (mapDrawing.element instanceof EllipseElement) {
elem = `<ellipse fill=\"${mapDrawing.element.fill}\" fill-opacity=\"${mapDrawing.element.fill_opacity}\" cx=\"${ elem = `<ellipse fill=\"${mapDrawing.element.fill}\" fill-opacity=\"${mapDrawing.element.fill_opacity}\" cx=\"${mapDrawing.element.cx}\" cy=\"${mapDrawing.element.cy}\" rx=\"${mapDrawing.element.rx}\" ry=\"${mapDrawing.element.ry}\" stroke=\"${mapDrawing.element.stroke}\" stroke-width=\"${mapDrawing.element.stroke_width}\" />`;
mapDrawing.element.cx
}\" cy=\"${mapDrawing.element.cy}\" rx=\"${mapDrawing.element.rx}\" ry=\"${mapDrawing.element.ry}\" stroke=\"${
mapDrawing.element.stroke
}\" stroke-width=\"${mapDrawing.element.stroke_width}\" />`;
} else if (mapDrawing.element instanceof LineElement) { } else if (mapDrawing.element instanceof LineElement) {
elem = `<line stroke=\"${mapDrawing.element.stroke}\" stroke-width=\"${mapDrawing.element.stroke_width}\" x1=\"${ elem = `<line stroke=\"${mapDrawing.element.stroke}\" stroke-width=\"${mapDrawing.element.stroke_width}\" x1=\"${mapDrawing.element.x1}\" x2=\"${mapDrawing.element.x2}\" y1=\"${mapDrawing.element.y1}\" y2=\"${mapDrawing.element.y2}\" />`;
mapDrawing.element.x1
}\" x2=\"${mapDrawing.element.x2}\" y1=\"${mapDrawing.element.y1}\" y2=\"${mapDrawing.element.y2}\" />`;
} else if (mapDrawing.element instanceof TextElement) { } else if (mapDrawing.element instanceof TextElement) {
elem = `<text fill=\"${mapDrawing.element.fill}\" fill-opacity=\"1.0\" font-family=\"${ elem = `<text fill=\"${mapDrawing.element.fill}\" fill-opacity=\"1.0\" font-family=\"${mapDrawing.element.font_family}\" font-size=\"${mapDrawing.element.font_size}\" font-weight=\"${mapDrawing.element.font_weight}\">${mapDrawing.element.text}</text>`;
mapDrawing.element.font_family
}\" font-size=\"${mapDrawing.element.font_size}\" font-weight=\"${mapDrawing.element.font_weight}\">${
mapDrawing.element.text
}</text>`;
} else return ''; } else return '';
return `<svg height=\"${mapDrawing.element.height}\" width=\"${mapDrawing.element.width}\">${elem}</svg>`; return `<svg height=\"${mapDrawing.element.height}\" width=\"${mapDrawing.element.width}\">${elem}</svg>`;

View File

@ -17,7 +17,7 @@ export class MapLinkToLinkConverter implements Converter<MapLink, Link> {
link.capturing = mapLink.capturing; link.capturing = mapLink.capturing;
link.filters = mapLink.filters; link.filters = mapLink.filters;
link.link_type = mapLink.linkType; link.link_type = mapLink.linkType;
link.nodes = mapLink.nodes.map(mapLinkNode => this.mapLinkNodeToMapLinkNode.convert(mapLinkNode)); link.nodes = mapLink.nodes.map((mapLinkNode) => this.mapLinkNodeToMapLinkNode.convert(mapLinkNode));
link.project_id = mapLink.projectId; link.project_id = mapLink.projectId;
link.suspend = mapLink.suspend; link.suspend = mapLink.suspend;
return link; return link;

View File

@ -27,7 +27,7 @@ export class MapNodeToNodeConverter implements Converter<MapNode, Node> {
node.node_type = mapNode.nodeType; node.node_type = mapNode.nodeType;
node.port_name_format = mapNode.portNameFormat; node.port_name_format = mapNode.portNameFormat;
node.port_segment_size = mapNode.portSegmentSize; node.port_segment_size = mapNode.portSegmentSize;
node.ports = mapNode.ports ? mapNode.ports.map(mapPort => this.mapPortToPort.convert(mapPort)) : []; node.ports = mapNode.ports ? mapNode.ports.map((mapPort) => this.mapPortToPort.convert(mapPort)) : [];
node.project_id = mapNode.projectId; node.project_id = mapNode.projectId;
node.status = mapNode.status; node.status = mapNode.status;
node.symbol = mapNode.symbol; node.symbol = mapNode.symbol;

View File

@ -29,14 +29,16 @@ export class NodeToMapNodeConverter implements Converter<Node, MapNode> {
mapNode.consoleType = node.console_type; mapNode.consoleType = node.console_type;
mapNode.firstPortName = node.first_port_name; mapNode.firstPortName = node.first_port_name;
mapNode.height = node.height; mapNode.height = node.height;
mapNode.label = this.labelToMapLabel ? this.labelToMapLabel.convert(node.label, { node_id: node.node_id }) : undefined; mapNode.label = this.labelToMapLabel
? this.labelToMapLabel.convert(node.label, { node_id: node.node_id })
: undefined;
mapNode.locked = node.locked; mapNode.locked = node.locked;
mapNode.name = node.name; mapNode.name = node.name;
mapNode.nodeDirectory = node.node_directory; mapNode.nodeDirectory = node.node_directory;
mapNode.nodeType = node.node_type; mapNode.nodeType = node.node_type;
mapNode.portNameFormat = node.port_name_format; mapNode.portNameFormat = node.port_name_format;
mapNode.portSegmentSize = node.port_segment_size; mapNode.portSegmentSize = node.port_segment_size;
mapNode.ports = node.ports ? node.ports.map(port => this.portToMapPort.convert(port)) : []; mapNode.ports = node.ports ? node.ports.map((port) => this.portToMapPort.convert(port)) : [];
mapNode.projectId = node.project_id; mapNode.projectId = node.project_id;
mapNode.status = node.status; mapNode.status = node.status;
mapNode.symbol = node.symbol; mapNode.symbol = node.symbol;

View File

@ -14,7 +14,7 @@ describe('StylesToFontConverter', () => {
const expectedFont: Font = { const expectedFont: Font = {
font_family: 'TypeWriter', font_family: 'TypeWriter',
font_size: 10, font_size: 10,
font_weight: 'bold' font_weight: 'bold',
}; };
expect(converter.convert(styles)).toEqual(expectedFont); expect(converter.convert(styles)).toEqual(expectedFont);

View File

@ -10,30 +10,30 @@ export class StylesToFontConverter implements Converter<string, Font> {
const font: Font = { const font: Font = {
font_family: undefined, font_family: undefined,
font_size: undefined, font_size: undefined,
font_weight: undefined font_weight: undefined,
}; };
const ast = csstree.parse(styles, { const ast = csstree.parse(styles, {
context: 'declarationList' context: 'declarationList',
}); });
ast.children.forEach(child => { ast.children.forEach((child) => {
if (child.property === 'font-size' && child.value && child.value.children) { if (child.property === 'font-size' && child.value && child.value.children) {
child.value.children.forEach(value => { child.value.children.forEach((value) => {
if (value.type === 'Dimension') { if (value.type === 'Dimension') {
font.font_size = parseInt(value.value); font.font_size = parseInt(value.value);
} }
}); });
} }
if (child.property === 'font-family' && child.value && child.value.children) { if (child.property === 'font-family' && child.value && child.value.children) {
child.value.children.forEach(value => { child.value.children.forEach((value) => {
if (value.type === 'Identifier') { if (value.type === 'Identifier') {
font.font_family = value.name; font.font_family = value.name;
} }
}); });
} }
if (child.property === 'font-weight' && child.value && child.value.children) { if (child.property === 'font-weight' && child.value && child.value.children) {
child.value.children.forEach(value => { child.value.children.forEach((value) => {
if (value.type === 'Identifier') { if (value.type === 'Identifier') {
font.font_weight = value.name; font.font_weight = value.name;
} }

View File

@ -37,5 +37,5 @@ export const D3_MAP_IMPORTS = [
LineDrawingWidget, LineDrawingWidget,
RectDrawingWidget, RectDrawingWidget,
TextDrawingWidget, TextDrawingWidget,
DrawingWidget DrawingWidget,
]; ];

View File

@ -20,7 +20,7 @@ export abstract class DataSource<T> {
} }
public set(data: T[]) { public set(data: T[]) {
data.forEach(item => { data.forEach((item) => {
const index = this.findIndex(item); const index = this.findIndex(item);
if (index >= 0) { if (index >= 0) {
const updated = Object.assign(this.data[index], item); const updated = Object.assign(this.data[index], item);
@ -31,9 +31,9 @@ export abstract class DataSource<T> {
}); });
const toRemove = this.data.filter( const toRemove = this.data.filter(
item => data.filter(i => this.getItemKey(i) === this.getItemKey(item)).length === 0 (item) => data.filter((i) => this.getItemKey(i) === this.getItemKey(item)).length === 0
); );
toRemove.forEach(item => this.remove(item)); toRemove.forEach((item) => this.remove(item));
this.dataChange.next(this.data); this.dataChange.next(this.data);
} }

View File

@ -6,10 +6,12 @@ import { MovingCanvasDirective } from './moving-canvas.directive';
import { Component } from '@angular/core'; import { Component } from '@angular/core';
@Component({ @Component({
template: `<svg #svg class="map" preserveAspectRatio="none" movingCanvas><g class="canvas" transform="translate(0, 0) scale(1)"></g></svg>` template: `<svg #svg class="map" preserveAspectRatio="none" movingCanvas>
<g class="canvas" transform="translate(0, 0) scale(1)"></g>
</svg>`,
}) })
class DummyComponent { class DummyComponent {
constructor(){} constructor() {}
} }
describe('MovingCanvasDirective', () => { describe('MovingCanvasDirective', () => {
@ -22,9 +24,9 @@ describe('MovingCanvasDirective', () => {
imports: [NoopAnimationsModule], imports: [NoopAnimationsModule],
providers: [ providers: [
{ provide: MovingEventSource, useValue: movingEventSource }, { provide: MovingEventSource, useValue: movingEventSource },
{ provide: Context, useClass: Context } { provide: Context, useClass: Context },
], ],
declarations: [DummyComponent, MovingCanvasDirective] declarations: [DummyComponent, MovingCanvasDirective],
}).compileComponents(); }).compileComponents();
})); }));
@ -44,21 +46,25 @@ describe('MovingCanvasDirective', () => {
let xMovement: number = 200; let xMovement: number = 200;
let yMovement: number = 200; let yMovement: number = 200;
canvas.dispatchEvent(new MouseEvent('mousedown', { canvas.dispatchEvent(
new MouseEvent('mousedown', {
bubbles: true, bubbles: true,
clientX: 0, clientX: 0,
clientY: 0, clientY: 0,
screenY: 0, screenY: 0,
screenX: 0, screenX: 0,
view: window view: window,
})); })
);
tick(); tick();
canvas.dispatchEvent(new MouseEvent('mousemove', { canvas.dispatchEvent(
new MouseEvent('mousemove', {
bubbles: true, bubbles: true,
relatedTarget: canvas, relatedTarget: canvas,
movementX: xMovement, movementX: xMovement,
movementY: yMovement movementY: yMovement,
} as MouseEventInit)); } as MouseEventInit)
);
tick(); tick();
expect(canvas.getAttribute('transform')).toEqual(`translate(${xMovement}, ${yMovement}) scale(1)`); expect(canvas.getAttribute('transform')).toEqual(`translate(${xMovement}, ${yMovement}) scale(1)`);
@ -67,21 +73,25 @@ describe('MovingCanvasDirective', () => {
it('should not move canvas if moving mode is not activated', fakeAsync(() => { it('should not move canvas if moving mode is not activated', fakeAsync(() => {
const canvas: HTMLElement = fixture.debugElement.nativeElement.querySelector('.canvas'); const canvas: HTMLElement = fixture.debugElement.nativeElement.querySelector('.canvas');
canvas.dispatchEvent(new MouseEvent('mousedown', { canvas.dispatchEvent(
new MouseEvent('mousedown', {
bubbles: true, bubbles: true,
clientX: 0, clientX: 0,
clientY: 0, clientY: 0,
screenY: 0, screenY: 0,
screenX: 0, screenX: 0,
view: window view: window,
})); })
);
tick(); tick();
canvas.dispatchEvent(new MouseEvent('mousemove', { canvas.dispatchEvent(
new MouseEvent('mousemove', {
bubbles: true, bubbles: true,
relatedTarget: canvas, relatedTarget: canvas,
movementX: 1000, movementX: 1000,
movementY: 1000 movementY: 1000,
} as MouseEventInit)); } as MouseEventInit)
);
tick(); tick();
expect(canvas.getAttribute('transform')).toEqual('translate(0, 0) scale(1)'); expect(canvas.getAttribute('transform')).toEqual('translate(0, 0) scale(1)');
@ -93,38 +103,46 @@ describe('MovingCanvasDirective', () => {
let xMovement: number = 200; let xMovement: number = 200;
let yMovement: number = 200; let yMovement: number = 200;
canvas.dispatchEvent(new MouseEvent('mousedown', { canvas.dispatchEvent(
new MouseEvent('mousedown', {
bubbles: true, bubbles: true,
clientX: 0, clientX: 0,
clientY: 0, clientY: 0,
screenY: 0, screenY: 0,
screenX: 0, screenX: 0,
view: window view: window,
})); })
);
tick(); tick();
canvas.dispatchEvent(new MouseEvent('mousemove', { canvas.dispatchEvent(
new MouseEvent('mousemove', {
bubbles: true, bubbles: true,
relatedTarget: canvas, relatedTarget: canvas,
movementX: xMovement, movementX: xMovement,
movementY: yMovement movementY: yMovement,
} as MouseEventInit)); } as MouseEventInit)
);
tick(); tick();
expect(canvas.getAttribute('transform')).toEqual(`translate(${xMovement}, ${yMovement}) scale(1)`); expect(canvas.getAttribute('transform')).toEqual(`translate(${xMovement}, ${yMovement}) scale(1)`);
canvas.dispatchEvent(new MouseEvent('mouseup', { canvas.dispatchEvent(
new MouseEvent('mouseup', {
bubbles: true, bubbles: true,
relatedTarget: canvas, relatedTarget: canvas,
movementX: 1000, movementX: 1000,
movementY: 1000 movementY: 1000,
} as MouseEventInit)); } as MouseEventInit)
);
tick(); tick();
canvas.dispatchEvent(new MouseEvent('mousemove', { canvas.dispatchEvent(
new MouseEvent('mousemove', {
bubbles: true, bubbles: true,
relatedTarget: canvas, relatedTarget: canvas,
movementX: xMovement, movementX: xMovement,
movementY: yMovement movementY: yMovement,
} as MouseEventInit)); } as MouseEventInit)
);
tick(); tick();
expect(canvas.getAttribute('transform')).toEqual(`translate(${xMovement}, ${yMovement}) scale(1)`); expect(canvas.getAttribute('transform')).toEqual(`translate(${xMovement}, ${yMovement}) scale(1)`);
@ -136,32 +154,38 @@ describe('MovingCanvasDirective', () => {
let xMovement: number = 200; let xMovement: number = 200;
let yMovement: number = 200; let yMovement: number = 200;
canvas.dispatchEvent(new MouseEvent('mousedown', { canvas.dispatchEvent(
new MouseEvent('mousedown', {
bubbles: true, bubbles: true,
clientX: 0, clientX: 0,
clientY: 0, clientY: 0,
screenY: 0, screenY: 0,
screenX: 0, screenX: 0,
view: window view: window,
})); })
);
tick(); tick();
canvas.dispatchEvent(new MouseEvent('mousemove', { canvas.dispatchEvent(
new MouseEvent('mousemove', {
bubbles: true, bubbles: true,
relatedTarget: canvas, relatedTarget: canvas,
movementX: xMovement, movementX: xMovement,
movementY: yMovement movementY: yMovement,
} as MouseEventInit)); } as MouseEventInit)
);
tick(); tick();
expect(canvas.getAttribute('transform')).toEqual(`translate(${xMovement}, ${yMovement}) scale(1)`); expect(canvas.getAttribute('transform')).toEqual(`translate(${xMovement}, ${yMovement}) scale(1)`);
movingEventSource.movingModeState.emit(false); movingEventSource.movingModeState.emit(false);
canvas.dispatchEvent(new MouseEvent('mousemove', { canvas.dispatchEvent(
new MouseEvent('mousemove', {
bubbles: true, bubbles: true,
relatedTarget: canvas, relatedTarget: canvas,
movementX: 1000, movementX: 1000,
movementY: 1000 movementY: 1000,
} as MouseEventInit)); } as MouseEventInit)
);
tick(); tick();
expect(canvas.getAttribute('transform')).toEqual(`translate(${xMovement}, ${yMovement}) scale(1)`); expect(canvas.getAttribute('transform')).toEqual(`translate(${xMovement}, ${yMovement}) scale(1)`);

View File

@ -1,4 +1,4 @@
import { HostListener, ElementRef, Directive, Input, OnInit, OnDestroy, Renderer2 } from '@angular/core' import { HostListener, ElementRef, Directive, Input, OnInit, OnDestroy, Renderer2 } from '@angular/core';
import { Subscription } from 'rxjs'; import { Subscription } from 'rxjs';
import { MovingEventSource } from '../events/moving-event-source'; import { MovingEventSource } from '../events/moving-event-source';
import { Context } from '../models/context'; import { Context } from '../models/context';
@ -13,11 +13,7 @@ export class MovingCanvasDirective implements OnInit, OnDestroy {
private movingModeState: Subscription; private movingModeState: Subscription;
private activated: boolean = false; private activated: boolean = false;
constructor( constructor(private element: ElementRef, private movingEventSource: MovingEventSource, private context: Context) {}
private element: ElementRef,
private movingEventSource: MovingEventSource,
private context: Context
) {}
ngOnInit() { ngOnInit() {
this.movingModeState = this.movingEventSource.movingModeState.subscribe((event: boolean) => { this.movingModeState = this.movingEventSource.movingModeState.subscribe((event: boolean) => {
@ -53,13 +49,25 @@ export class MovingCanvasDirective implements OnInit, OnDestroy {
this.removelisteners(); this.removelisteners();
}; };
this.element.nativeElement.addEventListener('mouseup', this.mouseupListener as EventListenerOrEventListenerObject); this.element.nativeElement.addEventListener(
this.element.nativeElement.addEventListener('mousemove', this.mousemoveListener as EventListenerOrEventListenerObject); 'mouseup',
this.mouseupListener as EventListenerOrEventListenerObject
);
this.element.nativeElement.addEventListener(
'mousemove',
this.mousemoveListener as EventListenerOrEventListenerObject
);
} }
} }
removelisteners() { removelisteners() {
this.element.nativeElement.removeEventListener('mouseup', this.mouseupListener as EventListenerOrEventListenerObject); this.element.nativeElement.removeEventListener(
this.element.nativeElement.removeEventListener('mousemove', this.mousemoveListener as EventListenerOrEventListenerObject); 'mouseup',
this.mouseupListener as EventListenerOrEventListenerObject
);
this.element.nativeElement.removeEventListener(
'mousemove',
this.mousemoveListener as EventListenerOrEventListenerObject
);
} }
} }

View File

@ -7,10 +7,12 @@ import { ZoomingCanvasDirective } from './zooming-canvas.directive';
import { MapScaleService } from '../../services/mapScale.service'; import { MapScaleService } from '../../services/mapScale.service';
@Component({ @Component({
template: `<svg #svg class="map" preserveAspectRatio="none" zoomingCanvas><g class="canvas" transform="translate(0, 0) scale(1)"></g></svg>` template: `<svg #svg class="map" preserveAspectRatio="none" zoomingCanvas>
<g class="canvas" transform="translate(0, 0) scale(1)"></g>
</svg>`,
}) })
class DummyComponent { class DummyComponent {
constructor(){} constructor() {}
} }
describe('ZoomingCanvasDirective', () => { describe('ZoomingCanvasDirective', () => {
@ -24,9 +26,9 @@ describe('ZoomingCanvasDirective', () => {
providers: [ providers: [
{ provide: MovingEventSource, useValue: movingEventSource }, { provide: MovingEventSource, useValue: movingEventSource },
{ provide: Context, useClass: Context }, { provide: Context, useClass: Context },
{ provide: MapScaleService, useClass: MapScaleService } { provide: MapScaleService, useClass: MapScaleService },
], ],
declarations: [DummyComponent, ZoomingCanvasDirective] declarations: [DummyComponent, ZoomingCanvasDirective],
}).compileComponents(); }).compileComponents();
})); }));
@ -46,12 +48,14 @@ describe('ZoomingCanvasDirective', () => {
let deltaMode: number = 0; let deltaMode: number = 0;
let zoom: number = -1000; let zoom: number = -1000;
canvas.dispatchEvent(new WheelEvent('wheel', { canvas.dispatchEvent(
new WheelEvent('wheel', {
bubbles: true, bubbles: true,
relatedTarget: canvas, relatedTarget: canvas,
deltaMode: deltaMode, deltaMode: deltaMode,
deltaY: zoom deltaY: zoom,
})); })
);
tick(); tick();
expect(canvas.getAttribute('transform')).toEqual(`translate(0, 0) scale(2)`); expect(canvas.getAttribute('transform')).toEqual(`translate(0, 0) scale(2)`);
@ -63,12 +67,14 @@ describe('ZoomingCanvasDirective', () => {
let deltaMode: number = 0; let deltaMode: number = 0;
let zoom: number = 100; let zoom: number = 100;
canvas.dispatchEvent(new WheelEvent('wheel', { canvas.dispatchEvent(
new WheelEvent('wheel', {
bubbles: true, bubbles: true,
relatedTarget: canvas, relatedTarget: canvas,
deltaMode: deltaMode, deltaMode: deltaMode,
deltaY: zoom deltaY: zoom,
})); })
);
tick(); tick();
expect(canvas.getAttribute('transform')).toEqual(`translate(0, 0) scale(0.9)`); expect(canvas.getAttribute('transform')).toEqual(`translate(0, 0) scale(0.9)`);
@ -80,23 +86,27 @@ describe('ZoomingCanvasDirective', () => {
let deltaMode: number = 0; let deltaMode: number = 0;
let zoom: number = -1000; let zoom: number = -1000;
canvas.dispatchEvent(new WheelEvent('wheel', { canvas.dispatchEvent(
new WheelEvent('wheel', {
bubbles: true, bubbles: true,
relatedTarget: canvas, relatedTarget: canvas,
deltaMode: deltaMode, deltaMode: deltaMode,
deltaY: zoom deltaY: zoom,
})); })
);
tick(); tick();
expect(canvas.getAttribute('transform')).toEqual(`translate(0, 0) scale(2)`); expect(canvas.getAttribute('transform')).toEqual(`translate(0, 0) scale(2)`);
movingEventSource.movingModeState.emit(false); movingEventSource.movingModeState.emit(false);
canvas.dispatchEvent(new WheelEvent('wheel', { canvas.dispatchEvent(
new WheelEvent('wheel', {
bubbles: true, bubbles: true,
relatedTarget: canvas, relatedTarget: canvas,
deltaMode: deltaMode, deltaMode: deltaMode,
deltaY: zoom deltaY: zoom,
})); })
);
tick(); tick();
expect(canvas.getAttribute('transform')).toEqual(`translate(0, 0) scale(2)`); expect(canvas.getAttribute('transform')).toEqual(`translate(0, 0) scale(2)`);
@ -107,12 +117,14 @@ describe('ZoomingCanvasDirective', () => {
let deltaMode: number = 0; let deltaMode: number = 0;
let zoom: number = -1000; let zoom: number = -1000;
canvas.dispatchEvent(new WheelEvent('wheel', { canvas.dispatchEvent(
new WheelEvent('wheel', {
bubbles: true, bubbles: true,
relatedTarget: canvas, relatedTarget: canvas,
deltaMode: deltaMode, deltaMode: deltaMode,
deltaY: zoom deltaY: zoom,
})); })
);
tick(); tick();
expect(canvas.getAttribute('transform')).toEqual(`translate(0, 0) scale(1)`); expect(canvas.getAttribute('transform')).toEqual(`translate(0, 0) scale(1)`);
@ -127,7 +139,7 @@ describe('ZoomingCanvasDirective', () => {
bubbles: true, bubbles: true,
relatedTarget: canvas, relatedTarget: canvas,
deltaMode: deltaMode, deltaMode: deltaMode,
deltaY: zoom deltaY: zoom,
}); });
spyOn(event, 'preventDefault'); spyOn(event, 'preventDefault');

View File

@ -1,4 +1,4 @@
import { ElementRef, Directive, OnInit, OnDestroy } from '@angular/core' import { ElementRef, Directive, OnInit, OnDestroy } from '@angular/core';
import { Subscription } from 'rxjs'; import { Subscription } from 'rxjs';
import { MovingEventSource } from '../events/moving-event-source'; import { MovingEventSource } from '../events/moving-event-source';
import { Context } from '../models/context'; import { Context } from '../models/context';
@ -35,13 +35,13 @@ export class ZoomingCanvasDirective implements OnInit, OnDestroy {
event.preventDefault(); event.preventDefault();
let zoom = event.deltaY; let zoom = event.deltaY;
zoom = event.deltaMode === 0 ? zoom/100 : zoom/3; zoom = event.deltaMode === 0 ? zoom / 100 : zoom / 3;
const view = select(this.element.nativeElement); const view = select(this.element.nativeElement);
const canvas = view.selectAll<SVGGElement, Context>('g.canvas').data([this.context]); const canvas = view.selectAll<SVGGElement, Context>('g.canvas').data([this.context]);
canvas.attr('transform', () => { canvas.attr('transform', () => {
this.context.transformation.k = this.context.transformation.k - zoom/10; this.context.transformation.k = this.context.transformation.k - zoom / 10;
const xTrans = this.context.getZeroZeroTransformationPoint().x + this.context.transformation.x; const xTrans = this.context.getZeroZeroTransformationPoint().x + this.context.transformation.x;
const yTrans = this.context.getZeroZeroTransformationPoint().y + this.context.transformation.y; const yTrans = this.context.getZeroZeroTransformationPoint().y + this.context.transformation.y;
@ -52,7 +52,9 @@ export class ZoomingCanvasDirective implements OnInit, OnDestroy {
}); });
}; };
this.element.nativeElement.addEventListener('wheel', this.wheelListener as EventListenerOrEventListenerObject, {passive: false}); this.element.nativeElement.addEventListener('wheel', this.wheelListener as EventListenerOrEventListenerObject, {
passive: false,
});
} }
removeListener() { removeListener() {

View File

@ -4,7 +4,7 @@ import {
ResizedDataEvent, ResizedDataEvent,
TextAddedDataEvent, TextAddedDataEvent,
TextEditedDataEvent, TextEditedDataEvent,
AddedDataEvent AddedDataEvent,
} from './event-source'; } from './event-source';
import { MapDrawing } from '../models/map/map-drawing'; import { MapDrawing } from '../models/map/map-drawing';

View File

@ -1,4 +1,4 @@
import { Injectable, EventEmitter } from "@angular/core"; import { Injectable, EventEmitter } from '@angular/core';
@Injectable() @Injectable()
export class MovingEventSource { export class MovingEventSource {

View File

@ -6,13 +6,13 @@ import { Injectable } from '@angular/core';
export class CssFixer { export class CssFixer {
public fix(styles: string): string { public fix(styles: string): string {
const ast = csstree.parse(styles, { const ast = csstree.parse(styles, {
context: 'declarationList' context: 'declarationList',
}); });
// fixes font-size when unit (pt|px) is not defined // fixes font-size when unit (pt|px) is not defined
ast.children.forEach(child => { ast.children.forEach((child) => {
if (child.property === 'font-size' && child.value && child.value.children) { if (child.property === 'font-size' && child.value && child.value.children) {
child.value.children.forEach(value => { child.value.children.forEach((value) => {
if (value.type === 'Number') { if (value.type === 'Number') {
const fontSize = value.value.toString(); const fontSize = value.value.toString();
if (!(fontSize.indexOf('pt') >= 0 || fontSize.indexOf('px') >= 0)) { if (!(fontSize.indexOf('pt') >= 0 || fontSize.indexOf('px') >= 0)) {

View File

@ -21,7 +21,7 @@ export class DefaultDrawingsFactory {
text: this.textElementFactory, text: this.textElementFactory,
ellipse: this.ellipseElementFactory, ellipse: this.ellipseElementFactory,
rectangle: this.rectangleElementFactory, rectangle: this.rectangleElementFactory,
line: this.lineElementFactory line: this.lineElementFactory,
}; };
} }

View File

@ -14,7 +14,7 @@ export class FontBBoxCalculator {
return { return {
width: bbox.width, width: bbox.width,
height: bbox.height height: bbox.height,
}; };
} }
} }

View File

@ -12,13 +12,13 @@ describe('FontFixer', () => {
const font: Font = { const font: Font = {
font_family: 'TypeWriter', font_family: 'TypeWriter',
font_size: 10, font_size: 10,
font_weight: 'bold' font_weight: 'bold',
}; };
expect(fixer.fix(font)).toEqual({ expect(fixer.fix(font)).toEqual({
font_family: 'Noto Sans', font_family: 'Noto Sans',
font_size: 11, font_size: 11,
font_weight: 'bold' font_weight: 'bold',
}); });
}); });
@ -26,13 +26,13 @@ describe('FontFixer', () => {
const font: Font = { const font: Font = {
font_family: 'OtherFont', font_family: 'OtherFont',
font_size: 11, font_size: 11,
font_weight: 'bold' font_weight: 'bold',
}; };
expect(fixer.fix(font)).toEqual({ expect(fixer.fix(font)).toEqual({
font_family: 'OtherFont', font_family: 'OtherFont',
font_size: 11, font_size: 11,
font_weight: 'bold' font_weight: 'bold',
}); });
}); });

View File

@ -22,16 +22,16 @@ export class FontFixer {
public fixStyles(styles: string) { public fixStyles(styles: string) {
const ast = csstree.parse(styles, { const ast = csstree.parse(styles, {
context: 'declarationList' context: 'declarationList',
}); });
let fontFamilyPointer = null; let fontFamilyPointer = null;
let fontSizePointer = null; let fontSizePointer = null;
let isByIdentifier = true; let isByIdentifier = true;
ast.children.forEach(child => { ast.children.forEach((child) => {
if (child.property === 'font-family' && child.value && child.value.children) { if (child.property === 'font-family' && child.value && child.value.children) {
child.value.children.forEach(value => { child.value.children.forEach((value) => {
if (value.type === 'Identifier') { if (value.type === 'Identifier') {
fontFamilyPointer = value; fontFamilyPointer = value;
} }
@ -42,7 +42,7 @@ export class FontFixer {
}); });
} }
if (child.property === 'font-size' && child.value && child.value.children) { if (child.property === 'font-size' && child.value && child.value.children) {
child.value.children.forEach(value => { child.value.children.forEach((value) => {
if (value.type === 'Dimension') { if (value.type === 'Dimension') {
fontSizePointer = value; fontSizePointer = value;
} }
@ -62,7 +62,7 @@ export class FontFixer {
const fixedFont = this.fix({ const fixedFont = this.fix({
font_family: fontFamilyValue.split('"').join(''), font_family: fontFamilyValue.split('"').join(''),
font_size: parseInt(fontSizeValue, 10) font_size: parseInt(fontSizeValue, 10),
} as Font); } as Font);
if (isByIdentifier) { if (isByIdentifier) {

View File

@ -25,7 +25,7 @@ export class MultiLinkCalculatorHelper {
} }
return { return {
dx: x2_x0, dx: x2_x0,
dy: y2_y0 dy: y2_y0,
}; };
} }

View File

@ -11,7 +11,7 @@ export class QtDasharrayFixer {
'25, 25': '10, 2', '25, 25': '10, 2',
'5, 25': '4, 2', '5, 25': '4, 2',
'5, 25, 25': '5, 5, 1, 5', '5, 25, 25': '5, 5, 1, 5',
'25, 25, 5, 25, 5': '5, 2, 5, 2, 5' '25, 25, 5, 25, 5': '5, 2, 5, 2, 5',
}; };
public fix(dasharray: string): string { public fix(dasharray: string): string {

View File

@ -19,7 +19,7 @@ export class SvgToDrawingConverter {
image: new ImageConverter(), image: new ImageConverter(),
rect: new RectConverter(), rect: new RectConverter(),
line: new LineConverter(), line: new LineConverter(),
ellipse: new EllipseConverter() ellipse: new EllipseConverter(),
}; };
} }

View File

@ -14,7 +14,7 @@ import {
MapNodesDataSource, MapNodesDataSource,
MapLinksDataSource, MapLinksDataSource,
MapDrawingsDataSource, MapDrawingsDataSource,
MapSymbolsDataSource MapSymbolsDataSource,
} from '../datasources/map-datasource'; } from '../datasources/map-datasource';
import { MultiLinkCalculatorHelper } from '../helpers/multi-link-calculator-helper'; import { MultiLinkCalculatorHelper } from '../helpers/multi-link-calculator-helper';
@ -35,7 +35,7 @@ export class GraphDataManager {
public setNodes(nodes: Node[]) { public setNodes(nodes: Node[]) {
if (nodes) { if (nodes) {
const mapNodes = nodes.map(n => this.nodeToMapNode.convert(n)); const mapNodes = nodes.map((n) => this.nodeToMapNode.convert(n));
this.mapNodesDataSource.set(mapNodes); this.mapNodesDataSource.set(mapNodes);
this.assignDataToLinks(); this.assignDataToLinks();
@ -45,7 +45,7 @@ export class GraphDataManager {
public setLinks(links: Link[]) { public setLinks(links: Link[]) {
if (links) { if (links) {
const mapLinks = links.map(l => this.linkToMapLink.convert(l)); const mapLinks = links.map((l) => this.linkToMapLink.convert(l));
this.mapLinksDataSource.set(mapLinks); this.mapLinksDataSource.set(mapLinks);
this.assignDataToLinks(); this.assignDataToLinks();
@ -55,7 +55,7 @@ export class GraphDataManager {
public setDrawings(drawings: Drawing[]) { public setDrawings(drawings: Drawing[]) {
if (drawings) { if (drawings) {
const mapDrawings = drawings.map(d => this.drawingToMapDrawing.convert(d)); const mapDrawings = drawings.map((d) => this.drawingToMapDrawing.convert(d));
this.mapDrawingsDataSource.set(mapDrawings); this.mapDrawingsDataSource.set(mapDrawings);
this.onDataUpdate(); this.onDataUpdate();
@ -64,7 +64,7 @@ export class GraphDataManager {
public setSymbols(symbols: Symbol[]) { public setSymbols(symbols: Symbol[]) {
if (symbols) { if (symbols) {
const mapSymbols = symbols.map(s => this.symbolToMapSymbol.convert(s)); const mapSymbols = symbols.map((s) => this.symbolToMapSymbol.convert(s));
this.mapSymbolsDataSource.set(mapSymbols); this.mapSymbolsDataSource.set(mapSymbols);
} }
} }

View File

@ -13,16 +13,16 @@ export class SelectionManager {
const dictItems = this.convertToKeyDict(items); const dictItems = this.convertToKeyDict(items);
const selected = Object.keys(dictItems) const selected = Object.keys(dictItems)
.filter(key => { .filter((key) => {
return !this.isSelectedByKey(key); return !this.isSelectedByKey(key);
}) })
.map(key => dictItems[key]); .map((key) => dictItems[key]);
const unselected = Object.keys(this.selection) const unselected = Object.keys(this.selection)
.filter(key => { .filter((key) => {
return !(key in dictItems); return !(key in dictItems);
}) })
.map(key => this.selection[key]); .map((key) => this.selection[key]);
this.selection = dictItems; this.selection = dictItems;
@ -36,7 +36,7 @@ export class SelectionManager {
} }
public getSelected(): Indexed[] { public getSelected(): Indexed[] {
return Object.keys(this.selection).map(key => this.selection[key]); return Object.keys(this.selection).map((key) => this.selection[key]);
} }
public isSelected(item): boolean { public isSelected(item): boolean {
@ -55,7 +55,7 @@ export class SelectionManager {
private convertToKeyDict(items: Indexed[]) { private convertToKeyDict(items: Indexed[]) {
const dict = {}; const dict = {};
items.forEach(item => { items.forEach((item) => {
dict[this.getKey(item)] = item; dict[this.getKey(item)] = item;
}); });
return dict; return dict;

View File

@ -9,17 +9,12 @@ export class TestSVGCanvas {
} }
public create() { public create() {
this.svg = select('body') this.svg = select('body').append<SVGSVGElement>('svg').attr('width', 1000).attr('height', 1000);
.append<SVGSVGElement>('svg')
.attr('width', 1000)
.attr('height', 1000);
this.canvas = this.svg.append<SVGGElement>('g').attr('class', 'canvas'); this.canvas = this.svg.append<SVGGElement>('g').attr('class', 'canvas');
} }
public destroy() { public destroy() {
select('body') select('body').selectAll('svg').remove();
.selectAll('svg')
.remove();
} }
} }

View File

@ -16,11 +16,7 @@ describe('MovingTool', () => {
tool = new MovingTool(context); tool = new MovingTool(context);
svg = new TestSVGCanvas(); svg = new TestSVGCanvas();
node = svg.canvas node = svg.canvas.append<SVGGElement>('g').attr('class', 'node').attr('x', 10).attr('y', 20);
.append<SVGGElement>('g')
.attr('class', 'node')
.attr('x', 10)
.attr('y', 20);
tool.setEnabled(true); tool.setEnabled(true);
tool.draw(svg.svg, context); tool.draw(svg.svg, context);
@ -39,7 +35,7 @@ describe('MovingTool', () => {
relatedTarget: svg.svg.node(), relatedTarget: svg.svg.node(),
screenY: 1024, screenY: 1024,
screenX: 1024, screenX: 1024,
view: window view: window,
}) })
); );
@ -70,7 +66,7 @@ describe('MovingTool', () => {
relatedTarget: svg.svg.node(), relatedTarget: svg.svg.node(),
screenY: 1024, screenY: 1024,
screenX: 1024, screenX: 1024,
view: window view: window,
}) })
); );
@ -101,7 +97,7 @@ describe('MovingTool', () => {
relatedTarget: svg.svg.node(), relatedTarget: svg.svg.node(),
screenY: 1024, screenY: 1024,
screenX: 1024, screenX: 1024,
view: window view: window,
}) })
); );

View File

@ -42,7 +42,7 @@ export class MovingTool {
private activate(selection: SVGSelection) { private activate(selection: SVGSelection) {
const self = this; const self = this;
const onZoom = function(this: SVGSVGElement) { const onZoom = function (this: SVGSVGElement) {
const canvas = selection.select<SVGGElement>('g.canvas'); const canvas = selection.select<SVGGElement>('g.canvas');
const e: D3ZoomEvent<SVGSVGElement, any> = event; const e: D3ZoomEvent<SVGSVGElement, any> = event;
canvas.attr('transform', () => { canvas.attr('transform', () => {

View File

@ -17,14 +17,9 @@ export class SelectionTool {
private path; private path;
private enabled = false; private enabled = false;
public constructor( public constructor(private context: Context, private selectionEventSource: SelectionEventSource) {}
private context: Context,
private selectionEventSource: SelectionEventSource
) {}
public disableContextMenu(){ public disableContextMenu() {}
}
public setEnabled(enabled) { public setEnabled(enabled) {
this.enabled = enabled; this.enabled = enabled;
@ -34,7 +29,7 @@ export class SelectionTool {
private activate(selection) { private activate(selection) {
const self = this; const self = this;
selection.on('mousedown', function() { selection.on('mousedown', function () {
// prevent deselection on right click // prevent deselection on right click
if (event.button == 2) { if (event.button == 2) {
selection.on('contextmenu', () => { selection.on('contextmenu', () => {
@ -55,11 +50,11 @@ export class SelectionTool {
selection.selectAll(SelectionTool.SELECTABLE_CLASS).classed('selected', false); selection.selectAll(SelectionTool.SELECTABLE_CLASS).classed('selected', false);
subject subject
.on('mousemove.selection', function() { .on('mousemove.selection', function () {
const end = self.transformation(mouse(parent)); const end = self.transformation(mouse(parent));
self.moveSelection(start, end); self.moveSelection(start, end);
}) })
.on('mouseup.selection', function() { .on('mouseup.selection', function () {
const end = self.transformation(mouse(parent)); const end = self.transformation(mouse(parent));
self.endSelection(start, end); self.endSelection(start, end);
subject.on('mousemove.selection', null).on('mouseup.selection', null); subject.on('mousemove.selection', null).on('mouseup.selection', null);
@ -100,9 +95,12 @@ export class SelectionTool {
} }
private moveSelection(start, move) { private moveSelection(start, move) {
let x = start[0]/this.context.transformation.k; let x = start[0] / this.context.transformation.k;
let y = start[1]/this.context.transformation.k; let y = start[1] / this.context.transformation.k;
this.path.attr('d', this.rect(x, y, move[0]/this.context.transformation.k - x, move[1]/this.context.transformation.k - y)); this.path.attr(
'd',
this.rect(x, y, move[0] / this.context.transformation.k - x, move[1] / this.context.transformation.k - y)
);
this.selectedEvent(start, move); this.selectedEvent(start, move);
} }
@ -127,7 +125,7 @@ export class SelectionTool {
const transformation_point = this.context.getZeroZeroTransformationPoint(); const transformation_point = this.context.getZeroZeroTransformationPoint();
return [ return [
point[0] - transformation_point.x - this.context.transformation.x, point[0] - transformation_point.x - this.context.transformation.x,
point[1] - transformation_point.y - this.context.transformation.y point[1] - transformation_point.y - this.context.transformation.y,
]; ];
} }
} }

View File

@ -23,7 +23,7 @@ export class DrawingLineWidget {
this.drawingLine.start = new Point(x, y); this.drawingLine.start = new Point(x, y);
this.drawingLine.end = new Point(x, y); this.drawingLine.end = new Point(x, y);
const over = function(this, d, i) { const over = function (this, d, i) {
const node = self.selection.select<SVGGElement>('g.canvas').node(); const node = self.selection.select<SVGGElement>('g.canvas').node();
const coordinates = mouse(node); const coordinates = mouse(node);
self.drawingLine.end.x = coordinates[0]; self.drawingLine.end.x = coordinates[0];
@ -60,7 +60,10 @@ export class DrawingLineWidget {
if (this.drawing) { if (this.drawing) {
link_data = [ link_data = [
[[this.drawingLine.start.x, this.drawingLine.start.y], [this.drawingLine.end.x, this.drawingLine.end.y]] [
[this.drawingLine.start.x, this.drawingLine.start.y],
[this.drawingLine.end.x, this.drawingLine.end.y],
],
]; ];
} }
@ -72,11 +75,7 @@ export class DrawingLineWidget {
const enter = tool.enter().append<SVGPathElement>('path'); const enter = tool.enter().append<SVGPathElement>('path');
tool tool.merge(enter).attr('d', value_line).attr('stroke', '#000').attr('stroke-width', '2');
.merge(enter)
.attr('d', value_line)
.attr('stroke', '#000')
.attr('stroke-width', '2');
tool.exit().remove(); tool.exit().remove();
} }

View File

@ -33,52 +33,49 @@ export class DrawingWidget implements Widget {
this.imageDrawingWidget, this.imageDrawingWidget,
this.rectDrawingWidget, this.rectDrawingWidget,
this.lineDrawingWidget, this.lineDrawingWidget,
this.ellipseDrawingWidget this.ellipseDrawingWidget,
]; ];
} }
public draw(view: SVGSelection) { public draw(view: SVGSelection) {
const drawing_body = view.selectAll<SVGGElement, MapDrawing>('g.drawing_body').data((l: MapDrawing) => [l]); const drawing_body = view.selectAll<SVGGElement, MapDrawing>('g.drawing_body').data((l: MapDrawing) => [l]);
const drawing_body_enter = drawing_body const drawing_body_enter = drawing_body.enter().append<SVGGElement>('g').attr('class', 'drawing_body');
.enter()
.append<SVGGElement>('g')
.attr('class', 'drawing_body');
const drawing_body_merge = drawing_body.merge(drawing_body_enter).attr('transform', (d: MapDrawing) => { const drawing_body_merge = drawing_body.merge(drawing_body_enter).attr('transform', (d: MapDrawing) => {
return `translate(${d.x},${d.y}) rotate(${d.rotation})`; return `translate(${d.x},${d.y}) rotate(${d.rotation})`;
}); });
this.drawingWidgets.forEach(widget => { this.drawingWidgets.forEach((widget) => {
widget.draw(drawing_body_merge); widget.draw(drawing_body_merge);
}); });
drawing_body_merge.select('.layer_label_wrapper').remove(); drawing_body_merge.select('.layer_label_wrapper').remove();
if (this.mapSettingsService.isLayerNumberVisible) { if (this.mapSettingsService.isLayerNumberVisible) {
drawing_body_merge drawing_body_merge
.filter(n => ((n.element instanceof RectElement) || (n.element instanceof EllipseElement))) .filter((n) => n.element instanceof RectElement || n.element instanceof EllipseElement)
.append<SVGRectElement>('rect') .append<SVGRectElement>('rect')
.attr('class', 'layer_label_wrapper') .attr('class', 'layer_label_wrapper')
.attr('width', '26') .attr('width', '26')
.attr('height', '26') .attr('height', '26')
.attr('x', n => n.element ? n.element.width/2 - 13 : 0) .attr('x', (n) => (n.element ? n.element.width / 2 - 13 : 0))
.attr('y', n => n.element ? n.element.height/2 - 13 : 0) .attr('y', (n) => (n.element ? n.element.height / 2 - 13 : 0))
.attr('fill', 'red'); .attr('fill', 'red');
} }
drawing_body_merge.select('.layer_label').remove(); drawing_body_merge.select('.layer_label').remove();
if (this.mapSettingsService.isLayerNumberVisible) { if (this.mapSettingsService.isLayerNumberVisible) {
drawing_body_merge drawing_body_merge
.filter(n => ((n.element instanceof RectElement) || (n.element instanceof EllipseElement))) .filter((n) => n.element instanceof RectElement || n.element instanceof EllipseElement)
.append<SVGTextElement>('text') .append<SVGTextElement>('text')
.attr('class', 'layer_label') .attr('class', 'layer_label')
.text((elem) => elem.z) .text((elem) => elem.z)
.attr('x', function(n) { .attr('x', function (n) {
if(n.z >= 100 ) return n.element ? n.element.width/2 - 13 : 0 if (n.z >= 100) return n.element ? n.element.width / 2 - 13 : 0;
else if(n.z >= 10 ) return n.element ? n.element.width/2 - 9 : 0 else if (n.z >= 10) return n.element ? n.element.width / 2 - 9 : 0;
else return n.element.width/2 - 5 else return n.element.width / 2 - 5;
}) })
.attr('y', n => n.element ? n.element.height/2 + 5 : 0) .attr('y', (n) => (n.element ? n.element.height / 2 + 5 : 0))
.attr('style', () => { .attr('style', () => {
const styles: string[] = []; const styles: string[] = [];
styles.push(`font-family: "Noto Sans"`); styles.push(`font-family: "Noto Sans"`);
@ -93,10 +90,10 @@ export class DrawingWidget implements Widget {
.select<SVGAElement>('line.top') .select<SVGAElement>('line.top')
.attr('stroke', 'transparent') .attr('stroke', 'transparent')
.attr('stroke-width', '8px') .attr('stroke-width', '8px')
.attr('x1', drawing => .attr('x1', (drawing) =>
drawing.element instanceof EllipseElement ? drawing.element.cx - drawing.element.width / 10 : '0' drawing.element instanceof EllipseElement ? drawing.element.cx - drawing.element.width / 10 : '0'
) )
.attr('x2', drawing => .attr('x2', (drawing) =>
drawing.element instanceof EllipseElement drawing.element instanceof EllipseElement
? drawing.element.cx + drawing.element.width / 10 ? drawing.element.cx + drawing.element.width / 10
: drawing.element.width : drawing.element.width
@ -110,16 +107,16 @@ export class DrawingWidget implements Widget {
.select<SVGAElement>('line.bottom') .select<SVGAElement>('line.bottom')
.attr('stroke', 'transparent') .attr('stroke', 'transparent')
.attr('stroke-width', '8px') .attr('stroke-width', '8px')
.attr('x1', drawing => .attr('x1', (drawing) =>
drawing.element instanceof EllipseElement ? drawing.element.cx - drawing.element.width / 10 : '0' drawing.element instanceof EllipseElement ? drawing.element.cx - drawing.element.width / 10 : '0'
) )
.attr('x2', drawing => .attr('x2', (drawing) =>
drawing.element instanceof EllipseElement drawing.element instanceof EllipseElement
? drawing.element.cx + drawing.element.width / 10 ? drawing.element.cx + drawing.element.width / 10
: drawing.element.width : drawing.element.width
) )
.attr('y1', drawing => drawing.element.height) .attr('y1', (drawing) => drawing.element.height)
.attr('y2', drawing => drawing.element.height) .attr('y2', (drawing) => drawing.element.height)
.attr('draggable', 'true') .attr('draggable', 'true')
.attr('cursor', 'ns-resize'); .attr('cursor', 'ns-resize');
@ -129,10 +126,10 @@ export class DrawingWidget implements Widget {
.attr('stroke-width', '8px') .attr('stroke-width', '8px')
.attr('x1', '0') .attr('x1', '0')
.attr('x2', '0') .attr('x2', '0')
.attr('y1', drawing => .attr('y1', (drawing) =>
drawing.element instanceof EllipseElement ? drawing.element.cy - drawing.element.height / 10 : '0' drawing.element instanceof EllipseElement ? drawing.element.cy - drawing.element.height / 10 : '0'
) )
.attr('y2', drawing => .attr('y2', (drawing) =>
drawing.element instanceof EllipseElement drawing.element instanceof EllipseElement
? drawing.element.cy + drawing.element.height / 10 ? drawing.element.cy + drawing.element.height / 10
: drawing.element.height : drawing.element.height
@ -144,12 +141,12 @@ export class DrawingWidget implements Widget {
.select<SVGAElement>('line.left') .select<SVGAElement>('line.left')
.attr('stroke', 'transparent') .attr('stroke', 'transparent')
.attr('stroke-width', '8px') .attr('stroke-width', '8px')
.attr('x1', drawing => drawing.element.width) .attr('x1', (drawing) => drawing.element.width)
.attr('x2', drawing => drawing.element.width) .attr('x2', (drawing) => drawing.element.width)
.attr('y1', drawing => .attr('y1', (drawing) =>
drawing.element instanceof EllipseElement ? drawing.element.cy - drawing.element.height / 10 : '0' drawing.element instanceof EllipseElement ? drawing.element.cy - drawing.element.height / 10 : '0'
) )
.attr('y2', drawing => .attr('y2', (drawing) =>
drawing.element instanceof EllipseElement drawing.element instanceof EllipseElement
? drawing.element.cy + drawing.element.height / 10 ? drawing.element.cy + drawing.element.height / 10
: drawing.element.height : drawing.element.height
@ -162,8 +159,8 @@ export class DrawingWidget implements Widget {
.attr('draggable', 'true') .attr('draggable', 'true')
.attr('fill', 'transparent') .attr('fill', 'transparent')
.attr('stroke', 'transparent') .attr('stroke', 'transparent')
.attr('cx', drawing => (drawing.element as LineElement).x1) .attr('cx', (drawing) => (drawing.element as LineElement).x1)
.attr('cy', drawing => (drawing.element as LineElement).y1) .attr('cy', (drawing) => (drawing.element as LineElement).y1)
.attr('r', 10) .attr('r', 10)
.attr('cursor', 'move'); .attr('cursor', 'move');
@ -172,8 +169,8 @@ export class DrawingWidget implements Widget {
.attr('draggable', 'true') .attr('draggable', 'true')
.attr('fill', 'transparent') .attr('fill', 'transparent')
.attr('stroke', 'transparent') .attr('stroke', 'transparent')
.attr('cx', drawing => (drawing.element as LineElement).x2) .attr('cx', (drawing) => (drawing.element as LineElement).x2)
.attr('cy', drawing => (drawing.element as LineElement).y2) .attr('cy', (drawing) => (drawing.element as LineElement).y2)
.attr('r', 10) .attr('r', 10)
.attr('cursor', 'move'); .attr('cursor', 'move');

View File

@ -111,7 +111,9 @@ export class DrawingsWidget implements Widget {
} }
} }
} else { } else {
dy = y - (evt.sourceEvent.pageY - (this.context.getZeroZeroTransformationPoint().y + this.context.transformation.y)); dy =
y -
(evt.sourceEvent.pageY - (this.context.getZeroZeroTransformationPoint().y + this.context.transformation.y));
y = evt.sourceEvent.pageY - (this.context.getZeroZeroTransformationPoint().y + this.context.transformation.y); y = evt.sourceEvent.pageY - (this.context.getZeroZeroTransformationPoint().y + this.context.transformation.y);
if (datum.element.height + dy < 0) { if (datum.element.height + dy < 0) {
@ -119,7 +121,8 @@ export class DrawingsWidget implements Widget {
y = topEdge; y = topEdge;
datum.element.height = Math.abs(datum.element.height + evt.dy); datum.element.height = Math.abs(datum.element.height + evt.dy);
} else { } else {
datum.y = evt.sourceEvent.pageY - (this.context.getZeroZeroTransformationPoint().y + this.context.transformation.y); datum.y =
evt.sourceEvent.pageY - (this.context.getZeroZeroTransformationPoint().y + this.context.transformation.y);
datum.element.height += dy; datum.element.height += dy;
if (datum.element instanceof EllipseElement) { if (datum.element instanceof EllipseElement) {
(datum.element as EllipseElement).cy = (datum.element as EllipseElement).cy =
@ -151,7 +154,9 @@ export class DrawingsWidget implements Widget {
const evt = event; const evt = event;
if (!isReflectedVertical) { if (!isReflectedVertical) {
dy = y - (evt.sourceEvent.pageY - (this.context.getZeroZeroTransformationPoint().y + this.context.transformation.y)); dy =
y -
(evt.sourceEvent.pageY - (this.context.getZeroZeroTransformationPoint().y + this.context.transformation.y));
y = evt.sourceEvent.pageY - (this.context.getZeroZeroTransformationPoint().y + this.context.transformation.y); y = evt.sourceEvent.pageY - (this.context.getZeroZeroTransformationPoint().y + this.context.transformation.y);
if (datum.element.height + dy < 0) { if (datum.element.height + dy < 0) {
@ -159,7 +164,8 @@ export class DrawingsWidget implements Widget {
isReflectedVertical = true; isReflectedVertical = true;
datum.element.height = Math.abs(datum.element.height + evt.dy); datum.element.height = Math.abs(datum.element.height + evt.dy);
} else { } else {
datum.y = evt.sourceEvent.pageY - (this.context.getZeroZeroTransformationPoint().y + this.context.transformation.y); datum.y =
evt.sourceEvent.pageY - (this.context.getZeroZeroTransformationPoint().y + this.context.transformation.y);
datum.element.height += dy; datum.element.height += dy;
if (datum.element instanceof EllipseElement) { if (datum.element instanceof EllipseElement) {
(datum.element as EllipseElement).cy = (datum.element as EllipseElement).cy =
@ -215,7 +221,9 @@ export class DrawingsWidget implements Widget {
const evt = event; const evt = event;
if (!isReflectedHorizontal) { if (!isReflectedHorizontal) {
dx = x - (evt.sourceEvent.pageX - (this.context.getZeroZeroTransformationPoint().x + this.context.transformation.x)); dx =
x -
(evt.sourceEvent.pageX - (this.context.getZeroZeroTransformationPoint().x + this.context.transformation.x));
x = evt.sourceEvent.pageX - (this.context.getZeroZeroTransformationPoint().x + this.context.transformation.x); x = evt.sourceEvent.pageX - (this.context.getZeroZeroTransformationPoint().x + this.context.transformation.x);
if (datum.element.width + dx < 0) { if (datum.element.width + dx < 0) {
@ -223,7 +231,8 @@ export class DrawingsWidget implements Widget {
isReflectedHorizontal = true; isReflectedHorizontal = true;
datum.element.width = Math.abs(datum.element.width + evt.dx); datum.element.width = Math.abs(datum.element.width + evt.dx);
} else { } else {
datum.x = evt.sourceEvent.pageX - (this.context.getZeroZeroTransformationPoint().x + this.context.transformation.x); datum.x =
evt.sourceEvent.pageX - (this.context.getZeroZeroTransformationPoint().x + this.context.transformation.x);
datum.element.width += dx; datum.element.width += dx;
if (datum.element instanceof EllipseElement) { if (datum.element instanceof EllipseElement) {
(datum.element as EllipseElement).cx = (datum.element as EllipseElement).cx =
@ -290,7 +299,9 @@ export class DrawingsWidget implements Widget {
datum.element.width = datum.element.width + evt.dx < 0 ? 1 : (datum.element.width += evt.dx); datum.element.width = datum.element.width + evt.dx < 0 ? 1 : (datum.element.width += evt.dx);
} }
} else { } else {
dx = x - (evt.sourceEvent.pageX - (this.context.getZeroZeroTransformationPoint().x + this.context.transformation.x)); dx =
x -
(evt.sourceEvent.pageX - (this.context.getZeroZeroTransformationPoint().x + this.context.transformation.x));
x = evt.sourceEvent.pageX - (this.context.getZeroZeroTransformationPoint().x + this.context.transformation.x); x = evt.sourceEvent.pageX - (this.context.getZeroZeroTransformationPoint().x + this.context.transformation.x);
if (datum.element.width + dx < 0) { if (datum.element.width + dx < 0) {
@ -298,7 +309,8 @@ export class DrawingsWidget implements Widget {
isReflectedHorizontal = false; isReflectedHorizontal = false;
datum.element.width = Math.abs(datum.element.width + evt.dx); datum.element.width = Math.abs(datum.element.width + evt.dx);
} else { } else {
datum.x = evt.sourceEvent.pageX - (this.context.getZeroZeroTransformationPoint().x + this.context.transformation.x); datum.x =
evt.sourceEvent.pageX - (this.context.getZeroZeroTransformationPoint().x + this.context.transformation.x);
datum.element.width += dx; datum.element.width += dx;
if (datum.element instanceof EllipseElement) { if (datum.element instanceof EllipseElement) {
(datum.element as EllipseElement).cx = (datum.element as EllipseElement).cx =

View File

@ -33,10 +33,7 @@ describe('EllipseDrawingWidget', () => {
drawing.element = ellipse; drawing.element = ellipse;
const drawings = svg.canvas.selectAll<SVGGElement, MapDrawing>('g.drawing').data([drawing]); const drawings = svg.canvas.selectAll<SVGGElement, MapDrawing>('g.drawing').data([drawing]);
const drawings_enter = drawings const drawings_enter = drawings.enter().append<SVGGElement>('g').classed('drawing', true);
.enter()
.append<SVGGElement>('g')
.classed('drawing', true);
const drawings_merge = drawings.merge(drawings_enter); const drawings_merge = drawings.merge(drawings_enter);
widget.draw(drawings_merge); widget.draw(drawings_merge);

View File

@ -17,25 +17,13 @@ export class EllipseDrawingWidget implements DrawingShapeWidget {
return d.element && d.element instanceof EllipseElement ? [d.element] : []; return d.element && d.element instanceof EllipseElement ? [d.element] : [];
}); });
drawing drawing.enter().append<SVGAElement>('line').attr('class', 'top');
.enter()
.append<SVGAElement>('line')
.attr('class', 'top');
drawing drawing.enter().append<SVGAElement>('line').attr('class', 'bottom');
.enter()
.append<SVGAElement>('line')
.attr('class', 'bottom');
drawing drawing.enter().append<SVGAElement>('line').attr('class', 'right');
.enter()
.append<SVGAElement>('line')
.attr('class', 'right');
drawing drawing.enter().append<SVGAElement>('line').attr('class', 'left');
.enter()
.append<SVGAElement>('line')
.attr('class', 'left');
const drawing_enter = drawing const drawing_enter = drawing
.enter() .enter()
@ -45,15 +33,15 @@ export class EllipseDrawingWidget implements DrawingShapeWidget {
const merge = drawing.merge(drawing_enter); const merge = drawing.merge(drawing_enter);
merge merge
.attr('fill', ellipse => ellipse.fill) .attr('fill', (ellipse) => ellipse.fill)
.attr('fill-opacity', ellipse => ellipse.fill_opacity) .attr('fill-opacity', (ellipse) => ellipse.fill_opacity)
.attr('stroke', ellipse => ellipse.stroke) .attr('stroke', (ellipse) => ellipse.stroke)
.attr('stroke-width', ellipse => ellipse.stroke_width) .attr('stroke-width', (ellipse) => ellipse.stroke_width)
.attr('stroke-dasharray', ellipse => this.qtDasharrayFixer.fix(ellipse.stroke_dasharray)) .attr('stroke-dasharray', (ellipse) => this.qtDasharrayFixer.fix(ellipse.stroke_dasharray))
.attr('cx', ellipse => ellipse.cx) .attr('cx', (ellipse) => ellipse.cx)
.attr('cy', ellipse => ellipse.cy) .attr('cy', (ellipse) => ellipse.cy)
.attr('rx', ellipse => ellipse.rx) .attr('rx', (ellipse) => ellipse.rx)
.attr('ry', ellipse => ellipse.ry); .attr('ry', (ellipse) => ellipse.ry);
drawing.exit().remove(); drawing.exit().remove();
} }

View File

@ -26,10 +26,7 @@ describe('ImageDrawingWidget', () => {
drawing.element = image; drawing.element = image;
const drawings = svg.canvas.selectAll<SVGGElement, MapDrawing>('g.drawing').data([drawing]); const drawings = svg.canvas.selectAll<SVGGElement, MapDrawing>('g.drawing').data([drawing]);
const drawings_enter = drawings const drawings_enter = drawings.enter().append<SVGGElement>('g').classed('drawing', true);
.enter()
.append<SVGGElement>('g')
.classed('drawing', true);
const drawings_merge = drawings.merge(drawings_enter); const drawings_merge = drawings.merge(drawings_enter);
widget.draw(drawings_merge); widget.draw(drawings_merge);

View File

@ -12,17 +12,14 @@ export class ImageDrawingWidget implements DrawingShapeWidget {
return d.element && d.element instanceof ImageElement ? [d.element] : []; return d.element && d.element instanceof ImageElement ? [d.element] : [];
}); });
const drawing_enter = drawing const drawing_enter = drawing.enter().append<SVGImageElement>('image').attr('class', 'image_element noselect');
.enter()
.append<SVGImageElement>('image')
.attr('class', 'image_element noselect');
const merge = drawing.merge(drawing_enter); const merge = drawing.merge(drawing_enter);
merge merge
.attr('xlink:href', (image: ImageElement) => image.data) .attr('xlink:href', (image: ImageElement) => image.data)
.attr('width', image => image.width) .attr('width', (image) => image.width)
.attr('height', image => image.height); .attr('height', (image) => image.height);
drawing.exit().remove(); drawing.exit().remove();
} }

View File

@ -31,10 +31,7 @@ describe('LineDrawingWidget', () => {
drawing.element = line; drawing.element = line;
const drawings = svg.canvas.selectAll<SVGGElement, MapDrawing>('g.drawing').data([drawing]); const drawings = svg.canvas.selectAll<SVGGElement, MapDrawing>('g.drawing').data([drawing]);
const drawings_enter = drawings const drawings_enter = drawings.enter().append<SVGGElement>('g').classed('drawing', true);
.enter()
.append<SVGGElement>('g')
.classed('drawing', true);
const drawings_merge = drawings.merge(drawings_enter); const drawings_merge = drawings.merge(drawings_enter);
widget.draw(drawings_merge); widget.draw(drawings_merge);

View File

@ -15,31 +15,22 @@ export class LineDrawingWidget implements DrawingShapeWidget {
return d.element && d.element instanceof LineElement ? [d.element] : []; return d.element && d.element instanceof LineElement ? [d.element] : [];
}); });
drawing drawing.enter().append<SVGCircleElement>('circle').attr('class', 'right');
.enter()
.append<SVGCircleElement>('circle')
.attr('class', 'right');
drawing drawing.enter().append<SVGCircleElement>('circle').attr('class', 'left');
.enter()
.append<SVGCircleElement>('circle')
.attr('class', 'left');
const drawing_enter = drawing const drawing_enter = drawing.enter().append<SVGLineElement>('line').attr('class', 'line_element noselect');
.enter()
.append<SVGLineElement>('line')
.attr('class', 'line_element noselect');
const merge = drawing.merge(drawing_enter); const merge = drawing.merge(drawing_enter);
merge merge
.attr('stroke', line => line.stroke) .attr('stroke', (line) => line.stroke)
.attr('stroke-width', line => line.stroke_width) .attr('stroke-width', (line) => line.stroke_width)
.attr('stroke-dasharray', line => this.qtDasharrayFixer.fix(line.stroke_dasharray)) .attr('stroke-dasharray', (line) => this.qtDasharrayFixer.fix(line.stroke_dasharray))
.attr('x1', line => line.x1) .attr('x1', (line) => line.x1)
.attr('x2', line => line.x2) .attr('x2', (line) => line.x2)
.attr('y1', line => line.y1) .attr('y1', (line) => line.y1)
.attr('y2', line => line.y2); .attr('y2', (line) => line.y2);
drawing.exit().remove(); drawing.exit().remove();
} }

View File

@ -31,10 +31,7 @@ describe('RectDrawingWidget', () => {
drawing.element = rect; drawing.element = rect;
const drawings = svg.canvas.selectAll<SVGGElement, MapDrawing>('g.drawing').data([drawing]); const drawings = svg.canvas.selectAll<SVGGElement, MapDrawing>('g.drawing').data([drawing]);
const drawings_enter = drawings const drawings_enter = drawings.enter().append<SVGGElement>('g').classed('drawing', true);
.enter()
.append<SVGGElement>('g')
.classed('drawing', true);
const drawings_merge = drawings.merge(drawings_enter); const drawings_merge = drawings.merge(drawings_enter);
widget.draw(drawings_merge); widget.draw(drawings_merge);

View File

@ -15,41 +15,26 @@ export class RectDrawingWidget implements DrawingShapeWidget {
return d.element && d.element instanceof RectElement ? [d.element] : []; return d.element && d.element instanceof RectElement ? [d.element] : [];
}); });
drawing drawing.enter().append<SVGAElement>('line').attr('class', 'top');
.enter()
.append<SVGAElement>('line')
.attr('class', 'top');
drawing drawing.enter().append<SVGAElement>('line').attr('class', 'bottom');
.enter()
.append<SVGAElement>('line')
.attr('class', 'bottom');
drawing drawing.enter().append<SVGAElement>('line').attr('class', 'right');
.enter()
.append<SVGAElement>('line')
.attr('class', 'right');
drawing drawing.enter().append<SVGAElement>('line').attr('class', 'left');
.enter()
.append<SVGAElement>('line')
.attr('class', 'left');
const drawing_enter = drawing const drawing_enter = drawing.enter().append<SVGRectElement>('rect').attr('class', 'rect_element noselect');
.enter()
.append<SVGRectElement>('rect')
.attr('class', 'rect_element noselect');
const merge = drawing.merge(drawing_enter); const merge = drawing.merge(drawing_enter);
merge merge
.attr('fill', rect => rect.fill) .attr('fill', (rect) => rect.fill)
.attr('fill-opacity', rect => rect.fill_opacity) .attr('fill-opacity', (rect) => rect.fill_opacity)
.attr('stroke', rect => rect.stroke) .attr('stroke', (rect) => rect.stroke)
.attr('stroke-width', rect => rect.stroke_width) .attr('stroke-width', (rect) => rect.stroke_width)
.attr('stroke-dasharray', rect => this.qtDasharrayFixer.fix(rect.stroke_dasharray)) .attr('stroke-dasharray', (rect) => this.qtDasharrayFixer.fix(rect.stroke_dasharray))
.attr('width', rect => rect.width) .attr('width', (rect) => rect.width)
.attr('height', rect => rect.height); .attr('height', (rect) => rect.height);
drawing.exit().remove(); drawing.exit().remove();
} }

View File

@ -32,10 +32,7 @@ describe('TextDrawingWidget', () => {
drawing.element = text; drawing.element = text;
const drawings = svg.canvas.selectAll<SVGGElement, MapDrawing>('g.drawing').data([drawing]); const drawings = svg.canvas.selectAll<SVGGElement, MapDrawing>('g.drawing').data([drawing]);
const drawings_enter = drawings const drawings_enter = drawings.enter().append<SVGGElement>('g').classed('drawing', true);
.enter()
.append<SVGGElement>('g')
.classed('drawing', true);
const drawings_merge = drawings.merge(drawings_enter); const drawings_merge = drawings.merge(drawings_enter);
widget.draw(drawings_merge); widget.draw(drawings_merge);
@ -55,10 +52,7 @@ describe('TextDrawingWidget', () => {
drawing.element = text; drawing.element = text;
const drawings = svg.canvas.selectAll<SVGGElement, MapDrawing>('g.drawing').data([drawing]); const drawings = svg.canvas.selectAll<SVGGElement, MapDrawing>('g.drawing').data([drawing]);
const drawings_enter = drawings const drawings_enter = drawings.enter().append<SVGGElement>('g').classed('drawing', true);
.enter()
.append<SVGGElement>('g')
.classed('drawing', true);
const drawings_merge = drawings.merge(drawings_enter); const drawings_merge = drawings.merge(drawings_enter);
widget.draw(drawings_merge); widget.draw(drawings_merge);
@ -81,10 +75,7 @@ describe('TextDrawingWidget', () => {
drawing.element = text; drawing.element = text;
const drawings = svg.canvas.selectAll<SVGGElement, MapDrawing>('g.drawing').data([drawing]); const drawings = svg.canvas.selectAll<SVGGElement, MapDrawing>('g.drawing').data([drawing]);
const drawings_enter = drawings const drawings_enter = drawings.enter().append<SVGGElement>('g').classed('drawing', true);
.enter()
.append<SVGGElement>('g')
.classed('drawing', true);
const drawings_merge = drawings.merge(drawings_enter); const drawings_merge = drawings.merge(drawings_enter);
widget.draw(drawings_merge); widget.draw(drawings_merge);

View File

@ -18,10 +18,7 @@ export class TextDrawingWidget implements DrawingShapeWidget {
return d.element && d.element instanceof TextElement ? [d.element] : []; return d.element && d.element instanceof TextElement ? [d.element] : [];
}); });
const drawing_enter = drawing const drawing_enter = drawing.enter().append<SVGTextElement>('text').attr('class', 'text_element noselect');
.enter()
.append<SVGTextElement>('text')
.attr('class', 'text_element noselect');
const merge = drawing.merge(drawing_enter); const merge = drawing.merge(drawing_enter);
merge merge
@ -40,8 +37,8 @@ export class TextDrawingWidget implements DrawingShapeWidget {
} }
return styles.join('; '); return styles.join('; ');
}) })
.attr('fill', text => text.fill) .attr('fill', (text) => text.fill)
.attr('text-decoration', text => text.text_decoration); .attr('text-decoration', (text) => text.text_decoration);
const lines = merge.selectAll<SVGTSpanElement, string>('tspan').data((text: TextElement) => { const lines = merge.selectAll<SVGTSpanElement, string>('tspan').data((text: TextElement) => {
return text.text.split(/\r?\n/); return text.text.split(/\r?\n/);
@ -52,14 +49,14 @@ export class TextDrawingWidget implements DrawingShapeWidget {
const lines_merge = lines.merge(lines_enter); const lines_merge = lines.merge(lines_enter);
lines_merge lines_merge
.text(line => line) .text((line) => line)
.attr('xml:space', 'preserve') .attr('xml:space', 'preserve')
.attr('x', 0) .attr('x', 0)
.attr('dy', (line, i) => (i === 0 ? '0em' : '1.4em')); .attr('dy', (line, i) => (i === 0 ? '0em' : '1.4em'));
lines.exit().remove(); lines.exit().remove();
merge.attr('transform', function(this: SVGTextElement) { merge.attr('transform', function (this: SVGTextElement) {
// SVG calculates y pos by the /bottom/ of the first tspan, hence we need to make some // SVG calculates y pos by the /bottom/ of the first tspan, hence we need to make some
// approx and make it matching to GUI // approx and make it matching to GUI
const tspan = select(this).selectAll<SVGTSpanElement, string>('tspan'); const tspan = select(this).selectAll<SVGTSpanElement, string>('tspan');

View File

@ -33,10 +33,7 @@ export class GraphLayout implements Widget {
} }
connect(view: SVGSelection, context: Context) { connect(view: SVGSelection, context: Context) {
this.drawingLineTool.connect( this.drawingLineTool.connect(view, context);
view,
context
);
} }
draw(view: SVGSelection, context: Context) { draw(view: SVGSelection, context: Context) {
@ -44,10 +41,7 @@ export class GraphLayout implements Widget {
const canvas = view.selectAll<SVGGElement, Context>('g.canvas').data([context]); const canvas = view.selectAll<SVGGElement, Context>('g.canvas').data([context]);
const canvasEnter = canvas const canvasEnter = canvas.enter().append<SVGGElement>('g').attr('class', 'canvas');
.enter()
.append<SVGGElement>('g')
.attr('class', 'canvas');
canvas.merge(canvasEnter).attr('transform', (ctx: Context) => { canvas.merge(canvasEnter).attr('transform', (ctx: Context) => {
const xTrans = ctx.getZeroZeroTransformationPoint().x + ctx.transformation.x; const xTrans = ctx.getZeroZeroTransformationPoint().x + ctx.transformation.x;

View File

@ -58,10 +58,7 @@ describe('InterfaceLabelsWidget', () => {
const linksSelection = svg.canvas.selectAll<SVGGElement, MapLink>('g.link').data(links); const linksSelection = svg.canvas.selectAll<SVGGElement, MapLink>('g.link').data(links);
linksEnter = linksSelection linksEnter = linksSelection.enter().append<SVGGElement>('g').attr('class', 'link');
.enter()
.append<SVGGElement>('g')
.attr('class', 'link');
linksSelection.exit().remove(); linksSelection.exit().remove();

View File

@ -36,7 +36,10 @@ export class InterfaceLabelWidget {
const link_node_position = selection const link_node_position = selection
.selectAll<SVGGElement, MapLinkNode>('g.link_node_position') .selectAll<SVGGElement, MapLinkNode>('g.link_node_position')
.data((link: MapLink) => [[link.source, link.nodes[0]], [link.target, link.nodes[1]]]); .data((link: MapLink) => [
[link.source, link.nodes[0]],
[link.target, link.nodes[1]],
]);
const enter_link_node_position = link_node_position const enter_link_node_position = link_node_position
.enter() .enter()
@ -58,10 +61,7 @@ export class InterfaceLabelWidget {
return []; return [];
}); });
const enter = labels const enter = labels.enter().append<SVGGElement>('g').classed('interface_label_container', true);
.enter()
.append<SVGGElement>('g')
.classed('interface_label_container', true);
// create surrounding rect // create surrounding rect
enter.append<SVGRectElement>('rect').attr('class', 'interface_label_selection'); enter.append<SVGRectElement>('rect').attr('class', 'interface_label_selection');
@ -72,9 +72,7 @@ export class InterfaceLabelWidget {
.attr('class', 'interface_label noselect') .attr('class', 'interface_label noselect')
.attr('interface_label_id', (i: MapLinkNode) => `${i.id}`); .attr('interface_label_id', (i: MapLinkNode) => `${i.id}`);
const merge = labels const merge = labels.merge(enter).on('contextmenu', (n: MapLinkNode, i: number) => {
.merge(enter)
.on('contextmenu', (n: MapLinkNode, i: number) => {
event.preventDefault(); event.preventDefault();
self.onContextMenu.emit(new InterfaceLabelContextMenu(event, n)); self.onContextMenu.emit(new InterfaceLabelContextMenu(event, n));
}); });
@ -102,7 +100,7 @@ export class InterfaceLabelWidget {
.attr('stroke-dasharray', '3,3') .attr('stroke-dasharray', '3,3')
.attr('stroke-width', '0.5') .attr('stroke-width', '0.5')
.attr('fill', 'none') .attr('fill', 'none')
.each(function(this: SVGRectElement, l: MapLinkNode) { .each(function (this: SVGRectElement, l: MapLinkNode) {
const current = select(this); const current = select(this);
const textLabel = merge.select<SVGTextElement>(`text[interface_label_id="${l.id}"]`); const textLabel = merge.select<SVGTextElement>(`text[interface_label_id="${l.id}"]`);
const bbox = textLabel.node().getBBox(); const bbox = textLabel.node().getBBox();

View File

@ -10,11 +10,9 @@ import { MapSettingsService } from '../../services/mapsettings.service';
@Injectable() @Injectable()
export class InterfaceStatusWidget implements Widget { export class InterfaceStatusWidget implements Widget {
private mapSettingsService: MapSettingsService private mapSettingsService: MapSettingsService;
constructor( constructor(private _mapSettingsService: MapSettingsService) {
private _mapSettingsService: MapSettingsService
) {
this.mapSettingsService = _mapSettingsService; this.mapSettingsService = _mapSettingsService;
} }
@ -22,22 +20,24 @@ export class InterfaceStatusWidget implements Widget {
const self = this; const self = this;
let mapLinks: MapLink[] = []; let mapLinks: MapLink[] = [];
view.each(function(this: SVGGElement, l: MapLink) { view.each(function (this: SVGGElement, l: MapLink) {
mapLinks.push(l); mapLinks.push(l);
}); });
mapLinks.forEach(mapLink => { mapLinks.forEach((mapLink) => {
mapLinks.forEach(n => { mapLinks.forEach((n) => {
if (n.nodes[0].linkId !== mapLink.nodes[0].linkId){ if (n.nodes[0].linkId !== mapLink.nodes[0].linkId) {
if ((mapLink.nodes[0].nodeId === n.nodes[0].nodeId && mapLink.nodes[1].nodeId === n.nodes[1].nodeId) || if (
(mapLink.nodes[0].nodeId === n.nodes[0].nodeId && mapLink.nodes[1].nodeId === n.nodes[1].nodeId) ||
(mapLink.nodes[0].nodeId === n.nodes[1].nodeId && mapLink.nodes[1].nodeId === n.nodes[0].nodeId) || (mapLink.nodes[0].nodeId === n.nodes[1].nodeId && mapLink.nodes[1].nodeId === n.nodes[0].nodeId) ||
(mapLink.nodes[1].nodeId === n.nodes[0].nodeId && mapLink.nodes[0].nodeId === n.nodes[1].nodeId)) { (mapLink.nodes[1].nodeId === n.nodes[0].nodeId && mapLink.nodes[0].nodeId === n.nodes[1].nodeId)
) {
mapLink.isMultiplied = true; mapLink.isMultiplied = true;
} }
} }
}); });
}); });
view.each(function(this: SVGGElement, l: MapLink) { view.each(function (this: SVGGElement, l: MapLink) {
const link_group = select<SVGGElement, MapLink>(this); const link_group = select<SVGGElement, MapLink>(this);
const link_path = link_group.select<SVGPathElement>('path'); const link_path = link_group.select<SVGPathElement>('path');
@ -48,37 +48,42 @@ export class InterfaceStatusWidget implements Widget {
if (link_path.node().getTotalLength() > 2 * 45 + 130) { if (link_path.node().getTotalLength() > 2 * 45 + 130) {
if (l.source && l.target) { if (l.source && l.target) {
let sourcePort = l.nodes.find(node => node.nodeId === l.source.id).label.text; let sourcePort = l.nodes.find((node) => node.nodeId === l.source.id).label.text;
let destinationPort = l.nodes.find(node => node.nodeId === l.target.id).label.text; let destinationPort = l.nodes.find((node) => node.nodeId === l.target.id).label.text;
statuses = [ statuses = [
new LinkStatus(start_point.x, start_point.y, (l.capturing && l.suspend) ? 'suspended' : l.source.status, sourcePort), new LinkStatus(
new LinkStatus(end_point.x, end_point.y, (l.capturing && l.suspend) ? 'suspended' : l.target.status, destinationPort) start_point.x,
start_point.y,
l.capturing && l.suspend ? 'suspended' : l.source.status,
sourcePort
),
new LinkStatus(
end_point.x,
end_point.y,
l.capturing && l.suspend ? 'suspended' : l.target.status,
destinationPort
),
]; ];
} }
} }
} }
link_group link_group.selectAll<SVGCircleElement, LinkStatus>('circle.status_started').remove();
.selectAll<SVGCircleElement, LinkStatus>('circle.status_started').remove(); link_group.selectAll<SVGCircleElement, LinkStatus>('circle.status_stopped').remove();
link_group link_group.selectAll<SVGCircleElement, LinkStatus>('circle.status_suspended').remove();
.selectAll<SVGCircleElement, LinkStatus>('circle.status_stopped').remove();
link_group
.selectAll<SVGCircleElement, LinkStatus>('circle.status_suspended').remove();
link_group link_group.selectAll<SVGRectElement, LinkStatus>('rect.status_started').remove();
.selectAll<SVGRectElement, LinkStatus>('rect.status_started').remove(); link_group.selectAll<SVGTextElement, LinkStatus>('text.status_started_label').remove();
link_group link_group.selectAll<SVGRectElement, LinkStatus>('rect.status_stopped').remove();
.selectAll<SVGTextElement, LinkStatus>('text.status_started_label').remove(); link_group.selectAll<SVGTextElement, LinkStatus>('text.status_stopped_label').remove();
link_group link_group.selectAll<SVGRectElement, LinkStatus>('rect.status_suspended').remove();
.selectAll<SVGRectElement, LinkStatus>('rect.status_stopped').remove(); link_group.selectAll<SVGTextElement, LinkStatus>('text.status_suspended_label').remove();
link_group
.selectAll<SVGTextElement, LinkStatus>('text.status_stopped_label').remove();
link_group
.selectAll<SVGRectElement, LinkStatus>('rect.status_suspended').remove();
link_group
.selectAll<SVGTextElement, LinkStatus>('text.status_suspended_label').remove();
if (self.mapSettingsService.showInterfaceLabels && self.mapSettingsService.integrateLinkLabelsToLinks && !l.isMultiplied) { if (
self.mapSettingsService.showInterfaceLabels &&
self.mapSettingsService.integrateLinkLabelsToLinks &&
!l.isMultiplied
) {
const status_started = link_group const status_started = link_group
.selectAll<SVGRectElement, LinkStatus>('rect.status_started') .selectAll<SVGRectElement, LinkStatus>('rect.status_started')
.data(statuses.filter((link_status: LinkStatus) => link_status.status === 'started')); .data(statuses.filter((link_status: LinkStatus) => link_status.status === 'started'));
@ -87,7 +92,7 @@ export class InterfaceStatusWidget implements Widget {
.merge(status_started_enter) .merge(status_started_enter)
.attr('class', 'status_started') .attr('class', 'status_started')
.attr('width', (ls: LinkStatus) => { .attr('width', (ls: LinkStatus) => {
return (ls.port.length * 8) + 10; return ls.port.length * 8 + 10;
}) })
.attr('height', 20) .attr('height', 20)
.attr('x', (ls: LinkStatus) => ls.x - 30) .attr('x', (ls: LinkStatus) => ls.x - 30)
@ -119,7 +124,7 @@ export class InterfaceStatusWidget implements Widget {
.merge(status_stopped_enter) .merge(status_stopped_enter)
.attr('class', 'status_stopped') .attr('class', 'status_stopped')
.attr('width', (ls: LinkStatus) => { .attr('width', (ls: LinkStatus) => {
return (ls.port.length * 8) + 10; return ls.port.length * 8 + 10;
}) })
.attr('height', 20) .attr('height', 20)
.attr('x', (ls: LinkStatus) => ls.x - 30) .attr('x', (ls: LinkStatus) => ls.x - 30)
@ -151,7 +156,7 @@ export class InterfaceStatusWidget implements Widget {
.merge(status_suspended_enter) .merge(status_suspended_enter)
.attr('class', 'status_suspended') .attr('class', 'status_suspended')
.attr('width', (ls: LinkStatus) => { .attr('width', (ls: LinkStatus) => {
return (ls.port.length * 8) + 10; return ls.port.length * 8 + 10;
}) })
.attr('height', 20) .attr('height', 20)
.attr('x', (ls: LinkStatus) => ls.x - 30) .attr('x', (ls: LinkStatus) => ls.x - 30)

View File

@ -43,9 +43,7 @@ export class LabelWidget implements Widget {
.attr('class', 'label_container') .attr('class', 'label_container')
.attr('label_id', (label: MapLabel) => label.id); .attr('label_id', (label: MapLabel) => label.id);
const merge = label_view const merge = label_view.merge(label_enter).on('contextmenu', (n: MapLabel, i: number) => {
.merge(label_enter)
.on('contextmenu', (n: MapLabel, i: number) => {
event.preventDefault(); event.preventDefault();
self.onContextMenu.emit(new LabelContextMenu(event, n)); self.onContextMenu.emit(new LabelContextMenu(event, n));
}); });
@ -60,20 +58,16 @@ export class LabelWidget implements Widget {
} }
private drawLabel(view: SVGSelection) { private drawLabel(view: SVGSelection) {
const label_body = view.selectAll<SVGGElement, MapLabel>('g.label_body').data(label => [label]); const label_body = view.selectAll<SVGGElement, MapLabel>('g.label_body').data((label) => [label]);
const label_body_enter = label_body const label_body_enter = label_body.enter().append<SVGGElement>('g').attr('class', 'label_body');
.enter()
.append<SVGGElement>('g')
.attr('class', 'label_body');
// add label of node // add label of node
label_body_enter.append<SVGTextElement>('text').attr('class', 'label'); label_body_enter.append<SVGTextElement>('text').attr('class', 'label');
label_body_enter.append<SVGRectElement>('rect').attr('class', 'label_selection'); label_body_enter.append<SVGRectElement>('rect').attr('class', 'label_selection');
const label_body_merge = label_body const label_body_merge = label_body.merge(label_body_enter);
.merge(label_body_enter);
label_body_merge label_body_merge
.select<SVGTextElement>('text.label') .select<SVGTextElement>('text.label')
@ -93,13 +87,13 @@ export class LabelWidget implements Widget {
label_body_merge label_body_merge
.select<SVGRectElement>('rect.label_selection') .select<SVGRectElement>('rect.label_selection')
.attr('visibility', (l: MapLabel) => { .attr('visibility', (l: MapLabel) => {
return (this.selectionManager.isSelected(l) ? 'visible' : 'hidden') return this.selectionManager.isSelected(l) ? 'visible' : 'hidden';
}) })
.attr('stroke', 'black') .attr('stroke', 'black')
.attr('stroke-dasharray', '3,3') .attr('stroke-dasharray', '3,3')
.attr('stroke-width', '0.5') .attr('stroke-width', '0.5')
.attr('fill', 'none') .attr('fill', 'none')
.each(function(this: SVGRectElement, label: MapLabel) { .each(function (this: SVGRectElement, label: MapLabel) {
const current = select(this); const current = select(this);
const textLabel = label_body_merge.select<SVGTextElement>(`text[label_id="${label.id}"]`); const textLabel = label_body_merge.select<SVGTextElement>(`text[label_id="${label.id}"]`);
const bbox = textLabel.node().getBBox(); const bbox = textLabel.node().getBBox();

Some files were not shown because too many files have changed in this diff Show More