Letter spacing in canvas element

前端 未结 10 2305
攒了一身酷
攒了一身酷 2020-12-24 06:46

The question says it all pretty much. I\'ve been searching around and starting to worry that it\'s impossible.

I\'ve got this canvas element that I\'m drawing text t

相关标签:
10条回答
  • 2020-12-24 07:02

    Not true. You can add letter-spacing property to the canvas element in css and it works perfectly. No need for complicated workarounds. I just figured it out right now in my canvas project. i.e.: canvas { width: 480px; height: 350px; margin: 30px auto 0; padding: 15px 0 0 0; background: pink; display: block; border: 2px dashed brown; letter-spacing: 0.1em; }

    0 讨论(0)
  • 2020-12-24 07:05

    You can't set letter-spacing as a property of the Canvas context. You can only achieve the effect by doing manual spacing, sorry. (As in, drawing each letter manually increasing the x by some pixel amount on each)

    For the record, you can set a few text properties by using ctx.font but letter-spacing is not one of them. The ones you can set are: "font-style font-variant font-weight font-size/line-height font-family"

    For instance you can technically write ctx.font = "bold normal normal 12px/normal Verdana" (or any omission of any of those) and it will parse correctly.

    0 讨论(0)
  • 2020-12-24 07:07

    I don't know about other people but I have adjusted line spacing by increasing the y value on the text that I am writing. I'm actually splitting a string by spaces and kicking each word down a line inside a loop. The numbers i use are based on the default font. If you use a different font that these numbers may need to be adjusted.

    // object holding x and y coordinates
    var vectors = {'x':{1:100, 2:200}, 'y':{1:0, 2:100}
    // replace the first letter of a word
    var newtext = YOURSTRING.replace(/^\b[a-z]/g, function(oldtext) {
        // return it uppercase
        return oldtext.toUpperCase(); 
    });
    // split string by spaces
    newtext = newtext.split(/\s+/);
    
    // line height
    var spacing = 10 ;
    // initial adjustment to position
    var spaceToAdd = 5;
    // for each word in the string draw it based on the coordinates + spacing
    for (var c = 0; c < newtext.length; c++) {
        ctx.fillText(newtext[c], vectors.x[i], vectors.y[i] - spaceToAdd);
        // increment the spacing 
        spaceToAdd += spacing;
    }               
    
    0 讨论(0)
  • 2020-12-24 07:09

    here's some coffeescript that allows you to set kerning to your context like so

    tctx = tcanv.getContext('2d')
    tctx.kerning = 10
    tctx.fillStyle = 'black'
    tctx.fillText 'Hello World!', 10, 10
    

    the supporting code is:

    _fillText = CanvasRenderingContext2D::fillText
    CanvasRenderingContext2D::fillText = (str, x, y, args...) ->
    
      # no kerning? default behavior
      return _fillText.apply this, arguments unless @kerning?
    
      # we need to remember some stuff as we loop
      offset = 0
    
      _.each str, (letter) =>
    
        _fillText.apply this, [
          letter
          x + offset + @kerning
          y
        ].concat args # in case any additional args get sent to fillText at any time
    
        offset += @measureText(letter).width + @kerning
    

    The javascript would be

    var _fillText,
      __slice = [].slice;
    
    _fillText = CanvasRenderingContext2D.prototype.fillText;
    
    CanvasRenderingContext2D.prototype.fillText = function() {
      var args, offset, str, x, y,
        _this = this;
    
      str = arguments[0], x = arguments[1], y = arguments[2], args = 4 <= arguments.length ? __slice.call(arguments, 3) : [];
      if (this.kerning == null) {
        return _fillText.apply(this, arguments);
      }
      offset = 0;
    
      return _.each(str, function(letter) {
        _fillText.apply(_this, [letter, x + offset + _this.kerning, y].concat(args));
        offset += _this.measureText(letter).width + _this.kerning;
      });
    };
    
    0 讨论(0)
  • 2020-12-24 07:10

    I'm not sure if it should work (per specs), but in some browsers (Chrome) you can set the letter-spacing CSS property on the <canvas> element itself, and it will be applied to all text drawn on the context. (Works in Chrome v56, does not work in Firefox v51 or IE v11.)

    Note that in Chrome v56 you must re-get the canvas 2d context (and re-set any values you care about) after each change to the letter-spacing style; the spacing appears to be baked into the 2d context that you get.

    Example: https://jsfiddle.net/hg4pbsne/1/

    var inp = document.querySelectorAll('input'),
        can = document.querySelector('canvas'),
        ctx = can.getContext('2d');
        can.width = can.offsetWidth;
    
    [].forEach.call(inp,function(inp){ inp.addEventListener('input', redraw, false) });
    redraw();
    
    function redraw(){
      ctx.clearRect(0,0,can.width,can.height);
      can.style.letterSpacing = inp[0].value + 'px';
    
      ctx = can.getContext('2d');
      ctx.textAlign = 'center';
      ctx.textBaseline = 'middle';
      ctx.font = '4em sans-serif';
      ctx.fillText('Hello', can.width/2, can.height*1/4);
      
      can.style.letterSpacing = inp[1].value + 'px';
      ctx = can.getContext('2d');
      ctx.textAlign = 'center';
      ctx.textBaseline = 'middle';
      ctx.font = '4em sans-serif';
      ctx.fillText('World', can.width/2, can.height*3/4);
    };
    canvas { background:white }
    canvas, label { display:block; width:400px; margin:0.5em auto }
    <canvas></canvas>
    <label>hello spacing: <input type="range" min="-20" max="40" value="1" step="0.1"></label>
    <label>world spacing: <input type="range" min="-20" max="40" value="1" step="0.1"></label>


    Original, cross-browser answer:

    This is not possible; the HTML5 Canvas does not have all the text-transformation power of CSS in HTML. I would suggest that you should combine the appropriate technologies for each usage. Use HTML layered with Canvas and perhaps even SVG, each doing what it does best.

    Note also that 'rolling your own'—drawing each character with a custom offset—is going to produce bad results for most fonts, given that there are letter kerning pairs and pixel-aligned font hinting.

    0 讨论(0)
  • 2020-12-24 07:11

    You can't set the letter spacing property, but you you can accomplish wider letter spacing in canvas by inserting one of the various white spaces in between every letter in the string. For instance

    ctx.font = "3em sheepsans";
    ctx.textBaseline = "middle";
    ctx.textAlign = "center";
    ctx.fillStyle = "rgb(255, 255, 255)";
    var ctext = "Blah blah text".split("").join(String.fromCharCode(8202))
    ctx.fillText(ctext, 1024 / 2, 768 / 2);
    

    This will insert a hair space between every letter.

    Using 8201 (instead of 8202) will insert the slightly wider thin space

    For more white space options, see this list of Unicode Spaces

    This method will help you to preserve the font's kerning much more easily than manually positioning each letter, however you wont be able to tighten your letter spacing this way.

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