Создайте функциональную подсказку для JSPlumb в Angular

Ожидаемый результат

Как я создалсоздал этоэтокнопки, нажмитеck функция. Я получаю данные, как ожидалось.
Чтобы использовать плагин всплывающей подсказки JSPlumb Tippy, вы должны сначала выполнить следующие предварительные условия:
- JSPlumbбиблиотека: Thэто JavaSскрипт библиотека. that обеспечиваетвозможностьвозможности визуальноподключения элементы на мыб страницед. Вывы можете вниз загрузить эту электронную библиотеку из отсюдана официальномофициальном веб-сайте или внутрина нем, используя пакет strong>agemanager like npm.

npm установить jsplumb
2. Tippy.js библиотека: это легкий, фургон illa JavaScript tooltip библиотекаary tht allows вы должны создаватьте клиентов, чтобы слишкомдать советы дляр вам на мыб странице. Вывы можете вниз загрузить библиотеку от с на официальном веб-сайте или вобновить его, используяна паккаге manager likeke npm.

npm установить типпи.js
3. После того, как у вас вы имеете эти предварительные требования, сайты установленустановлен иd настройкаt up.
давайте создадим пример проекта: -
создайте компонент узла приложения, где мы можем разместить наш код дизайна jsplumb
узел компонента ng g

<div class="content" role="main">
<input type="text" (input)="addNode($event)">
<label>No of Rows</label>
<button (click)="createConnections()">Auto Connect</button>
<div class="container">
<div class="panel-one">
<app-node [nodes]="nodes"></app-node>
</div>
<div class="vl"></div>
<div class="panel-two"></div>
</div>
<router-outlet></router-outlet>
</div>
вставьте приведенный выше код в app.component.html.
В вышеве коде мы разместилие поместили вас r app-node componentвнутриблока div,
из app.component.ts мы передаем данные узлов компоненту узла приложения
import { Component, OnInit } from '@angular/core';
import { jsPlumb } from 'jsplumb';
import tippy from 'tippy.js';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit {
jsPlumbInstance = jsPlumb.getInstance();
title = ' Angular jsPlumb Integration';
nodes = [];
index = 0;
totalNodes: number = 0;
ngOnInit() {
this.addNode(6)
}
addNode(n?) {
this.nodes = [];
this.index = 0;
// let n = num.target.value
this.totalNodes = n;
for (let i = 0; i < n; i++) {
this.nodes.push({
id: 'Node' + (this.index + 1),
name: (this.index + 1),
type: ''
});
this.index += 1;
}
}
// This function creates connections between nodes using the JSPlumb library.
createConnections() {
// Create a new JSPlumb instance with a state machine connector and left/right anchors.
const instance = jsPlumb.getInstance({
Connector: 'StateMachine',
Anchor: ['Left', 'Right'],
});
// Create an array of node IDs from the 'nodes' array.
let nodeIds = []
for (let i = 0; i < this.nodes.length - 1; i++) {
nodeIds.push(this.nodes[i]["id"])
}
// Loop through the node IDs and connect each node to its next neighbor.
for (let i = 0; i < nodeIds.length; i++) {
// Get the source and target IDs for the current connection.
const sourceId = nodeIds[i];
const targetId = nodeIds[(i + 1) % nodeIds.length];
// Connect the source and target nodes using the JSPlumb instance.
instance.connect({
source: this.nodes[i]["id"],
target: this.nodes[i + 1]["id"],
});
// Call the 'autoConnectNodes' function to automatically connect endpoints between nodes.
this.autoConnectNodes(instance, sourceId, targetId);
}
}
// This function automatically connects endpoints between nodes and creates a tooltip with buttons when a connection is made.
autoConnectNodes(instance, sourceId: string, targetId: string): void {
// Use the JSPlumb instance to connect the source and target nodes with a rectangle endpoint.
instance.connect({
source: sourceId,
target: targetId,
anchors: ['Right', 'Left'],
endpoint: 'Rectangle',
paintStyle: {
stroke: 'rgb(153, 203, 58)',
strokeWidth: 2,
},
});
// Create a tooltip with buttons when the user clicks on the source node.
tippy(sourceId, {
// Use HTML content to create a tooltip with buttons.
content: '<div class="tooltip-btns"><button (click)="createCircuit(${this.destinationEndPoint})">1</button><button>2</button><button>close</button></div>',
// Append the tooltip to the parent element.
appendTo: 'parent',
// Allow the tooltip to contain HTML content.
allowHTML: true,
// Position the tooltip at the bottom of the source node.
placement: 'bottom',
// Trigger the tooltip when the user clicks on the source node.
trigger: 'click',
// Make the tooltip interactive so the user can click on the buttons.
interactive: true,
// Add an arrow to the tooltip.
arrow: true,
})
}
}
вставьте приведенный выше код в app.component.ts
онмыe создаем начальные узлы как 6 >аd передача th на our компонент узла.

<ng-template #nodes></ng-template> <div class="modal-container"></div>
вставьте вышеve co в node.component.html

import { Component, OnInit, AfterViewInit, ViewChild, ViewContainerRef, Input, OnChanges } from '@angular/core';
import { NodeService } from './node.service';
import { SimpleModalService } from 'ngx-simple-modal';
import { DialogComponent } from '../dialog.component';
@Component({
selector: 'app-node',
templateUrl: './node.component.html',
styleUrls: ['./node.component.scss']
})
export class NodeComponent implements OnChanges, AfterViewInit {
@Input() nodes;
@ViewChild('nodes', { read: ViewContainerRef, static: true }) viewContainerRef: ViewContainerRef;
constructor(public nodeService: NodeService, public simpleModalService: SimpleModalService) {
}
// This method is called after the view has been initialized.
ngAfterViewInit() {
// Bind a 'connection' event to the JSPlumb instance.
this.nodeService.jsPlumbInstance.bind('connection', info => {
// When a connection is made, display a modal dialog and subscribe to the result.
this.simpleModalService.addModal(DialogComponent, {
title: 'Dialog',
questions: { name: '', type: '' }
})
.subscribe((result) => {
// When the modal dialog is closed, find the target node and update its name and type.
const targetNode = this.nodes.find(node => node.id === info.targetId);
if (targetNode) {
targetNode.name = result.name;
targetNode.type = result.type;
// If the target node is an 'end' node, delete the right endpoint to prevent further connections.
if (targetNode.type === 'end') {
this.nodeService.jsPlumbInstance.deleteEndpoint(info.targetId + 'right');
}
}
});
});
}
// This method is called whenever the input properties of the component change.
ngOnChanges() {
// Delete all existing endpoints.
this.nodeService.jsPlumbInstance.deleteEveryEndpoint();
// Set the root view container reference for the node service.
this.nodeService.setRootViewContainerRef(this.viewContainerRef);
// Clear all nodes from the node service.
this.nodeService.clear();
// If there are any nodes, add them to the node service as dynamic nodes.
if (this.nodes.length > 0) {
this.nodes.forEach(node => {
this.nodeService.addDynamicNode(node);
});
}
}
}
вставьте вышеве co в node.component.ts
Создайтете неде.серверныйфайл, файл, который я имею создатьте этув внутрииде нетде фолддер егоэльф

import {
ComponentFactoryResolver,
Injectable
} from '@angular/core';
import { DynamicNodeComponent } from './dynamic-node.component';
import { jsPlumb } from 'jsplumb';
@Injectable({
providedIn: 'root',
})
export class NodeService {
jsPlumbInstance = jsPlumb.getInstance();
private rootViewContainer: any;
constructor(private factoryResolver: ComponentFactoryResolver) {
}
public setRootViewContainerRef(viewContainerRef) {
this.rootViewContainer = viewContainerRef;
}
public addDynamicNode(node: any) {
const factory = this.factoryResolver.resolveComponentFactory(DynamicNodeComponent);
const component = factory.create(this.rootViewContainer.parentInjector);
(<any>component.instance).node = node;
(<any>component.instance).jsPlumbInstance = this.jsPlumbInstance;
this.rootViewContainer.insert(component.hostView);
}
public clear() {
this.rootViewContainer.clear();
}
}
Вставьтете еевышеве коде внутриидеи нетде.серверvice.ts файл
Создайтете 2 большере компонентовкомпонентов dynamic-node.component.ts, файл dialog.component.ts
import { Component, Input, AfterViewInit } from '@angular/core';
import { SimpleModalService } from 'ngx-simple-modal';
import { DialogComponent } from '../dialog.component';
import tippy, { animateFill, followCursor, inlinePositioning } from 'tippy.js';
export interface Node {
id: string;
name: string;
type: string;
}
@Component({
selector: 'app-dynamic-node',
template: `
<div (dblclick)="editNode(node)" class="node" id="{{node.id}}" style="top: 0; left: 50%;">
{{node.name}}
<!-- <i (click)="removeNode(node)" class="material-icons close">clear</i> -->
</div>`,
styles: [`
.node {
width: 30px;
height: 25px;
padding: 5px;
margin: 10px;
border-radius: 50%;
text-align: center;
position: relative;
box-shadow: 0 10px 40px 0 #b0c1d9;
}
.close {
font-size: 10px;
position: absolute;
right: 9px;
top: 0px;
cursor: pointer;
}
`]
})
export class DynamicNodeComponent implements AfterViewInit {
@Input() node: Node;
@Input() jsPlumbInstance;
sourceEndPoint: any;
destinationEndPoint: any;
exampleDropOptions = {
tolerance: 'touch',
hoverClass: 'dropHover',
activeClass: 'dragActive'
};
source = {
endpoint: ['Dot', { radius: 7 }],
paintStyle: { fill: '#99cb3a' },
isSource: true,
scope: 'jsPlumb_DefaultScope',
connectorStyle: { stroke: '#99cb3a', strokeWidth: 3 },
connector: ['Bezier', { curviness: 63 }],
maxConnections: 1,
isTarget: false,
connectorOverlays: [['Arrow', { location: 1 }]],
dropOptions: this.exampleDropOptions
};
destination = {
endpoint: ['Dot', { radius: 4 }],
paintStyle: { fill: '#ffcb3a' },
isSource: false,
scope: 'jsPlumb_DefaultScope',
connectorStyle: { stroke: '#ffcb3a', strokeWidth: 6 },
connector: ['Bezier', { curviness: 23 }],
maxConnections: 1,
isTarget: true,
dropOptions: this.exampleDropOptions
};
constructor(private simpleModalService: SimpleModalService) { }
ngOnInit() {
}
ngAfterViewInit() {
this.sourceEndPoint = this.jsPlumbInstance.addEndpoint(this.node.id,
{
anchor: 'Right',
uuid: this.node.id + 'right', endpoint: 'Dot',
isSource: true,
isTarget: true,
}, this.source);
this.destinationEndPoint = this.jsPlumbInstance.addEndpoint(this.node.id,
{
anchor: 'Left', uuid: this.node.id + 'left',
maxConnections: 2
}, this.destination);
let tippyInstance = tippy(this.destinationEndPoint.canvas, {
content: `<div class="tooltip-btns"><button data-info=${this.node.id} id ="tooltip-btn-1">1</button><button>2</button><button>close</button></div>`,
appendTo: 'parent',
allowHTML: true,
placement: 'bottom',
// trigger: 'manual',
// trigger: 'click',
interactive: true,
arrow: true,
animation: 'fade',
animateFill: true,
followCursor: true,
inlinePositioning: true,
plugins: [animateFill, followCursor, inlinePositioning],
popperOptions: {
strategy: 'fixed',
modifiers: [
{
name: 'flip',
options: {
fallbackPlacements: ['bottom', 'right'],
},
},
{
name: 'preventOverflow',
options: {
altAxis: true,
tether: false,
},
},
],
},
onMount: (instance) => {
const button = instance.popper.querySelector('#tooltip-btn-1');
button.addEventListener('click', () => {
let info = button.getAttribute("data-info")
// Do something when the button is clicked
console.log(this.node, ' - ', info)
}, { once: true });
},
})
console.log(tippyInstance["popper"]);
}
createCircuit(data) {
console.log(data)
}
removeNode(node) {
this.jsPlumbInstance.removeAllEndpoints(node.id);
this.jsPlumbInstance.remove(node.id);
}
editNode(node) {
this.simpleModalService.addModal(DialogComponent, {
title: 'Dialog',
questions: { name: node.name, type: node.type }
})
.subscribe((result) => {
this.node.name = result.name;
this.node.type = result.type;
if (node.type === 'end') {
this.jsPlumbInstance.deleteEndpoint(node.id + 'right');
} else {
this.jsPlumbInstance.addEndpoint(this.node.id,
{ anchor: 'Right', uuid: this.node.id + 'right' }, this.source);
}
});
}
}
Вставьте приведенный выше код в dynamic-node.component.ts.
import { Component } from '@angular/core';
import { SimpleModalComponent } from 'ngx-simple-modal';
export interface DialogModel {
title: string;
questions: { name: '', type: '' };
}
@Component({
selector: 'app-dialog',
template: `
<div class="modal-content">
<div class="modal-header">
<h4>{{title}}</h4>
</div>
<div class="modal-body">
<label>Name</label>
<!-- <input type="text" class="form-control" [(ngModel)]="questions['name']" name="name" />
<label>Type</label>
<select [(ngModel)]="questions['type']">
<option value="middle">Middle</option>
<option value="end">End</option>
</select> -->
</div>
<div class="modal-footer">
<button type="button" class="btn btn-outline-danger" (click)="close()">Cancel</button>
<button type="button" class="btn btn-primary" (click)="apply()">Save</button>
</div>
</div>
`
})
export class DialogComponent extends SimpleModalComponent<DialogModel, DialogModel['questions']> implements DialogModel {
title: string;
questions: { name: '', type: '' };
constructor() {
super();
}
apply() {
this.result = this.questions;
this.close();
}
}
Вставьте приведенный выше код в dialog.component.ts.
Мy Папкадер Структура: –

Дляр болееотносительной функции действительности ссылки на этот "JSP lumb» и Tippy.js Documentation
Заключение
Созданиеинструментаtip использованиеng Tippy.js в Angleular Angel достаточноэто простопле иd выи ар и идти strong>ing to needd createate one скоро раньше или позже э в тыр ап р.
Even if at firstst it may sou nd kindd of conf использование,you ar e идти ing to платаl удобствоrtable работакороль остроумие h вмид всехлихих преимуществах .