JSFiddle - React, Tailwind, and code Playground
by John Dittmar
HTML
<!DOCTYPE html>
<body>
<script src="http://d3js.org/d3.v2.js?2.9.6"></script>
</body>
</html>
CSS
text {
font-family:"Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 24px;
}
JavaScript
// initialize the svg canvas
var svg = d3.select("body").append("svg")
.attr("width", 960)
.attr("height", 500)
.append("g")
.attr("transform", "translate(80,150)");
// the message to animate
var msg = "⇢ My great message";
// shrink to this many characters
var min = 1;
// once shrunk replace with "replacementText"
var replacementText = '⇠';
// add the text to the canvas, calculate it's width, and then remove it
var ty = svg.append("text")
.text(msg);
// could have also used getBBox for width and height
var wid = ty.node().getComputedTextLength();
ty.remove();
ty = svg.append("text")
.text(msg.substr(0, min));
var minWid = ty.node().getComputedTextLength();
ty.remove();
// add a path of equal length as the width calculated for the text
svg.append("path")
// if you are going to have more than 1 of these
// on a give page, be sure to have a different id for each one
.attr("id", "path")
.attr("d", "M 0 25 L " + wid + " 25")
// add the text back to the canvas, add a
// text path for the text and link it to the path
// NOTE! the x and y attributes should not be set here -
// instead the appropriate x and y positions should be in the 'd'
// attribute of the path element!
// also - apparently text-anchor does not work well here, although,
// for my needs, it is not needed
var tp = svg.append("text")
.append("textPath")
.attr("class", "textpath")
.attr("xlink:href", "#path")
// initialize startOffset to 0 so things will work nicely right off the bat
.attr('startOffset', 0)
.text(msg);
// transition the text off of the viewport via the
// startOffset attribute
tp.on('click', function () {
toggleTextSlide(this, msg, (wid - minWid), replacementText)
});
function toggleTextSlide(elem, msg, transTo, transText) {
if (d3.select(elem).attr('startOffset') != 0) {
d3.select(elem).text(msg)
.transition()
.duration(750)
.attr('startOffset', 0);
} else {
...