Skip to content

Instantly share code, notes, and snippets.

@thekalinga
Forked from bollwyvl/README.md
Created May 20, 2018 23:40
Show Gist options
  • Save thekalinga/1efd42374b75062fbf592a804da49619 to your computer and use it in GitHub Desktop.
Save thekalinga/1efd42374b75062fbf592a804da49619 to your computer and use it in GitHub Desktop.
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
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
<svg xmlns="http://www.w3.org/2000/svg" viewBox="-0.2 -1 379 334" width="379" height="334">
<path id="puddle" fill="#9CDAF1" d="m296.94 295.43c0 20.533-47.56 37.176-106.22 37.176-58.67 0-106.23-16.643-106.23-37.176s47.558-37.18 106.23-37.18c58.66 0 106.22 16.65 106.22 37.18z"/>
<g id="shadow-legs" fill="#7DBBE6">
<path d="m161.85 331.22v-26.5c0-3.422-.619-6.284-1.653-8.701 6.853 5.322 7.316 18.695 7.316 18.695v17.004c6.166.481 12.534.773 19.053.861l-.172-16.92c-.944-23.13-20.769-25.961-20.769-25.961-7.245-1.645-7.137 1.991-6.409 4.34-7.108-12.122-26.158-10.556-26.158-10.556-6.611 2.357-.475 6.607-.475 6.607 10.387 3.775 11.33 15.105 11.33 15.105v23.622c5.72.98 11.71 1.79 17.94 2.4z"/>
<path d="m245.4 283.48s-19.053-1.566-26.16 10.559c.728-2.35.839-5.989-6.408-4.343 0 0-19.824 2.832-20.768 25.961l-.174 16.946c6.509-.025 12.876-.254 19.054-.671v-17.219s.465-13.373 7.316-18.695c-1.034 2.417-1.653 5.278-1.653 8.701v26.775c6.214-.544 12.211-1.279 17.937-2.188v-24.113s.944-11.33 11.33-15.105c0-.01 6.13-4.26-.48-6.62z"/>
</g>
<path id="cat" d="m378.18 141.32l.28-1.389c-31.162-6.231-63.141-6.294-82.487-5.49 3.178-11.451 4.134-24.627 4.134-39.32 0-21.073-7.917-37.931-20.77-50.759 2.246-7.25 5.246-23.351-2.996-43.963 0 0-14.541-4.617-47.431 17.396-12.884-3.22-26.596-4.81-40.328-4.81-15.109 0-30.376 1.924-44.615 5.83-33.94-23.154-48.923-18.411-48.923-18.411-9.78 24.457-3.733 42.566-1.896 47.063-11.495 12.406-18.513 28.243-18.513 47.659 0 14.658 1.669 27.808 5.745 39.237-19.511-.71-50.323-.437-80.373 5.572l.276 1.389c30.231-6.046 61.237-6.256 80.629-5.522.898 2.366 1.899 4.661 3.021 6.879-19.177.618-51.922 3.062-83.303 11.915l.387 1.36c31.629-8.918 64.658-11.301 83.649-11.882 11.458 21.358 34.048 35.152 74.236 39.484-5.704 3.833-11.523 10.349-13.881 21.374-7.773 3.718-32.379 12.793-47.142-12.599 0 0-8.264-15.109-24.082-16.292 0 0-15.344-.235-1.059 9.562 0 0 10.267 4.838 17.351 23.019 0 0 9.241 31.01 53.835 21.061v32.032s-.943 11.33-11.33 15.105c0 0-6.137 4.249.475 6.606 0 0 28.792 2.361 28.792-21.238v-34.929s-1.142-13.852 5.663-18.667v57.371s-.47 13.688-7.551 18.881c0 0-4.723 8.494 5.663 6.137 0 0 19.824-2.832 20.769-25.961l.449-58.06h4.765l.453 58.06c.943 23.129 20.768 25.961 20.768 25.961 10.383 2.357 5.663-6.137 5.663-6.137-7.08-5.193-7.551-18.881-7.551-18.881v-56.876c6.801 5.296 5.663 18.171 5.663 18.171v34.929c0 23.6 28.793 21.238 28.793 21.238 6.606-2.357.474-6.606.474-6.606-10.386-3.775-11.33-15.105-11.33-15.105v-45.786c0-17.854-7.518-27.309-14.87-32.3 42.859-4.25 63.426-18.089 72.903-39.591 18.773.516 52.557 2.803 84.873 11.919l.384-1.36c-32.131-9.063-65.692-11.408-84.655-11.96.898-2.172 1.682-4.431 2.378-6.755 19.25-.80 51.38-.79 82.66 5.46z"/>
<path id="face" fill="#F4CBB2" d="m258.19 94.132c9.231 8.363 14.631 18.462 14.631 29.343 0 50.804-37.872 52.181-84.585 52.181-46.721 0-84.589-7.035-84.589-52.181 0-10.809 5.324-20.845 14.441-29.174 15.208-13.881 40.946-6.531 70.147-6.531 29.07-.004 54.72-7.429 69.95 6.357z"/>
<path id="eyes" fill="#FFF" d="m160.1 126.06 c0 13.994-7.88 25.336-17.6 25.336-9.72 0-17.6-11.342-17.6-25.336 0-13.992 7.88-25.33 17.6-25.33 9.72.01 17.6 11.34 17.6 25.33z m94.43 0 c0 13.994-7.88 25.336-17.6 25.336-9.72 0-17.6-11.342-17.6-25.336 0-13.992 7.88-25.33 17.6-25.33 9.72.01 17.6 11.34 17.6 25.33z"/>
<g fill="#AD5C51">
<path id="pupils" d="m154.46 126.38 c0 9.328-5.26 16.887-11.734 16.887s-11.733-7.559-11.733-16.887c0-9.331 5.255-16.894 11.733-16.894 6.47 0 11.73 7.56 11.73 16.89z m94.42 0 c0 9.328-5.26 16.887-11.734 16.887s-11.733-7.559-11.733-16.887c0-9.331 5.255-16.894 11.733-16.894 6.47 0 11.73 7.56 11.73 16.89z"/>
<circle id="nose" cx="188.5" cy="148.56" r="4.401"/>
<path id="mouth" d="m178.23 159.69c-.26-.738.128-1.545.861-1.805.737-.26 1.546.128 1.805.861 1.134 3.198 4.167 5.346 7.551 5.346s6.417-2.147 7.551-5.346c.26-.738 1.067-1.121 1.805-.861s1.121 1.067.862 1.805c-1.529 4.324-5.639 7.229-10.218 7.229s-8.68-2.89-10.21-7.22z"/>
</g>
<path id="octo" fill="#C3E4D8" d="m80.641 179.82 c0 1.174-1.376 2.122-3.07 2.122-1.693 0-3.07-.948-3.07-2.122 0-1.175 1.377-2.127 3.07-2.127 1.694 0 3.07.95 3.07 2.13z m8.5 4.72 c0 1.174-1.376 2.122-3.07 2.122-1.693 0-3.07-.948-3.07-2.122 0-1.175 1.377-2.127 3.07-2.127 1.694 0 3.07.95 3.07 2.13z m5.193 6.14 c0 1.174-1.376 2.122-3.07 2.122-1.693 0-3.07-.948-3.07-2.122 0-1.175 1.377-2.127 3.07-2.127 1.694 0 3.07.95 3.07 2.13z m4.72 7.08 c0 1.174-1.376 2.122-3.07 2.122-1.693 0-3.07-.948-3.07-2.122 0-1.175 1.377-2.127 3.07-2.127 1.694 0 3.07.95 3.07 2.13z m5.188 6.61 c0 1.174-1.376 2.122-3.07 2.122-1.693 0-3.07-.948-3.07-2.122 0-1.175 1.377-2.127 3.07-2.127 1.694 0 3.07.95 3.07 2.13z m7.09 5.66 c0 1.174-1.376 2.122-3.07 2.122-1.693 0-3.07-.948-3.07-2.122 0-1.175 1.377-2.127 3.07-2.127 1.694 0 3.07.95 3.07 2.13z m9.91 3.78 c0 1.174-1.376 2.122-3.07 2.122-1.693 0-3.07-.948-3.07-2.122 0-1.175 1.377-2.127 3.07-2.127 1.694 0 3.07.95 3.07 2.13z m9.87 0 c0 1.174-1.376 2.122-3.07 2.122-1.693 0-3.07-.948-3.07-2.122 0-1.175 1.377-2.127 3.07-2.127 1.694 0 3.07.95 3.07 2.13z m10.01 -1.64 c0 1.174-1.376 2.122-3.07 2.122-1.693 0-3.07-.948-3.07-2.122 0-1.175 1.377-2.127 3.07-2.127 1.694 0 3.07.95 3.07 2.13z"/>
<path id="drop" fill="#9CDAF1" d="m69.369 186.12l-3.066 10.683s-.8 3.861 2.84 4.546c3.8-.074 3.486-3.627 3.223-4.781z"/>
</svg>
<!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>
Display the source blob
Display the rendered blob
Raw
Loading
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);
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment