i have an svg image inside object element of HTML document.
<object id="svg1" data="nejc/bg.svg" type="image/svg+xml">
Your browser doesn't support SVG
</object>
And i have javascript code. Inside of it i added click event which execute when svg is done loading. Code look for id in .svg file which i added on groups of elements. Everything is working. But i am having problem now and then when i load page the svg elements cant be clicked, but if i refresh it then the click is working just fine.
$( document ).ready(function() {
//button where are you
var a = document.getElementById("svg1");
//it's important to add an load event listener to the object, as it will load the svg doc asynchronously
a.addEventListener("load",function(){
var svgDoc = a.contentDocument; //get the inner DOM of svg
var delta = svgDoc.getElementById("right"); //get the inner element by id
delta.addEventListener("click",function(){
this.style.fill = '#DC7827';
setTimeout("document.location.href = '_mobile_whereareyou.php';",200);
},false); //add behaviour
},false);
//button place ID
var b = document.getElementById("svg1");
//it's important to add an load event listener to the object, as it will load the svg doc asynchronously
b.addEventListener("load",function(){
var svgDocB = b.contentDocument; //get the inner DOM of svg
var beta = svgDocB.getElementById("left"); //get the inner element by id
beta.addEventListener("click",function(){
this.style.fill = '#DC7827';
setTimeout("document.location.href = '_mobile_placeID.php';",200);
},false); //add behaviour
},false);
});
I am guessing that when svg elements could not be clicked then the svg image did not load correctly. Is there any way how to make sure that svg element is loaded and click is working ?
I think I came to solution. I was thinking right that svg did not load properly when click was not working. So i wrape all code in below block.
$('#svg1').load('nejc/bg.svg', null, function() {
//here is now my code given in question
});
This function load svg and on complete executes code in funtion.
Related
I have imported a svg as an object in HTML:
<object data="mySVG.svg" type="image/svg+xml" id="circle">
<img src="mySVG.svg" />
</object>
and I am trying to set an eventlistener on the whole page:
window.addEventListener('click', function(){
alert('Hello')
})
The problem is that the object blocks the eventlistener and when the user clicks on the image the alert is not fired. But when the user clicks anywhere else or over other elements, the alert is fired. How can I make it so the object is acting as the other elements and doesn't block the eventlistener?
I tried wait after the object is beaing loaded and then set the eventlistener but it didn't work.
If I import the SVG directly into HTML with svg tag it works, but the svg is quit big and it makes the HTML code really messy. I can't use the img tag either becuase I am also interacting with parts of the SVG with JS later.
As it can be seen in this codepen I've made: https://codepen.io/Dimertuper/pen/rNJoLrK (When you click outside the image it triggers, inside the image it doesn't)
Your <object> acts like an <iframe>, just like we wouldn't want any website to be able to embed our bank website in an iframe and see where we clicked, the <object> has the same "protection".
Even if the page are same-origin and can talk to each other, by default they won't receive any events from the other one.
But anyway what you probably want is to make the SVG document react to these events. For this, add the event listeners on that document directly.
// Wait for the <object> to be loaded
window.addEventListener("load", (evt) => {
const objEl = document.querySelector("object");
const svgDoc = objEl.getSVGDocument();
// Now you have access to the SVG document
// you can add event listeners to it as you wish
svgDoc.addEventListener("click", (evt) => {
console.log("clicked on", evt.target.outerHTML);
});
});
Unfortunately StackSnippets's null-origined iframes won't allow us to make live demos, so here is one on JSFiddle.
But beware the <object> element isn't gathering much love from implementers and spec authors these days and it may get removed from the standards at some point in the future.
So instead, you may prefer to actually use an <iframe> directly. Moreover since here we would access the loaded document, we can do the one thing that <object> can do and <iframe> can't: auto-resizing to the image content.
For this, when we get our SVG document, we grab its documentElement's BBox and set our <iframe>'s width and height attributes to the BBox's ones.
// Wait for the <iframe> to be loaded
window.addEventListener("load", (evt) => {
const frameEl = document.querySelector("iframe");
const svgDoc = frameEl.getSVGDocument();
// Resize the iframe to its content's size
const bbox = svgDoc.documentElement.getBBox();
frameEl.width = bbox.width;
frameEl.height = bbox.height;
svgDoc.addEventListener("click", (evt) => {
console.log("clicked on", evt.target.outerHTML);
});
});
Once again as a JSFiddle.
Per OP's requirements -
Needs to be able to click on window/document and receive the alert message even when clicking on the HTML object tag.
We can do this by removing the object tag as a clickable element with CSS pointer-events: none;.
object {
pointer-events: none;
}
https://codepen.io/LTFoReal/pen/NWyerZg?editors=1111
This link has work around. Using a transparent div to cover object image, or directly use svg image instead.
I checked the specification of object element. It's for embeded external content usage. So it has ability to load a full document, your case is load as image. The available property to do event binding for this element is contentDocument or getSvgDocument(). Both are null under your case, as it's loaded as svg image.
document.getElementsByTagName("object")[0].contentDocument
Check this link for detail. Hope this helps you.
I attached an event listener to my SVG image in order to perform some code after the image has been loaded. As it sometimes happens, a bug might occur in my SVG generating code and the SVG file won't load. In that case, when user clicks another button, I want it to remove the event listener, hide the unsuccessful result and let the user select another SVG image.
Here's what I have:
// In external .js file, loaded prior to the other code in <head>
function setResultViewBox() {
var objectEl = document.getElementById("resultImage");
var svgDoc = objectEl.contentDocument;
var svg = svgDoc.childNodes[0];
// If there's no SVG tag, remove the listener etc.
// Tested via alert() and console messages that this actually works.
if (svg.tagName !== "svg") {
editBrush();
return;
}
// some other code to set the viewBox
}
// Attached to the main file at the end of <body>
var resultImage = document.getElementById("resultImage");
function resultImageLoaded(event) {
resultImage.removeEventListener("load", resultImageLoaded, false);
setResultViewBox();
hideProgressBar();
}
submitChanges() {
// Compute URI here
resultImage.data = uri;
resultImage.addEventListener("load", resultImageLoaded, false);
hidePreview();
}
function editBrush() {
alert();
resultImage.removeEventListener("load", resultImageLoaded, false);
hideResult();
hideProgressBar();
}
<object id="resultImage" type="image/svg+xml" width="420" height="420" data=""></object>
Make outline
Edit brush
This came to me as a surprise: for once, in Internet Explorer 11, it does exactly what I want it to do; on the other hand, in Opera it doesn't work (the hell must have frozen I guess).
Testing it on an image case I know for sure it won't load, it attempts to set the viewBox of the result image, fails to find the <svg> tag, throws an alert message as it goes to editBrush(), removes the listener and allows me to select another SVG file, which it loads correctly then. That means it creates the listener once again, loads the correct URI, recognizes <svg> tag, sets viewBox, removes the listener in the resultImageLoaded(event) itself and all is good.
In Opera, it attempts to set the viewBox of the result image, fails to find the <svg> tag, throws an alert message as it goes to editBrush() and I suspect now it doesn't actually remove the listener. When I select another SVG image, which it should load correctly now, nothing happens (tried to add another alert to resultImageLoaded(event) and it wasn't triggered).
Things I gave special attention to:
resultImageLoaded(event) isn't an anonymous function and is located above the code that is using it
reference to the function itself in the add/remove listeners
resultImage is stored in one variable and both add/remove listeners are on this one object
I can't see what I'm doing wrong, any help would be most appreciated.
EDIT: In console in Opera, it shows Internal server error (500) on GET request when I try to load the image that should fail loading. IE shows no such thing. Not sure if this can be of any help.
EDIT 2: Alright, I just found out this has probably nothing to do with removeEventListener(). Even when I comment out all lines where I remove event listeners, the behaviour is exactly the same as described in both browsers. Could the problem be in Opera reporting an error and IE ignoring it?
And question for mods: when I find out the original question's topic is no more relevant, but the problem still persists and I'm not even sure what might be causing it, what do I do? Brutally edit the original question or make a new one and leave the original one unanswered?
Try adding event.stopPropagation(); at the end of each eventListener, this will prevent bubbling of the event to your ancestors and it'll stop at your event.target
If that doesn't help, try event.stopImmediatePropagation();
http://www.kirupa.com/html5/handling_events_for_many_elements.htm
// In external .js file, loaded prior to the other code in <head>
function setResultViewBox() {
var objectEl = document.getElementById("resultImage");
var svgDoc = objectEl.contentDocument;
var svg = svgDoc.childNodes[0];
// If there's no SVG tag, remove the listener etc.
// Tested via alert() and console messages that this actually works.
if (svg.tagName !== "svg") {
editBrush();
return;
}
// some other code to set the viewBox
}
// Attached to the main file at the end of <body>
var resultImage = document.getElementById("resultImage");
function resultImageLoaded(event) {
resultImage.removeEventListener("load", resultImageLoaded, false);
setResultViewBox();
hideProgressBar();
event.stopPropagation();
}
submitChanges() {
// Compute URI here
resultImage.data = uri;
resultImage.addEventListener("load", resultImageLoaded, false);
hidePreview();
event.stopPropagation();
}
function editBrush() {
alert();
resultImage.removeEventListener("load", resultImageLoaded, false);
hideResult();
hideProgressBar();
event.stopPropagation();
}
<object id="resultImage" type="image/svg+xml" width="420" height="420" data=""></object>
Make outline
Edit brush
How can I initialize a variable in JavaScript with a direct HTML code?
I am trying to put an animate tag in a variable so that I can append to the svg whenever a mouseover event occurs. I am using snap.svg.
var g = HTML CODE
var s = Snap("#svg");
s.mouseover(function(){
s.append(g);
});
Something like that. I know this syntax is wrong. I didn't want to write this tag in my html code but keep it hidden and then append it
Probably the easiest way:
var someHTML = '<div>Heeeyy</div>',
someElem = document.getElementById('someElement');
someElem.onmouseover = function(){
someElem.insertAdjacentHTML('beforeend', someHTML );
someElem.onmouseover = null; // Remove this if you want it to happen on every mouseover event
}
Alternatively, you can create a new element with document.createElement('DIV') and set the innerHTML to the desired html. Then append the created element with appendChild on the parent (desired element).
animateTransform doesn't have good support on some browsers like IE, so I tend to stay away from using that method, if something like Snap is available. If it is, I would do something similar to the following...
s = Snap(400, 620);
var c = s.circle(10,10,10);
var myMarkup = '<g><rect x="20" y="20" width="100" height="100"></g>'
c.mouseover( function() {
s.append( Snap.parse( myMarkup ) )
s.select('g').animate({ transform: 't50,50' }, 3000)
})
jsfiddle (hover over circle)
If you were just doing the markup to add an animateTransform element, you can skip the parsing/appending stuff as well, as thats not needed.
I have a small problem with SVG in an embed tag. I update the source of an embed tag with an SVG file path with javascript. Then I have to update the viewbox attribute to resize correctly the SVG.
The problem is that the SVG tag is not available because the javascript execution is too fast.
An example :
//Creation and insertion by JQuery
var EmbedTag = $("<embed id='zoomSVG' src=idSVG + ".svg' type='image/svg+xml' width='500px' height='500px' />").appendTo(zoomGalleryHisto);
//This doesn't work : svgDoc is null
//SVG document recovery
var svgDoc = document.getElementById('zoomSVG').getSVGDocument();
This work :
setTimeout(function(){
//SVG document recovery
var svgDoc = document.getElementById('zoomSVG').getSVGDocument();
},100);
I would like to not use the setTimeout function because the timeout value depend on hardware. Sometimes 100 ms works fine but I have to find an universal solution.
After embed tag insertion, could I reload the DOM by javascript ? Is an existing event for embed tag when the load of the embedded object is done ?
Thanks for your help
Use the »onload« event of the tag to delay your function until it is loaded, than the should be available.
Call the code from the onload of the embed e.g.
var EmbedTag = $("<embed id='zoomSVG' onload='init()' src=idSVG + ".svg' type='image/svg+xml' width='500px' height='500px' />").appendTo(zoomGalleryHisto);
and then implement your code in init (or whatever you want to call it)
First, you create the element and then you trying to find it again in the DOM.
Second, javascript cant block until something happen, use callbacks insteed.
Something like that:
var svgDoc = false;
// Create an element
var EmbedTag = $("<embed id='zoomSVG' type='image/svg+xml' width='500px' height='500px' />");
// Append it to the dom
EmbedTag.appendTo(zoomGalleryHisto);
// Load the svg file
$.get('file.svg', function() {
// And then add it to the created element
EmbedTag.attr('src', 'file.svg');
svgDoc = EmbedTag.getSVGDocument();
});
I am creating an iframe dynamically for submmiting a form,after submitting i need to remove the iframe form the page.I removed itas follows but it is not removed,
function remove(){
var frame = document.getElementById("upload_iframe"),
var frameDoc = frame.contentDocument || frame.contentWindow.document;
frameDoc.removeChild(frameDoc.documentElement);
}
How to remove the ifarme form the form completely.
Thanks
Frame has 2 behaviors: frame as document element (like div or another DOM element) and frame as window element (like global window object). So if you want to remove iframe from DOM tree you have to work with iframe like with DOM element
function remove(){
var frame = document.getElementById("upload_iframe");
frame.parentNode.removeChild(frame);
}
A way I've been doing it (since I have a large amount of iframes) is using jQuery,
$('iframe').remove()
or in the case of only one iframe you can remove it using its ID, still with jQuery
$('#iframeID').remove()