0

I am trying to get an svg path to be 'clickable' when put into an file rather than put in-line in the document.

Basically I just want to be able to click on the filled elements of an image, not any empty areas. I have converted my PNG image to svg and got this working, so that when I click on the filled areas the code executes as I need to, but not when clicking on any empty areas.

To do this, I have only had to put in a 'class' to the 'path' tag to make the filled areas interactive via the code.

However, if I now put this svg code into a file and load it into an element, as seems to be the way to do it from what I've read, then it won't working.

I have already added the jquery add on files below, and while these have allowed other svg functions to work it hasn't allowed for this one.

<link rel="stylesheet" type="text/css" href="assets/js/jquery.svg.css"> 

I am unable to interact with the internal svg path within the file even with some simple css. if I put the css into the file directly in a 'style' tag then the css is applied.

I am not sure where to go with this. I have several thousand images that need to have this functionality and each one has a lot of coding to create the path for the svg image so I really don't want to have to put all of these into the html document as it will be a nightmare to deal with.

I've seen people acheieving similar interactions but as yet I've not found one applying jquery or java or even a solution that will get the ability to vary css working.

here is the code for the svg, which is just using a test image rather than one of my own but works the same.

<svg version="1.0" xmlns="http://www.w3.org/2000/svg" width="100%" height="100%" viewBox="0 0 
300.000000 300.000000" preserveAspectRatio="xMidYMid meet">
<g transform="translate(0.000000,300.000000) scale(0.050000,-0.050000)" fill="#00000" stroke="none">
  <!-- The <a> tag we've added -->
         <path class="imageSelector" style="cursor: pointer;" d="M4390 5952 c-113 -53 -289 -221 -427 
-409 -84 -114 -98 -125 -153
-117 -171 27 -523 -80 -714 -217 l-98 -71 -97 71 c-186 137 -427 215 -661 215
l-115 0 -91 123 c-228 310 -551 543 -524 378 5 -30 19 -167 31 -305 12 -137
30 -281 40 -318 17 -66 13 -74 -119 -213 -336 -354 -415 -830 -210 -1265 l50
-106 -38 -104 c-235 -632 -120 -1587 226 -1874 64 -53 11 -59 -607 -64 l-636
-6 -79 -55 c-242 -167 -208 -515 61 -637 75 -34 153 -37 1058 -38 l977 0 -13
-75 c-25 -132 -109 -254 -295 -425 -213 -197 -351 -454 -221 -414 553 173 689
197 799 139 298 -158 287 -155 466 -155 179 0 168 -3 466 155 110 58 246 34
799 -139 130 -40 -8 217 -221 414 -186 171 -270 293 -295 425 l-13 75 977 0
c905 1 983 4 1058 38 269 122 303 470 61 637 l-79 55 -636 6 c-618 5 -671 11
-607 64 346 287 461 1244 225 1877 l-39 107 51 103 c208 416 127 909 -208
1262 -135 141 -136 144 -120 222 10 43 27 178 39 299 13 121 27 258 32 305 5
47 7 85 5 85 -3 0 -50 -22 -105 -48z m-1960 -899 c250 -67 549 -348 550 -518
0 -19 9 -35 20 -35 11 0 20 16 20 35 1 170 300 451 550 518 734 196 1249 -740
706 -1280 -233 -231 -581 -286 -874 -138 -71 36 -130 63 -132 60 -2 -3 -61
-115 -132 -250 -70 -135 -132 -245 -138 -245 -6 0 -68 110 -138 245 -71 135
-130 247 -132 250 -2 3 -61 -24 -132 -60 -297 -151 -682 -79 -905 167 -500
553 23 1441 737 1251z m-55 -3239 c25 -23 45 -55 45 -72 0 -19 25 -1 61 43 78
95 190 105 270 26 47 -47 49 -60 49 -311 0 -251 -2 -264 -49 -311 -80 -79
-192 -69 -270 26 -40 49 -61 63 -61 41 0 -104 -198 -150 -294 -68 l-56 49 0
260 c0 246 3 262 47 310 75 79 175 82 258 7z m1146 -31 c36 -44 59 -60 59 -41
0 114 205 162 298 70 51 -52 52 -59 52 -314 l0 -261 -56 -49 c-93 -80 -294
-37 -294 63 0 16 -9 29 -20 29 -11 0 -20 -11 -20 -24 0 -108 -203 -155 -291
-67 -54 55 -75 504 -27 594 57 108 210 108 299 0z" />
    <path d="M2090 4647 c-352 -186 -235 -697 160 -697 391 0 514 514 166 692 -91
46 -243 48 -326 5z" />
    <path d="M3590 4647 c-352 -186 -235 -697 160 -697 391 0 514 514 166 692 -91
46 -243 48 -326 5z" />
  
</g>
</svg>

If I put this into the document, it works fine. If I load it from a file, the image renders but I can't interact with the class for the path

this is the code for the flie load option:

<object class="imageClass" type="image/svg+xml" data="ImageFile.svg"></object>

thanks for any help on this Update: I have tried several ways to get this to work looking at options online and the help from suggestions below but I haven't had any success in getting the svg to be clickable at all when loaded from a file.

The only way I have been able to even access the inner elements of the svg file is using the following method with jquery.svg:

(document).ready(function() { 
$("#divforSVG").svg(
{ 
onLoad: function() { var svg = $("#divforSVG").svg('get'); 
svg.load('svgFile.svg', {addTo: true, changeSize: false}); 
}, 
settings: {}} ); 
$('#Button').click(function(e) { 
var rect = $('#ImagePath'); 
rect.css('fill','green'); 
rect.attrib('fill','green'); 
}); 
});

This i found from the following link: Modify a svg file using jQuery

This loads the svg file into an element, rather than placing the svg file within an object element in the html page, as seems to be the way suggested. This works, changing the colour by clicking on the button, and can apply this to any inner part of the svg file. However, I cannot find a way to bind a click event to the inner elements of the svg file.

The main method of accessing inner elements of the svg file using the object method, as set out in this link, I can't get to work at all to access any part of the svg element.

How to access SVG elements with Javascript

this seems to be the way to do it with normal javascript but I've not made any progress with it. If anyone has any suggestions on how I may be able to bind a click event using the jquery.svg method as set out above, or how to get the object element method working, I'd greatly appreciate it

Richard Harris
  • 311
  • 1
  • 3
  • 12

1 Answers1

1

If you reference a file in another file, that file is no longer part of the document object model, and Javascript can no longer interact with it. The file has its own, separate DOM.

You were right to use an <object> tag, because that gives you the possibility to bridge the gap between the two DOMs (something that would be impossible with an <img> tag). Basically, with

var childDocument = $('object.imageClass').prop('contentDocument')

you get access to the document interface of the SVG content - but only provided the linked file fullfills the same-origin policy.

Note carefully the role that jQuery plays in this. jQuery has been loaded into the parent document and is not present in the child document. So instead of selecting the SVG root element in the child document with $('svg'), you must use $(childDocument).find('svg'). You cannot traverse from one document to the other with .parent(), .children() or other traversal functions. You cannot delegate events from the child document to elements in the parent document.

The jquery-svg plugin would have to work with

var svg = $(childDocument).find('svg').svg('get')
ccprog
  • 20,308
  • 4
  • 27
  • 44
  • thanks for your input. Suspected it would be something like this but i'm not too familiar with using svg. I'll have a play around with those suggestions and see what I can do. – Richard Harris Aug 21 '20 at 14:11
  • hello, thanks again for your reply. have tried a number of different methods around your suggestion but not been able to get anywhere. looking at these two links (http://www.petercollingridge.co.uk/tutorials/svg/interactive/javascript/, https://stackoverflow.com/questions/2753732/how-to-access-svg-elements-with-javascript/3379830#3379830) as well as your code, I tried a simple alert but cannot get it to work with either of the following two methods: – Richard Harris Sep 01 '20 at 22:50
  • window.addEventListener("load", function() { var svgObject = document.getElementsByClassName('imageClass').contentDocument; var element = svgObject.getElementsByClassName('imageSelector'); $(element).on('click', function(){ alert("The image was clicked."); }); }); – Richard Harris Sep 01 '20 at 22:51
  • var a = document.getElementsByClassName("imageClass"); a.addEventListener("load",function(){ var svgDoc = a.contentDocument; var delta = svgDoc.getElementsByClassName("imageSelector"); // add behaviour delta.addEventListener("mousedown",function(){ alert('hello world!') }, false); }, false); – Richard Harris Sep 01 '20 at 22:53
  • These seem to be the methods to access elements within an svg, but can't get it to work with any element, whether the svg tag, g tag or path tag. I've stripped out pretty much everything else on the page to test it, other than an inline version of the imagewith the same alert, which works fine. Can't find anything to suggest another way of doing this. Thanks in advance for any further help – Richard Harris Sep 01 '20 at 22:57
  • This is what I tried using your 'get' method but still no joy: window.addEventListener("load", function() { var childDocument = $('object.imageClass').prop('contentDocument'); var svg = $(childDocument).find('svg').svg('get'); $(svg.imageSelector).on('click', function(){ alert("The image was clicked."); }); }); – Richard Harris Sep 01 '20 at 23:04
  • 1. `document.getElementsByClassName("imageClass")` returns a HTMLCollection. If you do not use jQuery, you have to loop through all members yourself. 2. `$(svg.imageSelector)` will find nothing since `svg` is a jQuery-svg object that has no property `imageSelector`, try `var svg = $(childDocument).find('svg'); svg.find('.imageSelector').on('click', ...); });`. Note this does **not** initialize the jQuery-svg plugin object with `.svg('get')`. – ccprog Sep 01 '20 at 23:42
  • Hi Again. I upgraded the jquery library link (was on and old one for some reason in the header) and has helped a bit to get the jquery .svg working a bit better. If i load the svg file into the dom in the following way, then I can access the internal elements of the svg file through a button. The following code will change the colour of the svg path now. However, I cannot get the loaded file elements to be clickable themselves. Think I'm close but can't seem to get the right combination. – Richard Harris Sep 10 '20 at 00:29
  • $(document).ready(function() { $("#divforSVG").svg({ onLoad: function() { var svg = $("#divforSVG").svg('get'); svg.load('svgFile.svg', {addTo: true, changeSize: false}); }, settings: {}} ); $('#Button').click(function(e) { var rect = $('#ImagePath'); rect.css('fill','green'); //rect.attrib('fill','green'); }); }); – Richard Harris Sep 10 '20 at 00:33
  • Thanks for any further input you may have – Richard Harris Sep 10 '20 at 00:33
  • Just to add, I did try the following after your suggestion but couldn't get it to work. $(document).ready(function() { var childDocument = $('.imageClass').prop('contentDocument'); var svg = $(childDocument).find('svg'); svg.find(".imageSelector").on("click", function () { alert("The image was clicked."); }) }); – Richard Harris Sep 10 '20 at 01:53
  • Comments are not the place to ask questions. Please either post a new question or add an edit to this one detailing both your progress and your failings. – ccprog Sep 10 '20 at 01:55
  • Ok, appologies I thought this was the way I was meant to do it. Will update now – Richard Harris Sep 10 '20 at 14:39