Context menu preps, ref. #5

This commit is contained in:
ziajka 2017-11-29 12:42:26 +01:00
parent 2eb7246f87
commit 5855587259
13 changed files with 146 additions and 14 deletions

View File

@ -40,6 +40,7 @@ import { AppComponent } from './app.component';
import { MapComponent } from './cartography/map/map.component'; import { MapComponent } from './cartography/map/map.component';
import { CreateSnapshotDialogComponent, ProjectMapComponent } from './project-map/project-map.component'; import { CreateSnapshotDialogComponent, ProjectMapComponent } from './project-map/project-map.component';
import { ServersComponent, AddServerDialogComponent } from './servers/servers.component'; import { ServersComponent, AddServerDialogComponent } from './servers/servers.component';
import { ContextMenuComponent } from './shared/context-menu/context-menu.component';
@NgModule({ @NgModule({
@ -53,6 +54,7 @@ import { ServersComponent, AddServerDialogComponent } from './servers/servers.co
ProjectsComponent, ProjectsComponent,
DefaultLayoutComponent, DefaultLayoutComponent,
ProgressDialogComponent, ProgressDialogComponent,
ContextMenuComponent,
], ],
imports: [ imports: [
NgbModule.forRoot(), NgbModule.forRoot(),

View File

@ -1 +1,15 @@
<svg preserveAspectRatio="none"></svg> <svg preserveAspectRatio="none"></svg>
<div class="context-menu" [style.left]="contextMenuLeft" [style.top]="contextMenuTop">
<span [matMenuTriggerFor]="contextMenu"></span>
<mat-menu #contextMenu="matMenu">
<button mat-menu-item>
<mat-icon>play_arrow</mat-icon>
<span>Start</span>
</button>
<button mat-menu-item>
<mat-icon>stop</mat-icon>
<span>Stop</span>
</button>
</mat-menu>
</div>

Before

Width:  |  Height:  |  Size: 39 B

After

Width:  |  Height:  |  Size: 435 B

View File

@ -1,3 +1,7 @@
svg { svg {
display: block; display: block;
} }
.context-menu {
position: absolute;
}

View File

@ -1,4 +1,8 @@
import { Component, ElementRef, Input, OnChanges, OnDestroy, OnInit, SimpleChange } from '@angular/core'; import {
ChangeDetectorRef,
Component, ElementRef, Input, NgZone, OnChanges, OnDestroy, OnInit, SimpleChange,
ViewChild
} from '@angular/core';
import { D3, D3Service } from 'd3-ng2-service'; import { D3, D3Service } from 'd3-ng2-service';
import { Selection } from 'd3-selection'; import { Selection } from 'd3-selection';
@ -8,12 +12,22 @@ import { GraphLayout } from "../shared/widgets/graph.widget";
import { Context } from "../../map/models/context"; import { Context } from "../../map/models/context";
import { Size } from "../shared/models/size.model"; import { Size } from "../shared/models/size.model";
import { Drawing } from "../shared/models/drawing.model"; import { Drawing } from "../shared/models/drawing.model";
import {MatMenuTrigger} from "@angular/material";
import {NodeOnContextMenuListener} from "../shared/widgets/nodes.widget";
import {DomSanitizer} from "@angular/platform-browser";
class NodeOnContextMenu implements NodeOnContextMenuListener {
constructor(private component: MapComponent) {}
onContextMenu() {
this.component.contextMenu.openMenu();
}
}
@Component({ @Component({
selector: 'app-map', selector: 'app-map',
templateUrl: '../../map/map.component.html', templateUrl: './map.component.html',
styleUrls: ['../../map/map.component.css'] styleUrls: ['./map.component.scss']
}) })
export class MapComponent implements OnInit, OnChanges, OnDestroy { export class MapComponent implements OnInit, OnChanges, OnDestroy {
@Input() nodes: Node[] = []; @Input() nodes: Node[] = [];
@ -21,10 +35,10 @@ export class MapComponent implements OnInit, OnChanges, OnDestroy {
@Input() drawings: Drawing[] = []; @Input() drawings: Drawing[] = [];
@Input() width = 1500; @Input() width = 1500;
@Input() height = 600; @Input() height = 600;
@Input() phylloRadius = 7;
@Input() pointRadius= 2;
@Input() windowFullSize = true; @Input() windowFullSize = true;
@ViewChild(MatMenuTrigger) contextMenu: MatMenuTrigger;
private d3: D3; private d3: D3;
private parentNativeElement: any; private parentNativeElement: any;
private svg: Selection<SVGSVGElement, any, null, undefined>; private svg: Selection<SVGSVGElement, any, null, undefined>;
@ -32,19 +46,25 @@ export class MapComponent implements OnInit, OnChanges, OnDestroy {
private graphLayout: GraphLayout; private graphLayout: GraphLayout;
private graphContext: Context; private graphContext: Context;
public contextMenuTop;
public contextMenuLeft;
constructor(protected element: ElementRef, constructor(protected element: ElementRef,
protected d3Service: D3Service protected d3Service: D3Service,
protected sanitizer: DomSanitizer,
protected changeDetector: ChangeDetectorRef
) { ) {
this.d3 = d3Service.getD3(); this.d3 = d3Service.getD3();
this.parentNativeElement = element.nativeElement; this.parentNativeElement = element.nativeElement;
this.contextMenuLeft = this.sanitizer.bypassSecurityTrustStyle("0");
this.contextMenuTop = this.sanitizer.bypassSecurityTrustStyle("0");
} }
ngOnChanges(changes: { [propKey: string]: SimpleChange }) { ngOnChanges(changes: { [propKey: string]: SimpleChange }) {
if ( if (
(changes['width'] && !changes['width'].isFirstChange()) || (changes['width'] && !changes['width'].isFirstChange()) ||
(changes['height'] && !changes['height'].isFirstChange()) || (changes['height'] && !changes['height'].isFirstChange()) ||
(changes['phylloRadius'] && !changes['phylloRadius'].isFirstChange()) ||
(changes['pointRadius'] && !changes['pointRadius'].isFirstChange()) ||
(changes['drawings'] && !changes['drawings'].isFirstChange()) || (changes['drawings'] && !changes['drawings'].isFirstChange()) ||
(changes['nodes'] && !changes['nodes'].isFirstChange()) || (changes['nodes'] && !changes['nodes'].isFirstChange()) ||
(changes['links'] && !changes['links'].isFirstChange()) (changes['links'] && !changes['links'].isFirstChange())
@ -89,7 +109,15 @@ export class MapComponent implements OnInit, OnChanges, OnDestroy {
this.graphLayout = new GraphLayout(); this.graphLayout = new GraphLayout();
this.graphLayout.draw(this.svg, this.graphContext); this.graphLayout.draw(this.svg, this.graphContext);
// this.graphLayout.getNodesWidget().setOnContextMenuListener(new NodeOnContextMenu(self));
this.graphLayout.getNodesWidget().setOnContextMenuCallback((event: any) => {
this.contextMenuLeft = this.sanitizer.bypassSecurityTrustStyle(event.clientX + "px");
this.contextMenuTop = this.sanitizer.bypassSecurityTrustStyle(event.clientY + "px");
this.changeDetector.detectChanges();
this.contextMenu.openMenu();
});
} }
} }

View File

@ -34,6 +34,10 @@ export class GraphLayout implements Widget {
this.drawings = drawings; this.drawings = drawings;
} }
public getNodesWidget() {
return this.nodesWidget;
}
draw(view: SVGSelection, context: Context) { draw(view: SVGSelection, context: Context) {
const self = this; const self = this;
@ -59,7 +63,7 @@ export class GraphLayout implements Widget {
this.linksWidget.draw(canvas, this.links); this.linksWidget.draw(canvas, this.links);
this.nodesWidget.draw(canvas, this.nodes); this.nodesWidget.draw(canvas, this.nodes);
this.drawingsWidget.draw(canvas, this.drawings) this.drawingsWidget.draw(canvas, this.drawings);
const onZoom = function(this: SVGSVGElement) { const onZoom = function(this: SVGSVGElement) {
const e: D3ZoomEvent<SVGSVGElement, any> = event; const e: D3ZoomEvent<SVGSVGElement, any> = event;

View File

@ -1,13 +1,31 @@
import {Widget} from "./widget"; import {Widget} from "./widget";
import {Node} from "../models/node.model"; import {Node} from "../models/node.model";
import {SVGSelection} from "../../../map/models/types"; import {SVGSelection} from "../../../map/models/types";
import { event } from "d3-selection";
import { D3} from "d3-ng2-service";
import {D3DragEvent} from "d3-drag"; import {D3DragEvent} from "d3-drag";
import {select} from "d3-selection"; import {select} from "d3-selection";
import {isUndefined} from "util";
export interface NodeOnContextMenuListener {
onContextMenu(): void;
};
export class NodesWidget implements Widget { export class NodesWidget implements Widget {
private onContextMenuListener: NodeOnContextMenuListener;
private onContextMenuCallback: (event: any) => void;
constructor() {} constructor() {}
public setOnContextMenuListener(onContextMenuListener: NodeOnContextMenuListener) {
this.onContextMenuListener = onContextMenuListener;
}
public setOnContextMenuCallback(onContextMenuCallback: (event: any) => void) {
this.onContextMenuCallback = onContextMenuCallback;
}
public draw(view: SVGSelection, nodes: Node[]) { public draw(view: SVGSelection, nodes: Node[]) {
const self = this; const self = this;
@ -33,7 +51,17 @@ export class NodesWidget implements Widget {
const node_image = node_enter.append<SVGImageElement>('image') const node_image = node_enter.append<SVGImageElement>('image')
.attr('xlink:href', (n: Node) => 'data:image/svg+xml;base64,' + btoa(n.icon.raw)) .attr('xlink:href', (n: Node) => 'data:image/svg+xml;base64,' + btoa(n.icon.raw))
.attr('width', (n: Node) => n.width) .attr('width', (n: Node) => n.width)
.attr('height', (n: Node) => n.height); .attr('height', (n: Node) => n.height)
.on("contextmenu", function (n: Node, i: number) {
// if (self.onContextMenuListener !== ) {
// self.onContextMenuListener.onContextMenu();
// }
console.log(event);
event.preventDefault();
if (self.onContextMenuCallback !== null) {
self.onContextMenuCallback(event);
}
});
node_enter.append<SVGCircleElement>('circle') node_enter.append<SVGCircleElement>('circle')
.attr('class', 'node_point') .attr('class', 'node_point')

View File

@ -1,3 +0,0 @@
svg {
display: block;
}

View File

@ -1 +0,0 @@
<svg xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="none"></svg>

Before

Width:  |  Height:  |  Size: 83 B

View File

@ -0,0 +1,6 @@
<span [matMenuTriggerFor]="contextMenu"></span>
<button mat-button (contextmenu)="openContextMenu($event)">Context Menu</button>
<mat-menu #contextMenu="matMenu">
<button md-menu-item>Item 1</button>
<button md-menu-item>Item 2</button>
</mat-menu>

View File

@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { ContextMenuComponent } from './context-menu.component';
describe('ContextMenuComponent', () => {
let component: ContextMenuComponent;
let fixture: ComponentFixture<ContextMenuComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ ContextMenuComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(ContextMenuComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,24 @@
import { Component, OnInit, ViewChild } from '@angular/core';
import { MatMenuTrigger } from '@angular/material';
@Component({
selector: 'app-context-menu',
templateUrl: './context-menu.component.html',
styleUrls: ['./context-menu.component.scss']
})
export class ContextMenuComponent implements OnInit {
@ViewChild(MatMenuTrigger) contextMenu: MatMenuTrigger;
constructor() { }
ngOnInit() {
}
openContextMenu(event) {
event.preventDefault();
this.contextMenu.openMenu();
}
}