Differences in using <iframe> and <embed> for displaying SVG and scripting - javascript

I'm trying to create Dynamic SVG graphics, it is my understanding that the only way to create dynamic SVG is to use a scripting language, so I have a few questions, basically I'd like to load or embed the SVG to a HTML web page and control the graphics using Inputs in the web page, rather than hardcoding the ECMAscript in the SVG file. I'm not entirely sure if I should use the embed tag or an iframe for displaying the SVG here are my doubts regarding SVG and scripting:
Whats the difference (in terms of scripting) in using an <iframe> or and <embed> tag for accessing the SVG elements?, maybe someone can include simple examples.
Can SVG evaluate math expressions in element attributes(just to be sure)?

Don't use either <iframe> or <embed>. Instead, embed your SVG directly in XHTML like so:
http://phrogz.net/svg/svg_in_xhtml5.xhtml
With that, you have full access to the SVG DOM as part of your document. As shown in that example, you simply need to be certain to create SVG elements (but not attributes) using the SVG namespace. You must also ensure that your web host is sending the content type for xhtml as application/xhtml+xml or text/xml, not text/html.
phrogz$ curl --silent -I http://phrogz.net/svg/svg_in_xhtml5.xhtml | grep "Type"
Content-Type: application/xhtml+xml
For more examples of JavaScript manipulating SVG mixed with HTML, see the various .xhtml files in that same directory. A particularly compelling example is this one, which dynamically creates hundreds of small SVG files as inline elements flowing like text.
And to your question:
Can SVG evaluate math expressions in element attributes(just to be sure)?
Not in general, no. However, the usage of SMIL Animation does allow you to specify various interpolation methods of properties over time.
Finally, note that you don't have to put SVG in HTML to make it dynamic. You can script SVG with JavaScript directly. For example, see this test file (press the green button to start simulation):
http://phrogz.net/svg/SpringzTest.svg

Whats the difference (in terms of scripting) in using an or and tag for accessing the SVG elements?, maybe someone can include simple examples.
<iframe>:
Scripts trying to access a frame's content are subject to the same-origin policy, and cannot access most of the properties in the other window object if it was loaded from a different domain. This also applies to a script inside a frame trying to access its parent window. Cross-domain communication can still be achieved with window.postMessage.
Source: https://developer.mozilla.org/en/HTML/Element/iframe#Scripting
We access iframe content by iframe_element.contentWindow method:
<html>
<body>
<iframe id="SVG_frame" src="image.svg"></iframe>
</body>
<script>
var SVG_frame = document.getElementById ( "SVG_frame" );
var SVG_content = null;
function getContent ()
{
SVG_content = SVG_frame.contentWindow;
SVG_content ? alert ( "YAY!" ) : alert ( "BOO!" );
}
SVG_frame.onload = getContent;
</script>
</html>
<embed>:
Example (view source): https://jwatt.org/svg/demos/scripting-across-embed.html
(both methods fail at least in Chromium)
<object>
Example (view source): https://jwatt.org/svg/demos/scripting-across-object.html
Can SVG evaluate math expressions in
element attributes(just to be sure)?
like <element attribute="48/2*(9+3)"/>?
I did't find a word about it in SVG spec.
EDIT
Personally, I recommend to use <object> + Data URI Scheme and/or object_element.contentDocument. I've tested both in Chromium and Firefox.
AHA! <object> has similar security behavior to <iframe>: domain, protocol must be same for site and SVG file.
EDIT2
If You are interested how to get markup vector graphics to work in Internet Explorer(s) without plug-in(s), then Vector Markup Language is the way.

Well, it depends on what you mean with dynamic. In most cases yes, you'll probably want scripts. There's no difference if you put your script in the HTML or the SVG file, both will be executed by the same engine.
You can create interactive/animated svg content with the declarative animation elements (aka SMIL). You can also do simple hover effects with CSS :hover rules, or transitions with CSS3 Transitions.
XSLT can also be used to make somewhat dynamic svg content, since it can transform your input to something else. It doesn't cover the interaction aspect though.
You can access the svg elements from the HTML file that includes it with either of:
theEmbeddingElement.contentDocument (preferred, but doesn't work on <embed>)
or alternatively theEmbeddingElement.getSVGDocument().

Related

How do I import a SVG file so that I can access its properties?

I have a large SVG and I need to access its 'path' to modify.
I pasted SVG directly in my app. but I want to split my code and make it more clear.
so I moved my SVG in an SVG file and I need to import the SVG file so that I can access its 'path'.
solutions that I found are using img tag. But this way I can't access 'path'.
The trick is to use the HTML "object" tag to embed the SVG.
<object type="image/svg+xml" data="src/beacon.svg" class="logo">
Beacon Logo <!-- fallback image in CSS -->
</object>
After you do so, you can target the "object" tag by using "querySelector" and then get access to the SVG document by using "getSVGDocument()" method. After that use regular Javascript to select the paths from the document and manipulate as you like. Pseudo code is as follows;
let svgDoc = document.querySelector("object.logo").getSVGDocument();
let svgPaths = svgDoc.querySelectorAll('path');
I use very large SVG files as well. My SVG is organized using separate groups (g) that are assigned a css attribute. Then, I can use Greensock (gsap) to animate. The tricky part is that SVGs are very sensitive. For path-based animations, they must be put in html (not linked to svg file).
So, to overcome that clutter you are describing. I started creating what I call "content blocks". You create a content block such as large-svg-file.html and then use a single line of "include" script for the intended page. This is ALSO handy if you wish to use this content block on different web pages.
Example: ##include('./blocks/large-svg-file.html')
Note: I usually put these files in a folder called "blocks" to separate them out from the primary html files.
I am not sure if you are using PHP, Grunt, Gulp (server-side include), or whatever; but, sadly there is no include code that is html only. So, you will need to pick your favorite solution. Here is a great tutorial that shows you how to apply the option of your choice: https://css-tricks.com/the-simplest-ways-to-handle-html-includes/
You can open it any browser & inspect the code and copy it. And put in a html file for modify.

Is there a way to make interactive standalone SVGs in a webpage?

Current libraries for making "interactive SVGs" in the web-browser are actually using javascript to manipulate a svg object in the page dynamically but don't actually embed the full javascript needed to animate the SVG in the svg tag itself. Libraries like d3.js, protovis, svg.js, etc.
But it's possible to create standalone interactive SVGs, for example Brendan Gregg's flamegraph tool, example:
http://www.brendangregg.com/FlameGraphs/cpu-bash-flamegraph.svg
Is there any way to create a standalone, interactive SVG in a webpage? Of course, you could generate the interactive SVG serverside (for example, Brendan uses a Perl library to generate the interactive SVG) and then serve that to the user. But I'd prefer to generate the SVG as part of generating the webpage itself, i.e. in Php or Ruby or, even better, client-side with a Javascript library. In either case, the key feature goal is to be able to right-click-download the custom-made interactive SVG.
Note: The benefit of the d3.js approach is that the animation can be integrated between the SVG and other DOM elements on the page, or have interaction with the SVG trigger dynamic AJAX requests. I'm not expecting the stand-alone SVG to be able to do these things.
As mentioned in the comments, You can inline an interactive SVG into the src= of an <embed> DOM element using a data: URI.
Unfortunately, current web browsers don't have right click -> download for <embed> elements, only for <img> tags. We can't use <img> because that tag won't run the javascript code inside the SVG for security reasons.
Luckily, we can hack in our own download link using javascript as follows:
<embed class="mygraph" src="data:image/svg+xml;utf8, ... svg code ...>
<a download class="downloadLink">Download this graph.</a>
<script>
document.querySelector(".downloadLink").href = document.querySelector(".mygraph").src;
</script>
If you try to use this technique to make standalone SVGs using popular libraries like d3.js you'll need to change a few things that are browser specific to work inside the SVG context. It took around 4 lines of code change to use d3.v5.js inside a standalone SVG without errors.
You can see an example of it here:
https://github.com/bjmnbraun/d3-standalone

How can I get angularJS dynamic content to display in an iframe?

I am generating some tabular content using ng-repeat in AngularJS, and I would like to have this content display in an iframe, so that the user can drag it and resize it.
I can't use the iframe src attribute, because that requires a URL and I am generating the content on the client.
I probably want some variant of srcdoc, but that seems to want a single quoted line of html code.
How can I construct my iframe such that the ng-repeat generated content is displayed within?
You can add an AngularJS table to an iframe. The support is limited to HTML5 but it looks something like this:
HTML
<iframe id="frame" sandbox="allow-same-origin allow-scripts" srcdoc="" seamless="true"></iframe>
Javascript
document.getElementById("frame").contentWindow.document.getElementById("mydiv")
The srcdoc property can be used instead of src to indicate you will be providing code for the contents. Seamless is also expected when you use srcdoc; it tells the browser that the iframe's contents are supposed to be treated as a part of the website, rather than a nested one. Unfortunately, this will trigger styling changes that eliminate the whole reason you wanted the iframe in the first place (the resize handles disappear). Furthermore, you'd have to inject css files and javascript files into the iframe - it's not worth it.
I'd recommend using something like jQuery UI resizable: https://jqueryui.com/resizable/
Here's a fiddle I was using to test out controlling iframe contents. It's very basic but accurately demonstrates how much trouble they actually are: Fiddle

Accessing SVG inside object with JS in Internet Explorer

I have a test page: http://benfrain.com/playground/svg-test/
On it I have inserted the same SVG a number of ways (img, object, inline, and background image)
I have also implemented the use method of re-using defs from within the SVG (only for the object insertion method and the 'inline' insertion method).
In the console you will see I am also attempting to access the SVG contents from each insertion method (I know img and background image should not be accessible via script - I'm just proving the point).
However, on any version of Internet Explorer (IE9+) the object insertion method fails to load the external CSS (as noted in the comments, IE requires the alternative linking mechanism) referenced from within (via xlink, you would see a 6px wide stroke if it was working) and it is not reachable via JavaScript (works in all the other evergreen browsers) (my mistake).
Can anyone clarify why? I've had a look through the spec: http://www.w3.org/TR/html5/embedded-content-0.html#the-object-element but I must confess some of the technicalities are beyond my comprehension.
Update:
Further to Robert's comments below I made some tweaks to the test page above.
Firstly, the object is accessible with script (rookie mistake). However, oddities still abound:
If the SVG has a link in this format: <?xml-stylesheet href="styles.css" type="text/css"?> then IE11 applies the styles within that stylesheet to the SVG whether it is inserted in the page via img, background-image, inline or object (Safari/Firefox/Chrome only apply the styles if the SVG is inserted inline or via object).
There is a w3c testsuite page for external <use>: http://www.w3.org/Graphics/SVG/Test/20110816/svg/struct-use-05-b.svg
The implementation matrix suggests that IE9 doesn't support external <use> I'm not sure why Firefox is listed as failing as I think even at that time it should have passed that particular test.
For the <object> issue, you need to run the script in the onload event of the <object> tag. I guess you just get lucky with the other UAs as you basically have a race condition.
Presumably IE doesn't support including stylesheets using html syntax. Try XML syntax instead: <?xml-stylesheet href="mystyle.css" type="text/css"?>
Allowing images to use external files is a privacy leak which is why Firefox, Chrome and Safari disallow it. If you converted the CSS to a data URL you could use a link element.

Iframe inside Iframe cant do changes

I have one iframe inside on iframe and with this code i want to change the src of an image
window.top.frames[0].frames[0].document.getElementById("maquina").src = "https://developer.cdn.mozilla.net/media/img/mdn-logo-sm.png";
and when i try it it work but i cant see changes in the page, only in code when e read .src
of that element
You cannot manipulate the contents of an iframe from within the parent frame without a global method for accessing the child DOM. There is an answer Here that suits your needs, but I will copy below for reference:
In the child iframe:
parent.childGetElementById = function (id) {return document.getElementById(id);}
parent.childLoaded();
In the parent:
function childLoaded() {var dom = childGetElementById('someid');}
Assuming you actually have access to the child page, I would recommend modifying your design away from the use of iframes.
[Answering the comment]
Well it depends on if you're just using straight HTML, or a scripting language (like PHP). If pure HTML, you can use a server side includes with
<!-- #include virtual="path/to/included/file.html" -->
In PHP, you can include the page like this
require('/real/path/to/included/file.php');
Don't get me wrong, iFrames can be useful in some specific situations (circumventing cross-domain origin policies, oAuth implementations, etc); they are more often abused than correctly used.

Categories