No line spacing when using drawline

Posted on
Page
of 2
/ 2
Next
  • Hi,

    When I use code like this

    g.setFontVector(20);
    g.drawString("Temp:"+t + "\nBattery:" + b + "%\n" + c + "\nUptime: " + u + " hr",0,60);
    

    the "\n" creates a newline, works fine, nice feature.

    But there is no spacing between the lines so the result is not very readable. In all cases the characters of the lines "touch" and in some cases characters of lines even "overlap" ( see picture in annex ).

    Searched the documentation for a line-space setting, but did not find it.

    Is there a line-space setting, and if not, is it a suggestion to add one?


    1 Attachment

    • p1.png
  • Looks like bug, there is now new vector font which is larger for same point size (e.g. size 26 now is similar to older size 30) so maybe some line pixel size constant was not updated somewhere in drawString code

  • Thanks for your comment, would be my 1st reported bug ;-)

    BTW. Running latest version 2V06, but 2v05.97 of the Emulator has the same behaviour.

  • well it uses customHeight here https://github.com/espruino/Espruino/blo­b/master/libs/graphics/jswrap_graphics.c­#L1374 and it is read here https://github.com/espruino/Espruino/blo­b/master/libs/graphics/jswrap_graphics.c­#L1322 and this call returns value 'scale' here https://github.com/espruino/Espruino/blo­b/master/libs/graphics/jswrap_graphics.c­#L1280
    so maybe the real issue is that the new font is now larger for same scale than before as mentioned here

  • Yes, this sounds like the new vector font...

    @NebbishHacker any strong feelings about this? I think it makes sense to keep the line height the same as the vector font height, so I guess we should just tweak the font size down slightly?

  • Currently the font size accurately represents the height of letters like A, but it doesn't take into account accented characters (like À) or descenders (like j). Accents and descenders both currently protrude by about 1/4 of the font height, so the actual maximum height of a line of text is 1.5 times what you might expect.

    For some stuff I'm currently working on it would be convenient if g.clearRect(x, y, x+g.stringWidth(text), y+g.getFontHeight()) was always guaranteed to cover a single line drawn via g.drawString(text), which isn't currently the case.

    Overall, though, I don't have very strong feelings about whether we should tweak the font size.

  • As can be seen in the picture the beginletters of the lines (T B C) have zero spacing.

    And in the case of "accents and descenders" the characters in successive line overlap.

    I am too using g.clearRect to clear the result of a g.drawString and would expect to clear all pixels of drawString characters. Didn't know that this currently NOT the case.

  • In analogy with http://forum.espruino.com/conversations/­302392/ I coded a "drawString" override that introduces proper line spacing in Strings witch "\n" newlines in it. In this case I have chosen for 5 pixels of space between each line..

    Rather new to Espruino so maybe not the best solution, but it works for me.

    Hopefully Gordon will come up with a structural solution.

    Example code:

    // override drawString function to allocate line spacing
    g._ds = g.drawString;
    g.drawString = function(s,x,y) {
      s=s.toString();
      sa=s.split("\n");
      print(sa);
      spacing=5+g.getFontHeight();
      sa.forEach(function(line){ g._ds(line,x,y); y+=spacing; });      
    };
    
    g.clear();
    g.setFontVector(20);
    g.setColor(1,1,1);
    g.drawString("Temp:\nBattery:%\nCharging­\nUptime: 0.00\nFreeFlash: \nFreeStor:",0,30);
    

    And the resulting output:


    1 Attachment

    • screenshot (3).png
  • So for reference: I flashed 2v05.1 onto a watch for comparison, and it looks like the old vector font exhibited the same issue with descenders overlapping the next line.


    1 Attachment

    • IMG_20200701_153204.jpg
  • OK, but in your picture at least there is 1 pixel between each successive line (between the T, B and C character).

    I'm running 2V06 on Bangle, and the 1 pixel spacing between the T,B, and C char is not there.

  • @gerardwr - That looks like a good solution to me, although I would have personally made an entirely new function named drawLines or something instead of overriding g.drawString.

  • If you look closely the B and the C are touching at one point, so even the 1 pixel space is not always there.

    In any case, I imagine you would generally want a bit more space between lines than that.

  • @NebbishHacker

    Fair enough, your suggestion is cleaner.

    But I wanted a "fix" for the drawString problem.

    Found my inspiration here http://forum.espruino.com/conversations/­302392/ and thought "hey that's clever" and coded away.

    I'm a lazy coder, so in this way I did not have to change my code ;-)

    And if Gordon comes up with a fix to "drawString" I delete the override and I'm ready.

  • @NebbishHacker

    Agree, 1 pixel of line-spacing is not enough, so in my override I used 5 pixels, that seems also enough for descendents. For now ...., have been using the "fix" only for a few hours.

    Output looks like this now:


    1 Attachment

    • screenshot (4).png
  • Hmm, that's tricky.

    it would be convenient if g.clearRect(x, y, x+g.stringWidth(text), y+g.getFontHeight()) was always guaranteed to cover a single line drawn via g.drawString(text)

    While not quite as pretty, I think that is probably the best solution here, and it's definitely the least hacky :) I'll see about tweaking that...

  • @Gordon - I guess this means that we can forget about a "structural solution"for the problem on the short term, and I will have to live with my drawString override for now. Right?

    Maybe I will add the g.clearRect(x, y, x+g.stringWidth(text), y+g.getFontHeight()) to my override, in my case it's always required with every drawstring.

  • Well some settable line space setting would solve it as mentioned in first post? there is
    https://www.espruino.com/Reference#l_Gra­phics_setFontAlign maybe this could remember line height/spacing preference too?

  • @fanoush
    Yes, a settable line spacing would be a good solution to the problem.

    Fixing the bug AND adding a line space setting would be the perfect solution.

    But @gordon says that it’s “tricky” 🙁

  • Well then this would be not a bug but feature, you would need to set your preferred additional space to compensate for that font feature as e.g. without using accented letters the reserved space would be otherwise too big for you (on the top). This could be used both for handling '\n' in drawString automatically and could be read for g.clearRect when trying to clear area occupied by the text.

  • One approach to making sure you clear the right area would be to take advantage of g.getModified:

    g.getModified(true); // Reset modified area
    // Insert whatever draw calls you want here
    g.drawString(...);
    let m = g.getModified(); // Save modified area for later
    
    g.clearRect(m.x1, m.y1, m.x2, m.y2); // Will clear the precise area affected by the above draw calls
    
  • @NebbishHacker
    I was thinking about this strategy for my drawstring override:

    • get the area that is going to be covered by the string using fontHeight/fontWidth accounting for newlines in the string
    • clear this area with clearRect
    • then call the original drawstring
    • done, nice and simple, no further bookkeeping.

    But using getModified is more universal as it seems to cover all graphics. I have an App that uses many screens, so I would have to do a lot of bookkeeping with the different getModified areas.

    Hmmmmm...... pondering .........

  • Changed my drawString override function to clearRect the area where the string is going to be displayed.

    Not extensively tested, but seems to work ok for me. It saves a lot of clearRects in my code :-)

    Comments and suggestions welcome!

    Code is like this:

    // override drawString function to:
    // - allocate proper line spacing between successive lines
    // - clear the area where the string will be displayed
    g._ds = g.drawString;
    g.drawString = function(s,x,y) {
      s=s.toString();
      sa=s.split("\n");
      spacing=5+g.getFontHeight();
      sa.forEach(function(line){
        // clear the area where the string will be written
        g.clearRect(x,y,x+g.stringWidth(line), y + spacing);
        // now call the original drawString
        g._ds(line,x,y);
        y+=spacing;
      });      
    };
    
    
  • @NebbishHacker
    As you can see in the post above I did not use your getModified suggestion at the moment.

    My app is currently limited to text, I'm a lazy programmer, so this was the most efficient solution for me now.

    When I get to the graphics part of my app I will remember your suggestion, thanks!

  • Fixed a bug in my override function, updated the code in the post above.

    And also found some flaws in my override code.

    If the drawString string is replacing a previous WIDER string the `clearRect' area is to narrow, so parts of the previous string will still be visible.

    Back to the drawing board :-(

  • @NebbishHacker
    Your suggestion on using getModified was "spot on", shame on me ;-)

    Here's my latest code including a random 'drawString` to check that the override is now OK. Seems that it's perfect for me now.

    Ofcourse it requires some bookkeeping of the m variable if you change to a complete different screen.

    var m=0;
    
    // override drawString function to:
    // - allocate proper line spacing between successive lines (here 5 pixels)
    // - clear the area where the previous drawString was displayed
    g._ds = g.drawString;
    g.drawString = function(s,x,y) {
      s=s.toString();
      sa=s.split("\n");
      spacing=5+g.getFontHeight();
    
      g.clearRect(m.x1, m.y1, m.x2, m.y2); // Will clear the precise area affected by the previous drawString calls
    
      g.getModified(true); // Reset modified area
    
      sa.forEach(function(line){    
        //call the original drawString
        g._ds(line,x,y);
        y+=spacing;
      });    
      m=g.getModified(); // save modified area for clearing on next drawString
    };
    
    
    
    // write a random string of random size at random x and y positions
    setInterval(function () {
      g.setFontVector(80*Math.random());
      g.setColor(1,0,0);
      getal=1000*Math.random();
      getal=getal.toFixed(0);
      g.drawString(getal,Math.random()*239,Mat­h.random()*239);
      
    }, 1000);
    
    g.clear();
    
  • Post a reply
    • Bold
    • Italics
    • Link
    • Image
    • List
    • Quote
    • code
    • Preview
About

No line spacing when using drawline

Posted by Avatar for gerardwr @gerardwr

Actions