Skip to content

Instantly share code, notes, and snippets.

@vsapsai
Created April 12, 2014 20:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save vsapsai/10555726 to your computer and use it in GitHub Desktop.
Save vsapsai/10555726 to your computer and use it in GitHub Desktop.
SVG path animations with D3.js.
<!DOCTYPE html>
<meta charset="utf-8">
<style>
svg path {
fill: none;
stroke: steelblue;
stroke-width: 1.5px;
}
svg text {
font-size: 20px;
font-family: sans-serif;
}
</style>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
var matchData = {"one": 1, "two": 2, "three": 3, "four": 4, "five": 5};
var mixedData = shuffleMatchData(matchData);
var width = 960,
height = 500;
var verticalLineTextAdjustment = 5,
lineAreaStart = 50,
rightColumnStart = 250,
rightColumnPadding = 5;
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
var line = d3.svg.line();
var textScale = d3.scale.ordinal()
.domain(d3.range(mixedData.length))
.rangeRoundBands([10, 150], 0.05);
var lineLength = function(mixedDataItem) {
return (rightColumnStart - rightColumnPadding - lineAreaStart) +
Math.abs(textScale(mixedDataItem.lhsIndex) - textScale(mixedDataItem.rhsIndex));
};
var groups = svg.selectAll("g")
.data(mixedData)
.enter().append("g");
// Left column text.
groups.append("text")
.attr("y", function(d) { return textScale(d.lhsIndex) + verticalLineTextAdjustment; })
.text(function(d) { return d.lhsValue; })
.on("mouseover", function(d) { drawLineWithAnimation(d, lineLength(d), /* isFromLeftToRight */true); });
// Right column text.
groups.append("text")
.attr("x", rightColumnStart)
.attr("y", function(d) { return textScale(d.rhsIndex) + verticalLineTextAdjustment; })
.text(function(d) { return d.rhsValue; })
.on("mouseover", function(d) { drawLineWithAnimation(d, lineLength(d), /* isFromLeftToRight */false); });
// Lines.
var lineAreaMiddle = (lineAreaStart + rightColumnStart - rightColumnPadding) / 2;
groups.append("path")
.attr("id", function(d) { return d.lhsValue; })
.attr("d", function(d) {
var lineCoordinates = [
[lineAreaStart, textScale(d.lhsIndex)],
[lineAreaMiddle, textScale(d.lhsIndex)],
[lineAreaMiddle, textScale(d.rhsIndex)],
[rightColumnStart - rightColumnPadding, textScale(d.rhsIndex)],
];
return line(lineCoordinates);
})
.style("stroke-dasharray", function(d) {
var length = lineLength(d);
return length + " " + length;
})
.style("stroke-dashoffset", function(d) { return lineLength(d); });
function shuffleMatchData(matchData) {
var keys = Object.keys(matchData);
var keysPositions = d3.shuffle(d3.range(keys.length));
var valuesPositions = d3.shuffle(d3.range(keys.length));
var mixedData = Object.keys(matchData).map(function(key, i) {
return {
"lhsValue": key,
"rhsValue": matchData[key],
"lhsIndex": keysPositions[i],
"rhsIndex": valuesPositions[i]
};
});
return mixedData;
}
function drawLineWithAnimation(lineDatum, lineLength, isFromLeftToRight) {
var visibleLine = d3.select(".visible-line");
var visibleLineId = null;
if (!visibleLine.empty()) {
visibleLineId = visibleLine.attr("id");
}
if (visibleLineId !== lineDatum.lhsValue) {
if (!visibleLine.empty()) {
var visibleLineLength = substringTillCharacter(visibleLine.style("stroke-dasharray"), ",");
visibleLine.interrupt()
.classed("visible-line", false)
.style("stroke-dashoffset", visibleLineLength);
}
d3.select("#" + lineDatum.lhsValue)
.classed("visible-line", true)
.transition()
.duration(1000)
.style("stroke-dashoffset", isFromLeftToRight ? 0 : 2 * lineLength);
}
}
function substringTillCharacter(string, searchValue) {
var index = string.indexOf(searchValue);
if (index == -1) {
return "";
}
return string.substring(0, index);
}
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment