|
/* |
|
# SVG fragment builds for reveal.js |
|
|
|
## LIMITATIONS |
|
- won't work in Chrome against `file://` |
|
- workarounds: |
|
- dropbox |
|
- sharepoint |
|
- confluence |
|
- gist |
|
- `python -m SimpleHTTPServer` |
|
- probably won't work in IE |
|
- wontfix |
|
|
|
## Basic use case |
|
- build 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 `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](http://www.w3.org/TR/css3-selectors/) |
|
|
|
## 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: [ |
|
... |
|
{ |
|
src: 'plugin/svg-fragment/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> |
|
*/ |
|
;Reveal.SvgFragment = (function(Reveal){ |
|
"use strict"; |
|
var window = this, |
|
document = window.document, |
|
proto = window.location.protocol, |
|
local = proto === "file:", |
|
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(){ |
|
var d3 = window.d3, |
|
container = d3.selectAll("[data-svg-fragment]"); |
|
|
|
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: "about:blank", |
|
// 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){ |
|
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); |
|
d3.xml(item.url, "image/svg+xml", function(xml){ |
|
item.idoc.node().body.appendChild(xml.documentElement); |
|
item.svg = item.idoc.select("svg"); |
|
api.svged(item); |
|
}); |
|
|
|
return api; |
|
}; |
|
|
|
|
|
// the svg was loaded for this item |
|
api.svged = function(item){ |
|
item.iframe.attr({ |
|
width: item.svg.attr("width"), |
|
height: item.svg.attr("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 || {}; |
|
|
|
return window.api ? api() : api.load(api.cfg("d3"), 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); |
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)
The coloured fields are different layers.
but i get this in my presentation:
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