outputarea.js: Wrap inline SVGs inside an iframe

When multiple inline SVGs are included in a single document,
they share the same parse tree. Therefore, style collisions and
use id collisions can occur and upset the rendering.

This patch wraps each SVG inside an individual iframe, ensuring
that SVG's declarations do not collide.

(The SVG representation is kept as XML and not converted to a binary
format, so I do not think this approach precludes the use of d3.js)

Tested on:
* Chrome Version 29.0.1547.57 Debian 7.1 (217859)
* Mozilla/5.0 (X11; Linux x86_64; rv:17.0) Gecko/20130806 Firefox/17.0 Iceweasel/17.0.8

Closes #1866
This commit is contained in:
Pablo de Oliveira 2013-09-22 12:53:05 +02:00
parent 0f25ac58b3
commit f152996f11

View File

@ -494,9 +494,36 @@ var IPython = (function (IPython) {
OutputArea.prototype.append_svg = function (svg, md, element) {
var toinsert = $("<div/>").addClass("output_subarea output_svg");
toinsert.append(svg);
element.append(toinsert);
// To avoid style or use collisions between multiple svg figures,
// svg figures are wrapped inside an iframe.
var iframe = $('<iframe/>')
iframe.attr('frameborder', 0);
iframe.attr('scrolling', 'no');
var wrapper = $("<div/>").addClass("output_subarea output_svg");
wrapper.append(svg);
// Once the iframe is loaded, the svg is dynamically inserted
iframe.on('load', function() {
// Set the iframe height and width to fit the svg
// (the +10 pixel offset handles the default body margins
// in Chrome)
var svg = wrapper.children()[0];
iframe.width(svg.width.baseVal.value + 10);
iframe.height(svg.height.baseVal.value + 10);
// Workaround needed by Firefox, to properly render svg inside iframes,
// see http://stackoverflow.com/questions/10177190/svg-dynamically-added-to-iframe-does-not-render-correctly
iframe.contents()[0].open();
iframe.contents()[0].close();
// Insert the svg inside the iframe
var body = iframe.contents().find('body');
body.html(wrapper.html());
});
element.append(iframe);
};