Adding SVG to your tool belt

Lennart Schoors - #fronteersbe meetup 24/04/2014

http://lensco.be/talks/svg

hello, i'm @lensco

freelance interface designer & front-end developer

not in this talk

  • a general overview or history of SVG
  • extensive fallback techniques
  • SVG icons
  • funny memes

so what’s in?

  • 3 real world use cases of SVG enhancing a design
  • no libraries or dependencies (jQuery optional)
  • plenty of code

1. Super Simple Pie Charts

http://jsfiddle.net/lensco/ScURE/

HTML


JS - basic setup


$.fn.easyaspie = function () {
	// get values from attributes & clean 'em up
	...

	// set the size of this element
	this.css({
		height: size,
		width: size
	});

	// do SVG magic
	...
};

$('.pie').easyaspie();
					

JS - adding SVG to the DOM


// make me some svg
this.pie = document.createElementNS("http://www.w3.org/2000/svg", "svg");

// make the slice
this.pie.slice = ...

// add the slice to the pie
$(this.pie.slice).appendTo(this.pie);

// add the pie to this
$(this.pie).appendTo(this);
					

JS - making the slice


if (value >= 100) {
	// if value is 100 or higher, just use a circle
	this.pie.slice = document.createElementNS("http://www.w3.org/2000/svg", "circle");
	this.pie.slice.setAttribute('r', radius);
	this.pie.slice.setAttribute('cx', radius);
	this.pie.slice.setAttribute('cy', radius);

} else {
	...
}
					

JS - making the slice (2)


this.pie.slice = document.createElementNS("http://www.w3.org/2000/svg", "path");

// calculate x,y coordinates of the point on the circle to draw the arc to
var x = Math.cos((2 * Math.PI)/(100/value));
var y = Math.sin((2 * Math.PI)/(100/value));

// should the arc go the long way round?
var longArc = (value <= 50) ? 0 : 1;

// d is a string that describes the path of the slice
var d = "M" + radius + "," + radius + " L" + radius + "," + 0 + ", A" + radius + "," + radius + " 0 " + longArc + ",1 " + (radius + y*radius) + "," + (radius - x*radius) + " z";

this.pie.slice.setAttribute('d', d);
					

Q: But Lennart, how do you know these complex formulas?

A: I don't. The internet knows.

The internet – it knows things™

CSS - icing on the cake


.pie {
    display: inline-block;
    vertical-align: middle;
    margin: 1em;
    background: #eee;
    border-radius: 100%;
    fill: #1b75bb;
}					

job's done, let's go home

http://jsfiddle.net/lensco/ScURE/

2. Animated Line Through Specific Points

http://codepen.io/lensco/pen/FmIHf

HTML


1
chapter 1
2
chapter 2
...

a word on SVG curves

http://codepen.io/yoksel/full/cruht

The idea

  1. define a starting point
  2. find all chapter numbers
  3. get their offset value
  4. calculate coordinates for the curve to the next chapter
  5. add svg path to DOM
  6. animate the path

example path coordinates



					

a word on line animation

Jake Archibald's article

Lazy Line Painter jQuery plugin

JS (coffeescript) - animating the path


# animate the line
pathLength = path.line.getTotalLength()
path.line.style.strokeDasharray = pathLength
path.line.style.strokeDashoffset = pathLength
path.line.style.transition = path.line.style.WebkitTransition = "stroke-dashoffset " + (length * .5) + "s linear"
path.line.getBoundingClientRect()
path.line.style.strokeDashoffset = 0
					

Q: But Lennart, how do you animate a dashed line?

A: Animate a full line, and use a dashed mask!

JS (coffeescript) - adding a mask


# add a mask for a dashed line
path.mask = document.createElementNS("http://www.w3.org/2000/svg", "mask")
path.maskPath = document.createElementNS("http://www.w3.org/2000/svg", "path")
path.maskPath.setAttribute "d", coordinates
path.maskPath.setAttribute "class", "mask-path"
path.mask.setAttribute "id", "mask"
path.line.setAttribute "mask", "url(#mask)"
path.mask.appendChild path.maskPath
path.appendChild path.mask
					

CSS


path {
	fill: none;
	}

.line {
	stroke-width: 1;
	stroke: #1b75bb;
	}

.mask-path {
	stroke-dasharray: 4;
	stroke-width: 4;
	stroke: #fff;
	}
					

boom, headshot!

http://codepen.io/lensco/pen/FmIHf

3. Animated Marker Highlight

http://jsfiddle.net/lensco/d2EMf/

The idea

  1. on load or resize:
  2. find all bounding rectangles behind highlighted text
  3. create absolutely positioned elements behind those rectangles
  4. add svg path to each
  5. animate the path

HTML


Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. This text might span multiple lines and will be highlighted, yay. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

JS - basic setup


var $highlightText = $('.highlighted')[0],
	$container = $('#container');

// debounced resize from https://github.com/louisremi/jquery-smartresize
function on_resize(c,t){onresize=function(){clearTimeout(t);t=setTimeout(c,100)};return c};

on_resize(function() {
	...
})();
					

JS - find bounding rectangles


rects = $highlightText.getClientRects();

// remove previous instance
$(".highlight").detach();

// loop over every bounding rectangle
for (var i = 0; i != rects.length; i++) {
	...
}
					

make pretty marker SVG in graphics app

open in text editor and copy d attribute of the path

JS - insert pretty marker SVG


var rect = rects[i],
    marker = document.createElementNS("http://www.w3.org/2000/svg", "svg"),
    scale = Math.round((rect.width / 160) * 100) / 100;

marker.path = document.createElementNS("http://www.w3.org/2000/svg", "path");
marker.path.setAttribute('d', "M1.4,17 c1,0.1,16.7-1.9,18.9-2.1C33.5,14.1,66.2,12.7,87,12c24.3-0.8,69.3,1,78,2");

// stretch marker to fit + offset a little
marker.path.setAttribute('transform', "scale(" + scale + ", 1) translate(0,3)");
marker.appendChild(marker.path);
					

JS - add positioned element and append SVG


$('
') .addClass("highlight") .css({ "top": (rect.top - 7) + "px", "left": (rect.left - 4) + "px", "width": (rect.width + 20) + "px", "height": (rect.height + 18) + "px" }) .appendTo($container); $(".highlight").each(function() { this.appendChild(marker); });

CSS


.highlight {
    position: absolute;
    z-index: -1;
}

.highlight path {
    stroke: rgba(246,227,52,0.5);
    stroke-width: 30;
    fill: none;
}
					

JS - animate it


pathLength = marker.path.getTotalLength();
marker.path.style.strokeDasharray = pathLength;
marker.path.style.strokeDashoffset = pathLength;

// add more delay for every new highlighted line
marker.path.style.transition = marker.path.style.WebkitTransition = "stroke-dashoffset 1s " + (i + .5) + "s ease";

marker.path.getBoundingClientRect();
marker.path.style.strokeDashoffset = 0;
					

there, i fixed it

http://jsfiddle.net/lensco/d2EMf/

Takeaways, Yummie!

so, what did we learn?

  • adding SVG to the DOM
  • adding shapes to it
  • styling the SVG with CSS
  • animate lines with dash-offset & dash-array
  • masking parts of the SVG
  • manipulating the SVG with transforms

That's all folks!

Lennart Schoors - lensco.be - @lensco