Skip to content

Instantly share code, notes, and snippets.

@ZJONSSON
Last active May 27, 2022 17:14
Show Gist options
  • Save ZJONSSON/1254855 to your computer and use it in GitHub Desktop.
Save ZJONSSON/1254855 to your computer and use it in GitHub Desktop.
Simple transitioning slides with SVG and D3
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.min.js"></script>
<script src="svg_slides.js"></script>
<script src="svg_interact.js"></script>
</head>
<body>
<script>
// There are probably better ways of loading the SVG, but this is one example I found
d3.xml("test.svg", "image/svg+xml", function(xml) {
d3.select("body").node().appendChild(xml.documentElement);
svg=d3.select("body").select("svg");
console.log(svg[0][0])
slides = svg_slides(svg,1500);
setTimeout(function() { svg_interact(svg);console.log("OK")},100);
// Lets test the slide scales - put a bouncing ball on slide id 3
s = slides[3];
circle = svg.append("svg:circle")
.attr("cx",s.scale_x(500)).attr("cy",s.scale_y(500))
.attr("r",20)
.style("fill","steelblue");
next = 500;
function bounce() {
next = -next;
circle.transition().duration(2500).attr("cx",s.scale_x(500+next))
.each("end",bounce);
}
bounce();
});
</script>
</body>
</html>
function svg_interact(svg,p) {
var p = p ? p : {},
zoom_speed = p.zoom_speed ? p.zoom_speed : 1.15,
viewBox = svg[0][0].viewBox.baseVal;
panning = null,
current_mouse = null;
/* Panning moves the viewbox */
function mousemove(){
current_mouse = d3.svg.mouse(this);
if (panning) {
viewBox.x +=(panning[0] -current_mouse[0]);
viewBox.y += (panning[1] - current_mouse[1]);
}
};
svg.on("mousemove",mousemove)
svg.on("mousedown", function() { panning = d3.svg.mouse(this)});
d3.select(window).on("mouseup",function () { panning = null;})
svg[0][0].ondragstart = function() { return false } // Firefox fix
/* Zoom with mousewheel - keeping mouse position in same location*/
function wheel(event) {
var delta = 0;
if (!event) event = window.event;
if (event.wheelDelta) {
delta = event.wheelDelta/120;
} else if (event.detail) {
delta = -event.detail/3;
}
move = (delta<0) ? -delta * zoom_speed : 1/(delta*zoom_speed);
viewBox.x=(current_mouse[0]-(current_mouse[0]-viewBox.x)*move);
viewBox.y=(current_mouse[1]-(current_mouse[1]-viewBox.y)*move);
viewBox.height = viewBox.height * move;
viewBox.width = viewBox.width * move;
};
svg[0][0].addEventListener('DOMMouseScroll', wheel, false);
svg[0][0].onmousewheel = wheel;
document.onmousewheel = function () { return null};
return svg;
}
/* This is a basic attempt to use d3 to process transitional slides from SVG files (i.e. Inkscape)
The main objective here was to keep everything as simple as possible
To create a slide, simply create a rectangle in inkscape where you set the object ID to "slide_" + a number
This number can be either integer or float, so "slide_1","slide_2" and "slide_3.56" all work.
The script sorts the slide-numbers and transitions between slides based on the final sorted order.
It is easy to add slides into a pre-existing ordering, simply by chosing a floating number in the middle of the two
Example: If we want to add slide between "slide_2" and "slide_3" we simply add a rectancle called "slide_2.5"
Keyboard definitions:
Right arrow: next slide
Left arrow: previous slide
Home: first slide
End: last slide
Please be aware that you need to remove any layer transition is the svg file (or put the layer transition to 0,0)
Each slide has a scale_x and scale_y functions that have pre-set range to the slide boundaries and a default
domain of [0,1000], allowing the user to position objects easily onto each slide.
ziggy.jonsson.nyc@gmail.com
*/
function svg_slides(svg,delay) {
var slides={},
slide = 0,
delay = delay ? delay : 3500;
svg.attr("preserveAspectRatio","xMidYid meet");
rects = svg.selectAll("rect")[0];
for (i=0;i<rects.length;i++) {
id = rects[i].id;
console.log(id);
if (id.slice(0,6)=='slide_') {
slides[id.slice(6)]=rects[i]
rects[i].scale_x = d3.scale.linear().range([rects[i].x.baseVal.value,rects[i].x.baseVal.value+rects[i].width.baseVal.value]).domain([0,1000]);
rects[i].scale_y = d3.scale.linear().range([rects[i].y.baseVal.value,rects[i].y.baseVal.value+rects[i].height.baseVal.value]).domain([0,1000]);
}
}
keys = Object.keys(slides).sort();
slides.keys = keys;
function next_slide() {
svg.transition().duration(delay).attr("viewBox",slides[keys[slide]].x.baseVal.value+" "+slides[keys[slide]].y.baseVal.value+" "+slides[keys[slide]].width.baseVal.value+" "+slides[keys[slide]].height.baseVal.value);
}
d3.select("body").on("touchmove", function() { if(slide<keys.length-1) {slide++; console.log(slide);}});
d3.select(window).on("keydown", function() {
switch (d3.event.keyCode) {
case 37: {if (slide>0) {slide=slide-1; console.log(slide);next_slide()};break}
case 39: {if(slide<keys.length-1) {slide++; console.log(slide);next_slide()};break}
case 36: {slide = 0;next_slide();break}
case 35: {slide = keys.length -1; next_slide();break}
}
});
// Start with the first slide
next_slide();
return slides
}
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.
@winniehell
Copy link

I love what you did there! 💖 This is just awesome! Thank you for sharing... 👍

@CrashLaker
Copy link

well... i'm just 10 years late.. awesome indeed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment