mirror of
https://github.com/GNS3/gns3-web-ui.git
synced 2025-05-08 11:38:38 +00:00
Reimplementation of moving component
This commit is contained in:
parent
5a71481d47
commit
3405f89a4a
@ -55,8 +55,9 @@ import { RectangleElementFactory } from './helpers/drawings-factory/rectangle-el
|
||||
import { LineElementFactory } from './helpers/drawings-factory/line-element-factory';
|
||||
import { TextEditorComponent } from './components/text-editor/text-editor.component';
|
||||
import { DrawingAddingComponent } from './components/drawing-adding/drawing-adding.component';
|
||||
import { MovingModeComponent } from './components/moving-mode/moving-mode.component';
|
||||
import { MovingEventSource } from './events/moving-event-source';
|
||||
import { MovingCanvasDirective } from './directives/moving-canvas.directive';
|
||||
import { ZoomingCanvasDirective } from './directives/zooming-canvas.directive';
|
||||
|
||||
@NgModule({
|
||||
imports: [CommonModule, MatMenuModule, MatIconModule],
|
||||
@ -70,7 +71,8 @@ import { MovingEventSource } from './events/moving-event-source';
|
||||
SelectionControlComponent,
|
||||
SelectionSelectComponent,
|
||||
DraggableSelectionComponent,
|
||||
MovingModeComponent
|
||||
MovingCanvasDirective,
|
||||
ZoomingCanvasDirective
|
||||
],
|
||||
providers: [
|
||||
CssFixer,
|
||||
|
@ -1,4 +1,4 @@
|
||||
<svg #svg class="map" preserveAspectRatio="none">
|
||||
<svg #svg class="map" preserveAspectRatio="none" movingCanvas zoomingCanvas>
|
||||
<filter id="grayscale"><feColorMatrix id="feGrayscale" type="saturate" values="0" /></filter>
|
||||
</svg>
|
||||
|
||||
@ -8,4 +8,3 @@
|
||||
<app-selection-select></app-selection-select>
|
||||
<app-text-editor #textEditor [svg]="svg"></app-text-editor>
|
||||
<app-draggable-selection [svg]="svg"></app-draggable-selection>
|
||||
<app-moving-mode [svg]="svg"></app-moving-mode>
|
||||
|
Before Width: | Height: | Size: 520 B After Width: | Height: | Size: 499 B |
@ -1,72 +0,0 @@
|
||||
import { ComponentFixture, TestBed, async } from '@angular/core/testing';
|
||||
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { Context } from '../../models/context';
|
||||
import { MovingModeComponent } from './moving-mode.component';
|
||||
import { MovingEventSource } from '../../events/moving-event-source';
|
||||
|
||||
class SvgMock {
|
||||
addEventListener() {}
|
||||
}
|
||||
|
||||
describe('MovingModeComponent', () => {
|
||||
let component: MovingModeComponent;
|
||||
let fixture: ComponentFixture<MovingModeComponent>;
|
||||
let movingEventSource = new MovingEventSource();
|
||||
let svg = new SvgMock();
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [NoopAnimationsModule],
|
||||
providers: [
|
||||
{ provide: MovingEventSource, useValue: movingEventSource },
|
||||
{ provide: Context, useClass: Context }
|
||||
],
|
||||
declarations: [MovingModeComponent]
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(MovingModeComponent);
|
||||
component = fixture.componentInstance;
|
||||
component.svg = svg as unknown as SVGSVGElement;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should activate listener when moving mode changed to true', () => {
|
||||
spyOn(component, 'activate');
|
||||
|
||||
movingEventSource.movingModeState.emit(true);
|
||||
|
||||
expect(component.activate).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should deactivate listener when moving mode changed to false', () => {
|
||||
spyOn(component, 'deactivate');
|
||||
|
||||
movingEventSource.movingModeState.emit(false);
|
||||
|
||||
expect(component.deactivate).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should add moousemove listener on activation', () => {
|
||||
spyOn(component, 'addMoveListener');
|
||||
spyOn(component.svg, 'addEventListener').and.returnValue({});
|
||||
|
||||
component.activate();
|
||||
|
||||
expect(component.addMoveListener).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should add mousewheel listener on activation', () => {
|
||||
spyOn(component, 'addZoomListener');
|
||||
spyOn(component.svg, 'addEventListener').and.returnValue({});
|
||||
|
||||
component.activate();
|
||||
|
||||
expect(component.addZoomListener).toHaveBeenCalled();
|
||||
});
|
||||
});
|
@ -1,103 +0,0 @@
|
||||
import { Component, OnInit, OnDestroy, Input } from '@angular/core';
|
||||
import { Context } from '../../models/context';
|
||||
import { MovingEventSource } from '../../events/moving-event-source';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { select } from 'd3-selection';
|
||||
|
||||
@Component({
|
||||
selector: 'app-moving-mode',
|
||||
templateUrl: './moving-mode.component.html',
|
||||
styleUrls: ['./moving-mode.component.scss']
|
||||
})
|
||||
export class MovingModeComponent implements OnInit, OnDestroy {
|
||||
@Input('svg') svg: SVGSVGElement;
|
||||
|
||||
private scrollListener: Function;
|
||||
private mouseupListener: Function;
|
||||
private mousedownListener: Function;
|
||||
private mousemoveListener: Function;
|
||||
private movingModeState: Subscription;
|
||||
|
||||
constructor(
|
||||
private context: Context,
|
||||
private movingEventSource: MovingEventSource
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.movingModeState = this.movingEventSource.movingModeState.subscribe((event: boolean) => {
|
||||
event ? this.activate() : this.deactivate();
|
||||
});
|
||||
}
|
||||
|
||||
activate() {
|
||||
this.addMoveListener();
|
||||
this.addZoomListener();
|
||||
}
|
||||
|
||||
addMoveListener() {
|
||||
this.mousemoveListener = (event: MouseEvent) => {
|
||||
const view = select(this.svg);
|
||||
const canvas = view.selectAll<SVGGElement, Context>('g.canvas').data([this.context]);
|
||||
|
||||
canvas.attr('transform', () => {
|
||||
this.context.transformation.x = this.context.transformation.x + event.movementX;
|
||||
this.context.transformation.y = this.context.transformation.y + event.movementY;
|
||||
|
||||
const xTrans = this.context.getZeroZeroTransformationPoint().x + this.context.transformation.x;
|
||||
const yTrans = this.context.getZeroZeroTransformationPoint().y + this.context.transformation.y;
|
||||
const kTrans = this.context.transformation.k;
|
||||
|
||||
return `translate(${xTrans}, ${yTrans}) scale(${kTrans})`;
|
||||
});
|
||||
};
|
||||
this.mousedownListener = (event: MouseEvent) => {
|
||||
this.mouseupListener = (event: MouseEvent) => {
|
||||
this.removelisteners();
|
||||
};
|
||||
|
||||
this.svg.addEventListener('mouseup', this.mouseupListener as EventListenerOrEventListenerObject);
|
||||
this.svg.addEventListener('mousemove', this.mousemoveListener as EventListenerOrEventListenerObject);
|
||||
};
|
||||
this.svg.addEventListener('mousedown', this.mousedownListener as EventListenerOrEventListenerObject);
|
||||
}
|
||||
|
||||
addZoomListener() {
|
||||
this.scrollListener = (event: WheelEvent) => {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
|
||||
let zoom = event.deltaY;
|
||||
zoom = event.deltaMode === 0 ? zoom/100 : zoom/3;
|
||||
|
||||
const view = select(this.svg);
|
||||
const canvas = view.selectAll<SVGGElement, Context>('g.canvas').data([this.context]);
|
||||
|
||||
canvas.attr('transform', () => {
|
||||
this.context.transformation.k = this.context.transformation.k - zoom/10;
|
||||
|
||||
const xTrans = this.context.getZeroZeroTransformationPoint().x + this.context.transformation.x;
|
||||
const yTrans = this.context.getZeroZeroTransformationPoint().y + this.context.transformation.y;
|
||||
const kTrans = this.context.transformation.k;
|
||||
|
||||
return `translate(${xTrans}, ${yTrans}) scale(${kTrans})`;
|
||||
});
|
||||
};
|
||||
document.addEventListener('wheel', this.scrollListener as EventListenerOrEventListenerObject);
|
||||
}
|
||||
|
||||
removelisteners() {
|
||||
this.svg.removeEventListener('mouseup', this.mouseupListener as EventListenerOrEventListenerObject);
|
||||
this.svg.removeEventListener('mousemove', this.mousemoveListener as EventListenerOrEventListenerObject);
|
||||
}
|
||||
|
||||
deactivate() {
|
||||
this.svg.removeEventListener('mouseup', this.mouseupListener as EventListenerOrEventListenerObject);
|
||||
this.svg.removeEventListener('mousedown', this.mousedownListener as EventListenerOrEventListenerObject);
|
||||
this.svg.removeEventListener('mousemove', this.mousemoveListener as EventListenerOrEventListenerObject);
|
||||
document.removeEventListener('wheel', this.scrollListener as EventListenerOrEventListenerObject);
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.movingModeState.unsubscribe();
|
||||
}
|
||||
}
|
65
src/app/cartography/directives/moving-canvas.directive.ts
Normal file
65
src/app/cartography/directives/moving-canvas.directive.ts
Normal file
@ -0,0 +1,65 @@
|
||||
import { HostListener, ElementRef, Renderer, Directive, Input, OnInit, OnDestroy } from '@angular/core'
|
||||
import { Subscription } from 'rxjs';
|
||||
import { MovingEventSource } from '../events/moving-event-source';
|
||||
import { Context } from '../models/context';
|
||||
import { select } from 'd3-selection';
|
||||
|
||||
@Directive({
|
||||
selector: '[movingCanvas]',
|
||||
})
|
||||
export class MovingCanvasDirective implements OnInit, OnDestroy {
|
||||
private mouseupListener: Function;
|
||||
private mousemoveListener: Function;
|
||||
private movingModeState: Subscription;
|
||||
private activated: boolean = false;
|
||||
|
||||
constructor(
|
||||
private element: ElementRef,
|
||||
private movingEventSource: MovingEventSource,
|
||||
private context: Context
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.movingModeState = this.movingEventSource.movingModeState.subscribe((event: boolean) => {
|
||||
this.activated = event;
|
||||
if (!event) this.removelisteners();
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.movingModeState.unsubscribe();
|
||||
}
|
||||
|
||||
@HostListener('mousedown', ['$event'])
|
||||
onMouseDown(event: MouseEvent) {
|
||||
if (this.activated) {
|
||||
this.mousemoveListener = (event: MouseEvent) => {
|
||||
const view = select(this.element.nativeElement);
|
||||
const canvas = view.selectAll<SVGGElement, Context>('g.canvas').data([this.context]);
|
||||
|
||||
canvas.attr('transform', () => {
|
||||
this.context.transformation.x = this.context.transformation.x + event.movementX;
|
||||
this.context.transformation.y = this.context.transformation.y + event.movementY;
|
||||
|
||||
const xTrans = this.context.getZeroZeroTransformationPoint().x + this.context.transformation.x;
|
||||
const yTrans = this.context.getZeroZeroTransformationPoint().y + this.context.transformation.y;
|
||||
const kTrans = this.context.transformation.k;
|
||||
|
||||
return `translate(${xTrans}, ${yTrans}) scale(${kTrans})`;
|
||||
});
|
||||
};
|
||||
|
||||
this.mouseupListener = (event: MouseEvent) => {
|
||||
this.removelisteners();
|
||||
};
|
||||
|
||||
this.element.nativeElement.addEventListener('mouseup', this.mouseupListener as EventListenerOrEventListenerObject);
|
||||
this.element.nativeElement.addEventListener('mousemove', this.mousemoveListener as EventListenerOrEventListenerObject);
|
||||
}
|
||||
}
|
||||
|
||||
removelisteners() {
|
||||
this.element.nativeElement.removeEventListener('mouseup', this.mouseupListener as EventListenerOrEventListenerObject);
|
||||
this.element.nativeElement.removeEventListener('mousemove', this.mousemoveListener as EventListenerOrEventListenerObject);
|
||||
}
|
||||
}
|
53
src/app/cartography/directives/zooming-canvas.directive.ts
Normal file
53
src/app/cartography/directives/zooming-canvas.directive.ts
Normal file
@ -0,0 +1,53 @@
|
||||
import { HostListener, ElementRef, Renderer, Directive, Input, OnInit, OnDestroy } from '@angular/core'
|
||||
import { Subscription } from 'rxjs';
|
||||
import { MovingEventSource } from '../events/moving-event-source';
|
||||
import { Context } from '../models/context';
|
||||
import { select } from 'd3-selection';
|
||||
|
||||
@Directive({
|
||||
selector: '[zoomingCanvas]',
|
||||
})
|
||||
export class ZoomingCanvasDirective implements OnInit, OnDestroy {
|
||||
private movingModeState: Subscription;
|
||||
private activated: boolean = false;
|
||||
|
||||
constructor(
|
||||
private element: ElementRef,
|
||||
private movingEventSource: MovingEventSource,
|
||||
private context: Context
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.movingModeState = this.movingEventSource.movingModeState.subscribe((event: boolean) => {
|
||||
this.activated = event;
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.movingModeState.unsubscribe();
|
||||
}
|
||||
|
||||
@HostListener('window:wheel', ['$event'])
|
||||
onWheel(event: WheelEvent) {
|
||||
if (this.activated) {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
|
||||
let zoom = event.deltaY;
|
||||
zoom = event.deltaMode === 0 ? zoom/100 : zoom/3;
|
||||
|
||||
const view = select(this.element.nativeElement);
|
||||
const canvas = view.selectAll<SVGGElement, Context>('g.canvas').data([this.context]);
|
||||
|
||||
canvas.attr('transform', () => {
|
||||
this.context.transformation.k = this.context.transformation.k - zoom/10;
|
||||
|
||||
const xTrans = this.context.getZeroZeroTransformationPoint().x + this.context.transformation.x;
|
||||
const yTrans = this.context.getZeroZeroTransformationPoint().y + this.context.transformation.y;
|
||||
const kTrans = this.context.transformation.k;
|
||||
|
||||
return `translate(${xTrans}, ${yTrans}) scale(${kTrans})`;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user