Demonstrate how you can draw a path in SVG with animation. Move mouse over the text to see the effect. Based on technic described in Polygon feature design: SVG animations for fun and profit.
Created
April 12, 2014 20:39
-
-
Save vsapsai/10555726 to your computer and use it in GitHub Desktop.
SVG path animations with D3.js.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!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