Reputation: 141
We are using d3.js tree (d3.tree()) to render org chart visualization. It is very similar to https://observablehq.com/@julienreszka/d3-v5-org-chart
I want to display small popup over the node on click/mouseover of some button. e.g. clicking on person image display small popup with some more actions. So user can click on any of the link in popup.
Is there any recommended approach to achieve it in D3js?
Upvotes: 0
Views: 770
Reputation: 9
First, you can import
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
after that, you can declare in constructor like this
constructor(public override injector: Injector, private modalService: NgbModal) {
super(injector);
}
after that you can create property like this
@ViewChild('d3TreeChart') d3TreeChart: ElementRef;
you can simply declare the this.openPopup method
const nodeEnter = node
.enter()
.append('g')
.attr('class', 'node')
.attr('transform', (d: any) => {
return 'translate(' + source.y0 + ',' + source.x0 + ')';
})
// .on('click', (_: any, d: any) => this.click(d));
.on('click', (event:any, d:any) => this.openPopup(event, d));
after that you can create openPopup && closeModel method
openPopup(event:any, d:any) {
// Inside openPopup whatever you can display
this.modalService.open(this.d3TreeChart, {
ariaLabelledBy: 'modal-basic-title',
});
}
closeModel() {
this.modalService.dismissAll('');
}
now we can create html
<ng-template #d3TreeChart>
<div class="modal-header">
<h6 class="modal-title" id="modal-title">Tree Nodes</h6>
<button type="button" class="close" aria-label="Close" (click)="closeModel()">
<span aria-hidden="true"> × </span>
</button>
</div>
<div class="modal-footer justify-content-start">
<h3 style="white-space: pre-line;">You can attach the event listener for click or mouseover when you update Nodes</h3>
<button type="button" class="btn btn-outline-dark btn-sm" (click)="closeModel()">
Close
</button>
</div>
Here you will not know about the <ng-template>
for that
The ng-template is an Angular element for rendering HTML. It is never displayed directly.
I hope this code it is help for you.
Upvotes: 0
Reputation: 821
You can attach the event listener for click
or mouseover
when you update Nodes. For instance, the example you mentioned has this piece of code:
// Updating nodes
const nodesSelection = centerG.selectAll('g.node')
.data(nodes, d => d.id)
// Enter any new nodes at the parent's previous position.
var nodeEnter = nodesSelection.enter().append('g')
.attr('class', 'node')
.attr("transform", function(d) {
return "translate(" + source.x0 + "," + source.y0 + ")";
})
.attr('cursor', 'pointer')
.on('click', function(d) {
if ([...d3.event.srcElement.classList].includes('node-button-circle')) {
return;
}
attrs.onNodeClick(d.data.nodeId);
})
If you check the onclick
here, it is calling the NodeClick
method; you will need to change NodeClick
or, if you want a mouseover
method, add an .on('mouseover')
event. If you want to target the image in node, then add the event at this place:
nodeUpdate.selectAll('.node-image-group')
.attr('transform', d => {
let x = -d.imageWidth / 2 - d.width / 2;
let y = -d.imageHeight / 2 - d.height / 2;
return `translate(${x},${y})`
})
nodeUpdate.select('.node-image-rect')
.attr('fill', d => `url(#${d.id})`)
.attr('width', d => d.imageWidth)
.attr('height', d => d.imageHeight)
.attr('stroke', d => d.imageBorderColor)
.attr('stroke-width', d => d.imageBorderWidth)
.attr('rx', d => d.imageRx)
.attr('y', d => d.imageCenterTopDistance)
.attr('x', d => d.imageCenterLeftDistance)
.attr('filter', d => d.dropShadowId)
Upvotes: 1