Search code examples
svgadobe-illustrator

Illustrator to SVG: How is 'startOffset' for TextPath calculated?


Simple example: I draw a horizontal, 1000px line in Illustrator (tried in CS5 & CS6) and put a text on it. I drag the starting point of the text on the path to 250px.

When I export to SVG, I would expect Illustrator to set the 'startOffset'-Attribute of the textPath tag to 25%. Instead, it's somewhere around 32% (a third??).

When I drag the text to 500px, however, 'startOffset' is set to 50% as expected.

At 750px, the attribute will be 67%.

The problem is that, viewing the SVG in Firefox, the text is displayed at a different position as it seems to apply the percentage in a linear way. So 32% really means 320px and not 250px the way Illustrator seems to calculate it...

Am I missing something here? Or does anybody know a way to recalculate the percentage so it's displayed correctly in SVG?

Thx for any help


Solution

  • Ok, so i figured out how to calculate the right percentages:

    • Apparently, Illustrator calculates the percentage depending on the number of path segments. If the path is made of two segments (i.e. 3 vertices), and a path text is applied and positioned at the second vertex (the 'middle'), this will result in a startOffset of 50% in the SVG-File, regardless of the size of each path segment. The first segment can be 1000px long and the second one only 4px (total path length of 1004px): Placing the text at the second vertex will always result in 50%.

    • SVG/Browsers on the other side calculate the percentage depending on the total path length. So, referring to the example above, the text will not be placed at a length of 1000px (which is 50% if you look at the number of segments and thus the end of the first segment) but at 502px which is 50% of the total path length.

    In order to convert the 'illustrator percentage' to the 'browser percentage', you could do something like this (not optimized):

     // Get the current percentage    
     var oldPercent = parseFloat(textPathNode.getAttribute('startOffset').split('%')[0])/100;
    
     // Get the path
     var parentPath = document.getElementById(textPathNode.getAttribute('xlink:href').split('#')[1])
    
     // Get the path segments
     var parentPath.getAttribute('d').match(/[MmLlHhCc][\d\,\.\-\s]+/g);
    
     // Calculate the percentage for one segment
     var percentPerSegment = 1/segments.length;
    
     // Find out on which segment the textPath lies
     var offsetIsOnSegmentNo = Math.floor(oldPercent/percentPerSegment);
    
     // Calculate the length of that segment
     var virtualPath = document.createElementNS('http://www.w3.org/2000/svg', 'path');
     virtualPath.setAttribute('d', 'M0,0'+segments[offsetIsOnSegmentNo]);
     var segLength = virtualPath.getTotalLength();
    
     // Calculate the total path length of the previous segments
     var prevSegLength=0;
     var prevD = '';
     for(var i=0; i<offsetIsOnSegmentNo; i++)
        prevD += segments[s];
    
     var virtualPrevPath = document.createElementNS('http://www.w3.org/2000/svg', 'path');
     virtualPrevPath.setAttribute('d', 'M0,0'+prevD);
     var prevPathLength = virtualPrevPath.getTotalLength();
    
     // Calculate the actual path length for the old percentage             
     var totalLength = prevPathLength + segLength*(oldPercent-(percentPerSegment*offsetIsOnSegmentNo))/(percentPerSegment);
    
     // Calculate the correct percentage
     var newPercentage = totalLength / parentPath.getTotalLength();
    
     textPathNode.setAttribute('startOffset', newPercentage*100+'%');