我在SVG元素上实现了SVG图像元素的拖放。这个想法是当pointerdown事件被触发时,pointermove事件被触发,所选的SVG图像元素被拖到指针位置,直到pointerup事件被触发。我使用RxJS fromEvent creational observable。
import { Component, ViewChild, ElementRef, AfterViewInit } from '@angular/core';
import { fromEvent, Observable, Subscription, Subject } from 'rxjs'
import { RouterComponent, Router } from '../router/router.component';
import { ToolbarComponent } from '../toolbar/toolbar.component';
import { LinkComponent } from '../link/link.component';
import * as d3 from 'd3';
import { of } from 'rxjs';
@Component({
selector: 'app-test',
templateUrl: './test.component.html',
styleUrls: ['./test.component.css']
})
export class TestComponent implements AfterViewInit {
@ViewChild("svg") svgElement: ElementRef<SVGSVGElement>;
svg: SVGSVGElement;
moveObjectPointerDown: Subscription;
moveObjectPointerMove: Subscription;
moveObjectPointerUp: Subscription;
linkPointerDown: Subscription;
linkPointerMove: Subscription;
linkPointerUp: Subscription;
@ViewChild(ToolbarComponent) toolbarComponent: ToolbarComponent;
@ViewChild(RouterComponent) routerComponent: RouterComponent;
@ViewChild(LinkComponent) linkComponent: LinkComponent;
constructor() {
}
ngAfterViewInit() {
this.svg = this.svgElement.nativeElement;
this.subscribeMoveMode();
this.toolbarComponent.createRouter$.subscribe(() => {
var router = this.routerComponent.create();
this.routerComponent.add(router);
});
this.toolbarComponent.createHost$.subscribe(() => {
});
}
unsubscribeMoveMode(): void {
this.moveObjectPointerDown.unsubscribe();
this.moveObjectPointerMove.unsubscribe();
this.moveObjectPointerUp.unsubscribe();
}
unsubscribeLinkMode(): void {
this.linkPointerDown.unsubscribe();
this.linkPointerMove.unsubscribe();
this.linkPointerUp.unsubscribe();
}
subscribeMoveMode(): void {
var selectedElement: any;
var offsetX: number;
var offsetY: number;
this.moveObjectPointerDown = fromEvent(this.svg, "pointerdown").subscribe((event: any) => {
if (event.target.classList.contains("router")) {
selectedElement = event.target;
let targetPositionX = selectedElement.getAttributeNS(null, 'x');
let targetPositionY = selectedElement.getAttributeNS(null, 'y');
let mousePositionX = event.clientX;
let mousePositionY = event.clientY;
let ctm = this.svg.getScreenCTM();
mousePositionX -= ctm!.e;
mousePositionY -= ctm!.f;
offsetX = mousePositionX - targetPositionX;
offsetY = mousePositionY - targetPositionY;
}
});
this.moveObjectPointerMove = fromEvent(this.svg, "pointermove").subscribe((event: any) => {
if (selectedElement) {
let mousePositionX = event.clientX;
let mousePositionY = event.clientY;
let ctm = this.svg.getScreenCTM();
mousePositionX -= ctm!.e;
mousePositionY -= ctm!.f;
mousePositionX -= offsetX;
mousePositionY -= offsetY;
selectedElement.setAttributeNS(null, 'x', mousePositionX);
selectedElement.setAttributeNS(null, 'y', mousePositionY);
// update position of router
this.routerComponent.update(selectedElement.id, mousePositionX, mousePositionY);
//this.routerObserver.update(selectedElement.id, selectedElement.x.baseVal.value, selectedElement.y.baseVal.value);
for (let linkID of this.routerComponent.getById(selectedElement.id)!.links) {
this.linkComponent.update(linkID, mousePositionX + 25 - 1, mousePositionY + 25 - 1);
}
}
event.preventDefault();
});
this.moveObjectPointerUp = fromEvent(this.svg, "pointerup").subscribe((event: any) => {
selectedElement = null;
});
}
subscribeLinkMode(): void {
var selectedLineElement: any;
var selectedRouterElement1: any;
var selectedRouterElement2: any;
this.linkPointerDown = fromEvent(this.svg, "pointerdown").subscribe((event: any) => {
selectedRouterElement1 = event.target;
if (selectedRouterElement1.classList.contains("router")) {
var router: Router | undefined = this.routerComponent.getById(selectedRouterElement1.id);
if (router != undefined) {
selectedLineElement = this.linkComponent.create(router.x + 25, router.y + 25, router.x + 25, router.y + 25);
}
}
});
this.linkPointerMove = fromEvent(this.svg, "pointermove").subscribe((event: any) => {
if (selectedLineElement) {
let ctm = this.svg.getScreenCTM();
var mousePositionX = event.clientX;
var mousePositionY = event.clientY;
mousePositionX -= ctm!.e;
mousePositionY -= ctm!.f;
selectedLineElement = this.linkComponent.update(selectedLineElement.id, mousePositionX - 1, mousePositionY - 1);
}
event.preventDefault();
});
this.linkPointerUp = fromEvent(this.svg, "pointerup").subscribe((event: any) => {
if (event.target.classList.contains("router")) {
selectedRouterElement2 = event.target;
var r1 = this.routerComponent.getById(selectedRouterElement1.id)!;
var r2 = this.routerComponent.getById(selectedRouterElement2.id)!;
if (r1.connectedTo.indexOf(r2) == -1 && r2.connectedTo.indexOf(r1) == -1) {
var newLink = this.linkComponent.create(r1.x + 25, r1.y + 25, r2.x + 25, r2.y + 25);
this.routerComponent.addLink(r1.id, newLink.id, r2);
this.routerComponent.addLink(r2.id, newLink.id, r1);
}
}
if (selectedLineElement) {
this.linkComponent.remove(selectedLineElement.id);
selectedRouterElement1 = null;
selectedRouterElement2 = null;
selectedLineElement = null;
}
});
}
}
字符串
我的问题是,有没有更聪明的方法来使用RxJS组合运算符来做到这一点?而不是有三个独立的可观测值与本地共享变量(selectedElement,offsetX,offsetY)。我可以使用combineLatest,或withLatestFrom,或其他吗?
1条答案
按热度按时间ou6hu8tu1#
不要重新发明轮子。换句话说,当尝试实现一个新功能时,寻找一个现有的实现。另外,确保你信任源代码作者,以避免恶意软件。这将为你保存大量的时间。
对于这种拖放特性,您可以利用Angular Material UI component library。
请按照以下步骤操作:
npm i @angular/cdk
ng add @angular/material
字符串
对于独立的应用程序(Angular v17之后的默认设置),没有
NgModule
s。所以,你可以使用这个:型
cdkDrag
指令添加到元素(本例中为SVGimage
):型
使用
DragDropModule
可以做很多事情。访问Drag and Drop页面了解更多信息。