spidey
spidey

Reputation: 141

How to add popup on D3.js visualization (tree nodes)

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

Answers (2)

ShahnawazVhora
ShahnawazVhora

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

B Kalra
B Kalra

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

Related Questions