Hype TextPath (Beta)
Animated demo here
So as we now have path information in Hype we can manipulate… how about using that for a nice text path animation. Assign a class that starts with textPath
to your vector path and assign the same class to your text with the addition content
. So for example assign to your first path the class textPathOne
and to the corresponding text the class textPathOne content
. Use the line animation to move the text along the line. That’s it.
Put this code snippet in your Head HTML …
<script>
function HypeTextPath(hypeDocument, element, event) {
/* get scene */
var sceneElm = document.querySelector('#'+hypeDocument.documentId()+' > .HYPE_scene[style*="block"]');
/* helper for offset transfer from stroke dashoffset to textpath offset */
var setStartOffset = function(path, textPath){
if (typeof path.getAttribute('stroke-dasharray') === 'string') {
var p = Number(path.getAttribute('stroke-dashoffset'));
var l = path.getTotalLength();
textPath.setAttribute('startOffset', ((1-p/l)*100).toFixed(2)+'%');
}
}
/* fetch selector for textPath svg */
var nElmAll = sceneElm.querySelectorAll ('div[class*="textPath"] svg');
/* process them */
nElmAll.forEach (function(nElm) {
var textPathID = nElm.parentNode.classList[1];
if (textPathID.length>8) {
var tElm = sceneElm.querySelector('.'+textPathID+'.content');
var pElm = nElm.querySelector ('path');
/* hide path */
pElm.style.opacity = 0;
pElm.style.pointerEvents = 'none';
/* hide text */
tElm.style.opacity= 0;
/* add text to path */
var nsSvg = "http://www.w3.org/2000/svg";
var nsXlink = 'http://www.w3.org/1999/xlink'
var svgtElm = document.createElementNS(nsSvg, "text");
var svgtpElm = document.createElementNS(nsSvg, "textPath");
svgtElm.appendChild(svgtpElm);
/* copy content */
svgtpElm.innerHTML = tElm.innerHTML;
/* transfer and translate styles frm HTML to SVG */
var keys = ['fontFamily','fontSize',['color','fill'], 'letterSpacing', 'wordSpacing'];
for (var i=0; i<keys.length; i++) {
var isArray = typeof keys[i] === 'object';
var hKey = isArray ? keys[i][0] : keys[i];
var vKey = isArray ? keys[i][1] : keys[i];
svgtElm.style[vKey] = tElm.style[hKey];
}
/* fix overflow based on font size */
var buffer =parseInt(svgtElm.style.fontSize);
nElm.style.setProperty('padding', buffer+'px', 'important');
nElm.style.setProperty('margin-left', '-'+buffer+'px', 'important');
nElm.style.setProperty('margin-top', '-'+buffer+'px', 'important');
nElm.style.setProperty ('overflow', 'visible', 'important');
/* link path*/
svgtpElm.setAttributeNS(nsXlink, 'xlink:href', '#'+pElm.id);
svgtpElm.setAttribute( 'href', '#'+pElm.id);
/* set initial offset */
setStartOffset (pElm,svgtpElm);
/* append to SVG */
nElm.appendChild(svgtElm);
/* listen to and act on changes */
var mutationObserver = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
if (mutation.attributeName == 'stroke-dashoffset') {
setStartOffset (mutation.target,svgtpElm);
}
});
});
mutationObserver.observe(pElm, {
attributes: true
});
}
});
return true;
}
if("HYPE_eventListeners" in window === false) {
window.HYPE_eventListeners = Array();
}
window.HYPE_eventListeners.push({"type":"HypeSceneLoad", "callback":HypeTextPath});
</script>
Example Download:
HypeTextPath.hype.zip
Versionhistory:
1.0 Initial release under MIT-license