Создайте функциональную подсказку для 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 вмид всехлихих преимуществах .