Enhancing static SVG with dynamic tooltips using D3.js

Our challenge involves adding tooltips dynamically to a static SVG image when a hover event occurs on an object within the SVG using d3.js in the context of an AngularJS application.

The SVG image we are working with is a floorplan, which is quite intricate. To start off, we have included a small representative snippet of one section:

<g id="f3s362c12">
  <g>
    <rect x="75.2" y="92.4" pointer-events="visible" fill="none" 
    width="64.7" height="57.8" />
    <polyline fill="none" stroke="#CDDDED" stroke-width="0.5" 
     stroke-miterlimit="10" points="118.4,149.9 140.3,149.9 140.3,92.4
     75.2,92.4 75.2,128.7" />
  </g>
  <g>
    <text transform="matrix(1 0 0 1 87.8719 144.8836)" fill="#010101" 
    font-family="arial, sans-serif" font-size="13.4182">362.12</text>
  </g>
</g>

While D3.js is a new tool for us, our research indicates that it may be the solution we need, as it works well with SVG and can manipulate data within SVG images. However, most examples we found demonstrate dynamically creating SVG (particularly charts) rather than modifying existing SVG images.

In summary, our objectives are:

  1. Identify g tags starting with "f3", like g id="f3s362c12" above
  2. Add a tooltip hover event to each associated rect within the g tag
  3. Retrieve corresponding data records from a .csv file when a user hovers over a specific g tag, such as f3s362c12:

({"floor":"3","location":"f3s362c12","name":"David Byrne","occ":"Singer","img":"img/davidAvatar.jpg\r"})

  1. Show this information in the tooltip so that hovering over g id=f3s362c12 displays details about David Byrne, including his occupation and avatar image.

We have provided a Plunk demonstration that:

  1. Loads the SVG in the HTML
  2. Imports the .csv file

Our current struggle lies in implementing d3.js functionality. For instance, in our Plunk, specifically script.js, we are attempting to locate g tags as follows:

 var svg = d3.select("#svgFP");
 var allG = svg.selectAll("g").each(function (d,i) {}

At this point, we encounter challenges when trying to access a rect element within allG using the "this" keyword.

if (this.id.indexOf("f3") > -1)
 {
        //1. Add label/div/hover
        //2. Find corresponding record from array object.
        //3. Inject respective name, occupation and image into label/div along with mouseover/mouseout event.
 }

We have been experimenting with Firebug to identify suitable properties, but the process has proved quite frustrating. We are hopeful that there might be experienced d3.js/angular experts in this community who can offer some guidance.

We appreciate any help in advance.

Answer №1

In your plunker, the initial issue lies in your CSV: the first row should always be the header, defining each column's content. To correct this, I made adjustments to your CSV:

floor,location,name,surname,role,image
3,f3s362c12,David ,Byrne,Singer,img/davidAvatar.jpg
3,f3s362c11,Tina,Weymouth,Bassist,img/tinaAvatar.jpg
3,f3s362c2,Jerry,Harrison,Keyboards,img/jerryAvatar.jpg
3,f3s362c1,Chris,Frantz,Drums,img/chrisAvatar.jpg

With regard to your actual inquiry...

The optimal D3 approach involves binding data to DOM elements, specifically in your SVG setup. However, since you're utilizing a static SVG not built with D3 and data isn't bound, here's an alternative solution.

Firstly, select all pertinent group elements:

var groups = d3.selectAll("g[id^='f3']");

Add the mouseover function to that selection.

The crux of this solution comes within the mouseover code block: extracting the ID of the element beneath the cursor...

var groupId = this.id

...then, leveraging this ID to filter the previously imported CSV dataset:

var thisData = data.filter(function(d) {
    return d.location === groupId
});

This snippet essentially filters the loaded CSV (stored in a variable named

data</code). Each object within 'data' possesses a <code>location
property, as per the new CSV header. By comparing each object's location with the group's ID (groupId), we generate a specific subset called thisData.

You now possess a variable (thisData) ready for populating your tooltip information.

Below is a concise example featuring a MCVE version of your script:

(preformatted code examples) ... (preformatted CSS) ... (script and SVG snippets) ... (preformatted CSV) ...

To summarize the steps involved:

  1. Establish a selector for mouse events;
  2. Parse and load your CSV file;
  3. Upon hovering over a <g> element, filter your data array based on that <g>'s unique identifier;
  4. Utilize the filtered array to construct the HTML content for your tooltip.

Note: In this illustration, I've utilized a <pre> element to hold your CSV content due to limitations within this platform compared to Plunker.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

the navigation process in $state was not successful

In order to navigate from page A to B, I included the following code in my page A (history.html) view: <a href="#/history/{{data.id}}"> <li class="item"> {{data.items}} </li> </a> In my app.js file, I set the state as ...

The function forEach is unable to handle the process of uploading multiple images to cloudinary

I'm facing an issue with uploading multiple images to Cloudinary from my Vue2JS front-end. I have successfully created a function that uploads a single image, but I am struggling with uploading multiple images using a forEach loop. upload(evt) { ...

Tips for eliminating the undefined/null values from an array nested within another array in Angular

DATA = [{ application: [{ name: 'Room1' },{ name: 'Room2' },{ name: 'Room3' },{ name: 'Room4' },{ name: 'Room5' }], name: 'Batch 1&ap ...

jQuery's AJAX feature fails to identify the newly modified div classes

For my new website, I am developing a simple checklist feature. To handle the check and uncheck requests from users, I'm using jQuery's $.ajax() function. Whenever a user clicks on the check or uncheck buttons, jQuery retrieves the validation tok ...

The Chrome browser allows interaction between two separate divs, where a button located in one div can impact

One issue I encountered involves a button located within a div that has unintended consequences for another div. Here is the basic structure of the elements: <div> <div> <div> <div> <butto ...

Get tabular information in xlsx format by utilizing the xlsx npm package for download

I have been attempting to convert my json-like data into an xlsx file format. I utilized the xlsx npm package and followed various code samples available online, however, when trying to open the file in Excel, I encountered the following error: https://i.s ...

The variable remains undefined, despite the fact that the code executes correctly in a different location

I'm currently working on a multiplayer game in three js and integrating socket.io for real-time communication. I have all the player characters stored in an array called players on the server side. When each client connects, I send them the list of p ...

Get the value of an HTML element

Is there a way to retrieve the value of an HTML element using PHP or JavaScript, especially when the value is dynamically loaded from another source? I have tried using jQuery with the DOM ready event, but often encounter the issue where the element's ...

Integrating Bootstrap-vue into your Webpack setup for seamless usage

After beginning a project with vuejs-templates and webpack, I decided to incorporate bootstrap-vue. Now, the challenge is figuring out how to implement a bootstrap button. In my code base, specifically in main.js, I have imported BootstrapVue: import Vu ...

Mark scheduled specific time periods

I need help removing booked time slots from the total time slots. How can I achieve this? Input: Actual time slots: [ '10:00-10:30', '10:30-11:00', '11:00-11:30', '11:30-12:00', '12:00-12:30', ...

Transferring files via Bluetooth on PhoneGap

As someone new to phonegap, I'm interested in transferring text files from one device to another using Bluetooth within the platform. I've looked at several examples but haven't found a solution yet. I've come across some examples that ...

when the window is scrolled a certain amount, use jQuery to scroll back in the opposite direction

Using jQuery for Background Image Position: $(window).scroll(function() { var scroll = $(window).scrollTop(); if (scroll >= 50) { $(".class").addClass("bgposi"); // $(".top").addClass("fixd"); // $(".logo").addClass ...

Using Codeigniter to fetch a PHP array in an AJAX success callback

I have implemented a jQuery script to send the value selected from a dropdown menu to my controller. The controller then calls a function in my model to execute a query using this value, and retrieve an array of results from the database. These results are ...

What is the method for inputting multi-line strings in the REST Client extension for Visual Studio Code?

Clarification There seems to be some confusion regarding the nature of the data I am storing. I am developing a code snippet web application using Express.js and MongoDB. The purpose is not to store executable code for later use; instead, I am saving snipp ...

Blank white screen in Three.js following the rendering of numerous objects

I have a situation where I am loading over 4350 3D objects from JSON files in my game. for (var y in game.fields) { for (var x in game.fields[y]) { switch (game.fields[y][x]) { case 'm': ...

When using node.js and express, attempting to send an email with the packages 'nodemailer' and 'nodemailer-handlebars' may result in a TypeError being thrown, specifically [ERR_INVALID_ARG_TYPE]

I am encountering an issue while attempting to send an email using an HTML template located in the 'view' folder within the same path. The HTML template is named 'index.handlebars'. Despite believing that the path is correct, I am recei ...

What is the best way to iterate through two arrays without disrupting the sequence of displayed elements?

I am currently working on developing a chat-bot that includes the functionality of sending and receiving voice audio. To achieve this, I have implemented two separate array states: one for rendering text messages and another for rendering audio messages. I ...

Error: $this.text is throwing a TypeError and is not working as a function

Upon examining the code below: var $this = $(this).children('div.submenu1').children('a.subtile')[0], title = $this.text(), name = $this.attr('node').val; An error is encountered: Uncaught TypeError: $this.text is not a fun ...

Leverage the power of AngularJS by seamlessly updating controller variables from a directive and integrating

I recently delved into using AngularJS and managed to create an image fallback directive with some guidance from Stack Overflow. The fallback feature is operational, but now I'm looking to incorporate a boolean variable, possibly set in the controller ...

The Art of Validating Forms in Vue.js

Currently I am in the process of developing a form with validation using Vue, however, I've run into some errors that are showing up as not defined even though they are currently defined. HTML <form class="add-comment custom-form" @submit="checkF ...