Triggering Actions with SVG Paths

In reference to the code snippet provided below on how to retrieve data with a click on an SVG path here, I am facing an issue with my example that displays Number 2. I want the alert button to appear only when the cursor is clicked near number 2. Currently, my code is flawed as it triggers the alert box even when the click is far away from Number 2. Any assistance on this matter would be greatly appreciated :)

function getKey(button) {
 let key = button.querySelectorAll('path')[0].dataset.key;
 alert('key is ' + key)
}
<div onClick="getKey(this)">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="800pt" height="600pt" viewBox="0 0 800 600 " id="svg1">
  <g enable-background="new">
    <path data-key="12345" transform="matrix(1,0,0,-1,0,600)" stroke-width=".74" stroke-linecap="round" stroke-linejoin="round" fill="none" stroke="#000000" d="M 224.34 585.57 L 224.34 586.6 L 225.22 588.68 L 226.1 589.71 L 227.87 590.75 L 231.39 590.75 L 233.15 589.71 L 234.04 588.68 L 234.92 586.6 L 234.92 584.53 L 234.04 582.46 L 232.27 579.35 L 223.46 568.98 L 235.8 568.98 "/>
  </g>
</svg>
</div>

Answer №1

this in an element's onclick attribute refers to the element itself

Setting an onclick attribute on a div containing an svg allows any click within the div to trigger the function. By passing this as an argument, it will always reference the specific div element.

After the function is triggered, it extracts the data attribute of the first path tag within the div.

An alternative approach would be to attach an eventListener directly to the path elements. This way, each event generates an event object with a target property pointing to the element that initiated the event. This target element should then have its data attribute extracted.

For more information, visit: https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener

The provided code snippet demonstrates how to attach event listeners to various paths in your SVG image.

let paths = document.querySelectorAll('path');
// paths represents all path elements;
// assign event listeners to each path element;
for (let i=0; i<paths.length; i++) {
  paths[i].addEventListener('click', event => alert(event.target.dataset.key));
} 
<div>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="800pt" height="600pt" viewBox="0 0 800 600 " id="svg1">
  <g enable-background="new">
    <path data-key="12345" transform="matrix(1,0,0,-1,0,600)" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" fill="none" stroke="#000000" d="M 224.34 585.57 L 224.34 586.6 L 225.22 588.68 L 226.1 589.71 L 227.87 590.75 L 231.39 590.75 L 233.15 589.71 L 234.04 588.68 L 234.92 586.6 L 234.92 584.53 L 234.04 582.46 L 232.27 579.35 L 223.46 568.98 L 235.8 568.98 "/>
  </g>
</svg>
</div>

If you have numerous paths, duplicating the same handler function for each path may not be memory-efficient. It is recommended to use a single handler function and assign it to each event listener individually. Like so:

let paths = document.querySelectorAll('path');
// paths represents all path elements;
// assign event listeners to each path element;
for (let i=0; i<paths.length; i++) {
  paths[i].addEventListener('click', displayAlert);
} 

function displayAlert(event) {
  alert(event.target.dataset.key)
}
<div>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="800pt" height="600pt" viewBox="0 0 800 600 " id="svg1">
  <g enable-background="new">
    <path data-key="12345" transform="matrix(1,0,0,-1,0,600)" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" fill="none" stroke="#000000" d="M 224.34 585.57 L 224.34 586.6 L 225.22 588.68 L 226.1 589.71 L 227.87 590.75 L 231.39 590.75 L 233.15 589.71 L 234.04 588.68 L 234.92 586.6 L 234.92 584.53 L 234.04 582.46 L 232.27 579.35 L 223.46 568.98 L 235.8 568.98 "/>
  </g>
</svg>
</div>
Take note that the displayAlert function is referenced within the event listener without parentheses or arguments. The event is automatically passed to the external function mentioned by name (ensure the function declaration supports an argument if utilizing the passed event inside). While unlikely to cause memory issues with such a simple function, this is included for thoroughness.

Alternatively, consider attaching a single event listener to the div and verifying that the event's target is a path before displaying the related data. Despite being attached to the div, the event's target adjusts based on which child element was clicked:

let div = document.getElementById('svg-container');

div.addEventListener('click', event => {
  if (event.target.tagName == 'path') alert(event.target.dataset.key)
});
 
<div id="svg-container">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="800pt" height="600pt" viewBox="0 0 800 600 " id="svg1">
  <g enable-background="new">
    <path data-key="12345" transform="matrix(1,0,0,-1,0,600)" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" fill="none" stroke="#000000" d="M 224.34 585.57 L 224.34 586.6 L 225.22 588.68 L 226.1 589.71 L 227.87 590.75 L 231.39 590.75 L 233.15 589.71 L 234.04 588.68 L 234.92 586.6 L 234.92 584.53 L 234.04 582.46 L 232.27 579.35 L 223.46 568.98 L 235.8 568.98 "/>
  </g>
</svg>
</div>

Important note:

When using narrow strokes for paths, users might find it challenging to precisely click on the line, potentially leading to missed clicks. To address this, consider duplicating paths, setting wider strokes for enhanced visibility, or adding invisible rectangles behind characters for easier interaction.

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

Dynamic form population with dropdown selection using Ajax - Coldfusion continuation

Following some valuable feedback from my previous inquiry, I have made progress: Refer to the original post - Coldfusion Populate form with dropdown selection using ajax Currently, I have successfully sent a request to my CFC with a remote function, but I ...

Guide to sorting data by the status value within a JavaScript object?

I have a JavaScript object structured like this: { "3": { "id": 3, "first": "Lisa", "last": "Morgan", "email": "<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="bbd7d6d4c9dcdad5fbdcd6dad2d795d8d4d6">[email&# ...

Stop the web browser from storing the value of the input control in its cache

Many web browsers have a feature that saves the information you enter into certain fields so you don't have to type it again. While this can be convenient for most cases, I am faced with a situation where users must input a unique reference for a new ...

Activate dynamic form fields using Ajax

Consider a scenario where the code looks like this: <div id="stuff<? echo $dynID; ?>" class="bla"> <form id="myform<? echo $dynID; ?> " action="bla.php"> <input name="iname<? echo $dynID; ?>" value="<? echo $row[1] ...

Drawing text on a canvas using fillText() in an Android 2.x browser

context.fillText(text,x,y,maxWidth); The maxWidth argument is not functioning properly on Android 2.x; it is being ignored altogether. ...

Using CSS and Vue, you can customize the appearance of inactive thumbnails by displaying them

My goal is for a clicked thumbnail to display in color while the others show as grey. The active thumbnail will be in color, and I want inactive thumbnails to appear in grey. Here is what I am trying to achieve: Vue.component('carousel', { ...

Having trouble with jQuery not sending JSON data?

Is there a way to interact with a specific view using the CouchDB API? I have attempted to achieve this by requesting data from the following endpoint: $.post(targetURL, { "keys": ["Query Value"] }, function (data, status) { cons ...

Combine the leftover bytes from a byte array into a complete new byte array

When dealing with a TCP stream that fills up a 256 byte[], I need to process the byte array by parsing out messages. However, once the first array has less than 100 bytes remaining, I want to transfer the excess bytes to a new array and append it to anothe ...

The responsiveness of Bootstrap 5 columns in Chrome inspection appears to break after reaching medium size, yet functions properly in other areas

I am currently working with cards within a grid system, but I am encountering an issue with resizing when the column size is smaller than medium in the mobile view inside the inspect section. The width does not expand to 100%, regardless of how much I try ...

Issue encountered in React: Unable to access object value within ComponentDidUpdate method

I'm struggling to retrieve the value from an object key. componentDidUpdate(prevProps) { if (prevProps !== this.props) { console.log("component did update in top menu", this.props.topmenudata[0]) this.setState({ ...

A step-by-step guide on activating dark mode for the markdown-it-vue plugin while incorporating Vuetify styling

I'm looking to display some documentation in my Vue application. The documentation is in markdown format, so I have already integrated the markdown-it-vue plugin. However, I've run into an issue where the plugin doesn't support vuetify dark ...

What could be causing my Java code for generating Pascal's Triangle to malfunction?

After encountering my question being put on hold, I have decided to present it again. In an assignment assigned by my professor, we are required to create Pascal's triangle using Java. The professor has provided us with a Main class that is already c ...

I am unable to input just one numerical value into my function

I am encountering an issue with my function that calls another function. The problem arises when inputting single numbers in the prompt; I have to append a letter like (a1, a2, a3) for it to function correctly. The function "PrintSelectedToPDF" works smoo ...

What is the process for updating a MySQL database by clicking a button?

Hey there, I have a bit of a dilemma. I know that accomplishing this task can't be done solely with PHP; I believe Ajax/Javascript is required. Unfortunately, my knowledge in these areas is quite limited, so I could really use your assistance. Here&a ...

What is the best method for retrieving JSON POST data in ASP.NET Web Forms?

I have implemented some jquery code on my website to post data. Currently, I am testing the code by posting JSON data. However, I am facing difficulties in retrieving the data on the back-end once it has been posted. Typically, I have used Request.Params ...

Place a stationary element under another stationary element

I have a dilemma with two fixed elements on my website. One of them can toggle between display: block and display: none, while the other is always visible. I want both elements to stay at the top of the webpage without overlapping each other. I've co ...

Setting the minimum width for a grid item in a React Material UI component

Is there a way to ensure that a material-ui Grid item has a minimum width of 250 pixels? I've tried using the sizing suggestions from Material UI's documentation, but haven't had any success. The 'logo' element within the Grid cont ...

The jQuery dataFilter function appears to be leading to empty data being passed to the ajax success callback

For my jQuery calls that return JSON data, I have implemented an ajax dataFilter to automatically convert .Net-encoded dates to JavaScript dates: $.ajaxSetup({ dataFilter: function(data, type) { var rx = /"\\\/Date\(([0-9]+ ...

Yii2: implementing the safe validator based on a specified condition

I am having some issues with implementing this validation rule in my model. It doesn't seem to be working as expected. Even when I select another option, it still remains safe. [['dhanwantri_bill_number'], 'safe', 'when ...

Double tap problem with pseudo elements on iOS links

Trying to achieve a scrolling line effect beneath anchor links for a client project led me to attempt some CSS3 coding, only to find myself stuck with an elusive bug after spending hours on it. The issue arises on mobile devices (iOS and Android) where, up ...