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 {
       ...