Raphael JS Text Along path

前端 未结 2 1505
天涯浪人
天涯浪人 2021-01-05 01:58

I am looking for an example or some confirmation on a concept. Looking to use Raphael JS on an app and want to be able to warp text similar to how graphic design application

相关标签:
2条回答
  • 2021-01-05 02:30

    Here's an adaptation of Chris Wilson's code, refactored as a drop-in function, with added features:

    • IE8 / VML mode support and Gecko/Firefox support (by defining the rotation origin - without this, IE8 and Firefox go nuts throwing the text all around the page)
    • A small adjustment to make text less ugly in Gecko browsers (e.g. Firefox) - without this, these increase the letter spacing arbitrarily
    • Support for manually defined font sizes and letter spacing, as well as dynamic 'fill the path' sizes and spacing
    • Support for manual kerning (fine-tuning letter spacing character by character). Text on a path often creates really ugly letter spaces; this allows you to define manual tweaks to fix these, by:
      • Numeric position in the string, or,
      • Character, or,
      • Character pairs (applying to instances of a character based on the preceding character, e.g. the below example tightens 'ae' pairs and widens 'rn' pairs)

    JSBIN DEMO

    function textOnPath( message, path, fontSize, letterSpacing, kerning, geckoKerning) {
        // only message and path are required, other args are optional
        // if fontSize or letterSpacing are undefined, they are calculated to fill the path
        // 10% of fontSize is usually good for manual letterspacing
    
        // Gecko, i.e. Firefox etc, inflates and alters the letter spacing
        var gecko = /rv:([^\)]+)\) Gecko\/\d{8}/.test(navigator.userAgent||'') ? true : false;
    
        var letters = [], places = [], messageLength = 0;
        for (var c=0; c < message.length; c++) {
            var letter = paper.text(0, 0, message[c]).attr({"text-anchor" : "middle"});
            letters.push(letter);
    
            if (kerning) {
                if(gecko && geckoKerning) {
                    kerning = geckoKerning;
                }
                var character = letter.attr('text'), kern = 0;
                var predecessor = letters[c-1] ? letters[c-1].attr('text') : '';
    
                if (kerning[c]) {
                    kern = kerning[c];
                } else if (kerning[character]) {
                    if( typeof kerning[character] === 'object' ) {
                        kern = kerning[character][predecessor] || kerning[character]['default'] || 0;
                    } else {
                        kern = kerning[character];
                    }
                }
                if(kerning['default'] ) {
                    kern = kern + (kerning['default'][predecessor] || 0);
                }            
                messageLength += kern;
            }
    
            places.push(messageLength);
            //spaces get a width of 0, so set min at 4px
            messageLength += Math.max(4.5, letter.getBBox().width);
        }
    
        if( letterSpacing ){
            if (gecko) {
                letterSpacing = letterSpacing * 0.83;
            }
        } else {
            letterSpacing = letterSpacing || path.getTotalLength() / messageLength;
        }
        fontSize = fontSize || 10 * letterSpacing;
    
        for (c = 0; c < letters.length; c++) {
            letters[c].attr("font-size", fontSize + "px");
            p = path.getPointAtLength(places[c] * letterSpacing);
            var rotate = 'R' + (p.alpha < 180 ? p.alpha + 180 : p.alpha > 360 ? p.alpha - 360 : p.alpha )+','+p.x+','+p.y;
        letters[c].attr({ x: p.x, y: p.y, transform: rotate });
        }
    }
    
    0 讨论(0)
  • 2021-01-05 02:42

    This isn't too difficult using path.getPointAtLength, as Kevin Nielsen suggests:

    path = paper.path("M50,100c40,-50 270,50 300,0").attr("stroke", "#CCC");
    message = "I want to do this in RaphaelJS";
    
    //since not every letter is the same width, get the placement for each letter 
    //along the length of the string
    //however, Raphael appears to group the width of letters into intervals of 4px,
    //so this won't be perfect        
    for (; c < message.length; c += 1) {
            letter = paper.text(0, 0, message[c]).attr({"text-anchor" : "start"});
        letters.push(letter);
        places.push(message_length);
        //spaces get a width of 0, so set min at 4px
        message_length += Math.max(4, letter.getBBox().width);
    }
    
    ratio = path.getTotalLength() / message_length;
    fontsize = 10 * ratio;
    
    for (c = 0; c < letters.length; c += 1) {
        letters[c].attr("font-size", fontsize + "px"); 
        p = path.getPointAtLength(places[c] * ratio);
        //there does appear to be a bug in p.alpha around 180. Here's the fix
        letters[c].attr({ x: p.x, y: p.y, transform: 'r' + (p.alpha < 180 ? p.alpha + 180 : p.alpha)});
    }
    

    jsFiddle

    0 讨论(0)
提交回复
热议问题