Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
RevealJS SVG fragment presenter

SVG fragment builds for reveal.js

Basic use case

  • make an SVG (maybe in inkscape)
    • save it someplace reveal.js can find it (maybe next to your presentation)
    • figure out how to identify them (maybe use named layers)
  • in reveal.js/index.html
    • add reveal-svg-fragment.js as a dependency
    • in a <section> of reveal.js markup
      • add data-svg-fragment="<url of the someplace>" to something, e.g. a div
      • add some things with class="fragment" inside that thing
        • add title="<a selector>" to those things
          • [*|label=<a label>] is good
          • for more about selectors, check out the W3C page

Example

Let's assume I made an SVG in Inkscape, and saved it next to my index.html. It has three layers: base, fragment1 and fragment2.

<html>
  ...
  <section>
    <div data-svg-fragment="figure.svg#[*|label=base]">
      <a class="fragment" href="[*|label=fragment1]"></a>
      <a class="fragment" href="[*|label=fragment2]"></a>
    </div>
  </section>
  ...
  <script>
    ...
    Reveal.initialize({
      dependencies: [
        ...
        {
          // maybe you put this in `plugins`
          src: 'reveal-svg-fragment.js',
          condition: function(){
            return !!document.querySelector( '[data-svg-fragment]' );
          }
          // Additional options
          // defaults to using already-loaded version, or CDN
          //d3: "./d3.min.js",
          // use a different attribute for your fragment selector
          //selector: "title",
        }
        ...
      ]
    ...
    }
    ...
  </script>
  ...
</html>

LIMITATIONS

  • won't work in Chrome against file://
    • workarounds:
      • dropbox
      • sharepoint
      • confluence
      • gist
      • python -m SimpleHTTPServer
  • probably won't work in IE
    • wontfix
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>reveal.js svg fragments</title>
<meta name="description" content="An SVG Plugin for reveal.js">
<meta name="author" content="Nicholas Bollweg">
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<link rel="stylesheet" href="//cdn.jsdelivr.net/reveal.js/latest/css/reveal.min.css">
<link rel="stylesheet" href="//cdn.jsdelivr.net/reveal.js/latest/css/theme/default.css" id="theme">
<!-- For syntax highlighting -->
<link rel="stylesheet" href="//cdn.jsdelivr.net/reveal.js/latest/lib/css/zenburn.css">
<!-- If the query includes 'print-pdf', include the PDF print sheet -->
<script>
if( window.location.search.match( /print-pdf/gi ) ) {
var link = document.createElement( 'link' );
link.rel = 'stylesheet';
link.type = 'text/css';
link.href = '//cdn.jsdelivr.net/reveal.js/latest/css/print/pdf.css';
document.getElementsByTagName( 'head' )[0].appendChild( link );
}
</script>
<style>
.column{ width: 50%; float:left;}
</style>
<!--[if lt IE 9]>
<script src="lib/js/html5shiv.js"></script>
<![endif]-->
</head>
<body>
<div class="reveal">
<!-- Any section element inside of this container is displayed as a slide -->
<div class="slides">
<section>
<h1>Reveal.js SVG Fragments</h1>
<h3>
<div class="column">
Built with <a href="http://d3js.org">d3</a>
<div data-svg-fragment="d3.svg"></div>
</div>
<div class="column">
Works with <a href="http://inkscape.org">Inkscape</a>
<div data-svg-fragment="inkscape.svg" href="http://inkscape.org"></div>
</div>
</h3>
<p>
<small>Created by <a href="http://github.com/bollwyvl">@bollwyvl</a></small>
</p>
</section>
<section>
<h1>Basic HTML Test</h1>
<div data-svg-fragment="test.svg#[*|label=base]">
<a class="fragment" title="[*|label=fragment1]"></a>
<a class="fragment" title="[*|label=fragment2]"></a>
</div>
</section>
<section data-markdown>
<script type="text/template">
# Using Markdown
<div data-svg-fragment="test.svg#[*|label=fragment1]">
<a class="fragment" title="[*|label=base]"></a>
<a class="fragment" title="[*|label=fragment2]"></a>
</div>
</script>
</section>
<section>
<h1>Questions / Feedback</h1>
<h3>
Comment/fork on
<a href="https://gist.github.com/bollwyvl/fe1d2806449487cdf88a">
GitHub
</a>
<div data-svg-fragment="github.svg"></div>
</h3>
</section>
</div>
</div>
<script src="//cdn.jsdelivr.net/reveal.js/latest/lib/js/head.min.js"></script>
<script src="//cdn.jsdelivr.net/reveal.js/latest/js/reveal.min.js"></script>
<script>
var cdn = "//cdn.jsdelivr.net/reveal.js/latest/";
// Full list of configuration options available here:
// https://github.com/hakimel/reveal.js#configuration
Reveal.initialize({
controls: true,
progress: true,
history: true,
center: true,
theme: Reveal.getQueryHash().theme, // available themes are in /css/theme
transition: Reveal.getQueryHash().transition || 'default', // default/cube/page/concave/zoom/linear/fade/none
// Parallax scrolling
// parallaxBackgroundImage: 'https://s3.amazonaws.com/hakim-static/reveal-js/reveal-parallax-1.jpg',
// parallaxBackgroundSize: '2100px 900px',
// Optional libraries used to extend on reveal.js
dependencies: [
{ src: cdn + 'lib/js/classList.js', condition: function() { return !document.body.classList; } },
{ src: cdn + 'plugin/markdown/marked.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } },
{ src: cdn + 'plugin/markdown/markdown.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } },
{ src: cdn + 'plugin/highlight/highlight.js', async: true, callback: function() { hljs.initHighlightingOnLoad(); } },
{ src: cdn + 'plugin/zoom-js/zoom.js', async: true, condition: function() { return !!document.body.classList; } },
{ src: cdn + 'plugin/notes/notes.js', async: true, condition: function() { return !!document.body.classList; } },
{ src: 'reveal-svg-fragment.js', condition: function() { return !!document.querySelector( '[data-svg-fragment]' ); } }
]
});
</script>
</body>
</html>
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
/*
Copyright (C) 2014 Nicholas Bollweg
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
;Reveal.SvgFragment = (function(Reveal){
"use strict";
var window = this,
document = window.document,
proto = window.location.protocol,
local = proto === "file:",
d3 = window.d3,
defaults = {
d3: (local ? "http:" : proto) + "//cdn.jsdelivr.net/d3js/latest/d3.min.js",
selector: "title"
};
// the main function, to be called when d3 is available
function api(){
d3 = d3 || window.d3;
var container = d3.selectAll("[data-svg-fragment]"),
slides = d3.select(".slides");
container.data(function(){
return container[0].map(function(d){
var $ = d3.select(d);
return {
container: $,
url: $.attr("data-svg-fragment")
};
});
});
container.append("iframe")
.attr({
src: function(item){ return item.url; },
// TODO: make this an option?
scrolling: "no"
})
.on("load", api.iframed);
Reveal.addEventListener("fragmentshown", api.listen(container, true));
Reveal.addEventListener("fragmenthidden", api.listen(container));
return api;
};
// generate listeners for reveal events
api.listen = function(container, show){
return function(event){
var fragment = d3.select(event.fragment);
container.filter(function(){
return this === event.fragment.parentNode;
}).each(function(item){
api.toggle(fragment, item, show);
});
return api;
};
};
// toggle a fragment
// TODO: add hide
api.toggle = function(fragment, item, show){
if(!item.svg){ return; }
var selector = fragment.attr(api.cfg("selector"));
item.svg.selectAll(selector)
.transition()
.style({opacity: show ? 1 : 0});
return api;
};
// the iframe was created for this item
api.iframed = function(item){
item.iframe = d3.select(this);
item.idoc = d3.select(this.contentDocument);
item.svg = item.idoc.select("svg");
item.dims = {
width: item.svg.attr("width") || 100,
height: item.svg.attr("height") || 100
};
item.iframe.attr(item.dims);
// see https://groups.google.com/forum/#!topic/d3-js/mTBxTLi0q1o
item.svg.attr({
width: "100%",
height: "100%",
viewBox: "0 0 "+ item.dims.width + " " + item.dims.height
});
return api.clean(item);
};
// prepare
// TODO: smarter initialization?
api.clean = function(item){
var base;
item.container.selectAll(".fragment").each(function(){
item.svg.selectAll(d3.select(this).attr(api.cfg("selector")))
.style({opacity: 0});
});
if(base = item.url.match(/(?:#)(.*)$/)){
item.svg.selectAll(base[1])
.style({opacity: 1});
}
return api;
};
// preflight, call immediately it d3 is available, otherwise load the script
api.init = function(){
var options = Reveal.getConfig().svgFragment || {};
if(window.d3){
api();
}else if(window.require){
require([api.cfg("d3")], function(_d3){
d3 = _d3;
api();
});
}else{
api.load(api.cfg("d3"), api);
}
return api;
};
// get configuration values (or defaults)
api.cfg = function(opt){
var cfg = Reveal.getConfig().svgFragment || {};
return cfg.hasOwnProperty(opt) ? cfg[opt] :
defaults.hasOwnProperty(opt) ? defaults[opt] :
function(){ throw new Error("Unknown property: "+ opt); };
};
// load a script, jacked from search, i think
api.load = function(url, callback){
var head = document.querySelector('head'),
script = document.createElement('script');
// Wrapper for callback to make sure it only fires once
var finish = function(){
if(typeof callback === 'function') {
callback.call();
callback = null;
}
};
// IE
script.onreadystatechange = function() {
if (this.readyState === 'loaded') {
finish();
}
};
script.type = 'text/javascript';
script.src = url;
script.onload = finish;
// Normal browsers
head.appendChild(script);
return api;
};
return api.init();
}).call(this, Reveal);
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
@ghost

This comment has been minimized.

Copy link

ghost commented Feb 5, 2016

Hi,
Noob here.
But I wanted to use the plugin as I would more or less need it, but I don't get it to work...

I downloaded the latest release of reveal.js form the github.

I downloaded your plugin under /plugin.

I added a line to my dependencies:
// Optional reveal.js plugins
dependencies: [
{ src: 'lib/js/classList.js', condition: function() { return !document.body.classList; } },
{ src: 'plugin/markdown/marked.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } },
{ src: 'plugin/markdown/markdown.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } },
{ src: 'plugin/highlight/highlight.js', async: true, callback: function() { hljs.initHighlightingOnLoad(); } },
{ src: 'plugin/zoom-js/zoom.js', async: true },
{ src: 'plugin/notes/notes.js', async: true },
{ src: 'plugin/reveal-svg-fragment.js', condition: function() { return !!document.querySelector( '[data-svg-fragment]' ); } }
]

I added this to insert the figure:

( made in inkscape)

proper svg

The coloured fields are different layers.

but i get this in my presentation:

result

Someting or the other has to do with the viewbox but I don't know how to implement/correct that...
As that is my hunch, I've added the top of the svg.
Any help?



<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.35"
inkscape:cx="187.88978"
inkscape:cy="303.82656"
inkscape:document-units="px"
inkscape:current-layer="layer4"
showgrid="false"
fit-margin-top="10"
fit-margin-right="10"
fit-margin-bottom="10"
fit-margin-left="10"
inkscape:window-width="1651"
inkscape:window-height="1032"
inkscape:window-x="1949"
inkscape:window-y="18"
inkscape:window-maximized="1" />

rdf:RDF
<cc:Work
rdf:about="">
dc:formatimage/svg+xml/dc:format
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
dc:title/dc:title
/cc:Work
/rdf:RDF

@zouter

This comment has been minimized.

Copy link

zouter commented Feb 16, 2016

This is fixed for me if I go to document properties (in inkscape) and select as units "px".

@ghost

This comment has been minimized.

Copy link

ghost commented Feb 25, 2016

image

still nothing :-(

@ghost

This comment has been minimized.

Copy link

ghost commented Feb 28, 2016

just today, i saw that everything works fine in mozilla firefox, but it doesn't in chrome... Maybe that can heblp to debug?

ubuntu 15.10
firefox44.02
chrome 48.0.2564.116

@csachs

This comment has been minimized.

Copy link

csachs commented Feb 13, 2017

The link to the CDN hosted D3 file now leads to incompatible 4.xx … one can change it e.g. to https://cdn.jsdelivr.net/d3js/3.5.17/d3.min.js to fix it.
Could this gist probably become a github repository and be packaged?

@mvala

This comment has been minimized.

Copy link

mvala commented Sep 28, 2017

+1

@ebousse

This comment has been minimized.

Copy link

ebousse commented Feb 6, 2018

+1

@kris71

This comment has been minimized.

Copy link

kris71 commented May 15, 2018

It seems that the fade-out fragment type is not working. It behaves like the fade-in type.
Does anyone know how to fix that?

@aaronjg

This comment has been minimized.

Copy link

aaronjg commented Nov 2, 2018

I am getting an error trying to run the demo:

TypeError: container[0] is undefined[Learn More] reveal-svg-fragment.js:42:7

Firefox 62.0.3 (64-bit)

Any idea what is going on?

@deisi

This comment has been minimized.

Copy link

deisi commented Nov 5, 2018

@aaronjg I see the same. Was just about to post a question.

I opened an issue in the github repo here

@deisi

This comment has been minimized.

Copy link

deisi commented Nov 5, 2018

Okay, don't use this gist version. In the repo the bug is fixed.

@alanafoleykeane

This comment has been minimized.

Copy link

alanafoleykeane commented Apr 5, 2019

Hi,

Are you able to advise how I can set me CSS animation to start when the slide is .present rather than it loading animations beforehand.

I have inserted my animations like this: <img data-src="pres-assets/svg/clip.svg"/> ---> with my CSS animations embedded inline the SVG

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.