Open tilleraj opened 4 years ago
The default layout seems to work just fine. Loyalty has been added with it's own position and is placed where P/T are.
While not limited to Planeswalkers, this is where I first encountered it. The issue is that card text is not bounded by the text frame and can overflow from its designated area. Text that is too long needs to be sized to fit. Below I've provided examples of the issue and included two attempts at fixing it.
A more mathematically and practically elegant solution is desired.
Below we see Chandra, Pyromaster
and Jace, Architect of Thought
's last lines touching the outside of the text box.
Here we see all cards overflowing, Greater Morphling
being the worst offender, bleeding into the card below it.
(There are some obvious mathematical oversights with this method looking at it now, but here it is nonetheless.)
In these examples, Line Height, Font Size, and Paragraph Spacing are all reduced by the percentage of characters over the limit.
(totalLetters+(numNewLines*newLineCharWeight))/charCap-1
So with a charCap
of 425 and a newLineCharWeight
of 50, you get a reasonable
Chandra, Pyromaster - {2}{R}{R} (Legendary Planeswalker — Chandra)
355 letters + 2 new lines was too big to fit.
* lineHeight reduced 7.06% from 2.2 to 2.0447058823529414
* fontSize reduced 7.06% from 2.2 to 2.0447058823529414
* paragraphSpacing reduced 7.06% from 0.5 to 0.4647058823529412
355+2*50 = 455
Jace, Architect of Thought - {2}{U}{U} (Legendary Planeswalker — Jace)
370 letters + 2 new lines was too big to fit.
* lineHeight reduced 10.59% from 2.2 to 1.9670588235294117
* fontSize reduced 10.59% from 2.2 to 1.9670588235294117
* paragraphSpacing reduced 10.59% from 0.5 to 0.44705882352941173
370+2*50 = 470
Note: Jace is reduced more than necessary
This method is over-zealous with more verbose cards.
Master of The Hunt
looks alright:
Master of the Hunt - {2}{G}{G} (Creature — Human)
487 letters + 0 new lines was too big to fit.
* lineHeight reduced 14.59% from 2.2 to 1.8790588235294117
[...]487+0*50 = 487
But cards with multiple paragraphs are far too reduced
Bureaucracy - {3}{U}{U} (Enchantment)
617 letters + 1 new lines was too big to fit.
* lineHeight reduced 56.94% from 2.2 to 0.9472941176470591
[...]617+1*50 = 667
Greater Morphling - {6}{U}{U} (Creature — Shapeshifter)
510 letters + 6 new lines was too big to fit.
* lineHeight reduced 90.59% from 2.2 to 0.20705882352941202
[...]510+6*50 = 810
I got a bit creative and manipulated straight percentage until it gave me something resembling the desired results. I also tried tweaking newLineCharWeight
and charCap
to little success and the values I started with worked the best. I tried reducing values based on how much of the charCap was contributed to by new lines vs text, adjusting paragraphSpacing
first and more heavily for new line heavy text, but got mixed results. Below are the flawed but best results I've gotten so far.
pctOverCap = (totalLetters+(numNewLines*newLineCharWeight))/charCap-1
pctOverCap = math.sqrt(pctOverCap*100)/30
Chandra and Jace are slightly smaller than straight-percentage. Chandra 8.86% from 7.06 and Jace 10.85% from 10.59%
Chandra, Pyromaster - {2}{R}{R} (Legendary Planeswalker — Chandra)
355 letters + 2 new lines was too big to fit.
* lineHeight reduced 8.86% from 2.2 to 2.0051647251811793
[...]355+2*50 = 455
Jace, Architect of Thought - {2}{U}{U} (Legendary Planeswalker — Jace)
370 letters + 2 new lines was too big to fit.
* lineHeight reduced 10.85% from 2.2 to 1.9613764963994784
[...]370+2*50 = 470
The biggest change, however, can be seen with the more verbose cards.
Master of The Hunt
is reduced 12.73% vs 14.59% in straight percentage, Bureaucracy
25.15% vs 56.94%, and Greater Morphling
31.73% vs 90.59%
Master of the Hunt - {2}{G}{G} (Creature — Human)
487 letters + 0 new lines was too big to fit.
* lineHeight reduced 12.73% from 2.2 to 1.919906644881212
[...]487+0*50 = 487
Bureaucracy - {3}{U}{U} (Enchantment)
617 letters + 1 new lines was too big to fit.
* lineHeight reduced 25.15% from 2.2 to 1.6466312319401715
[...]617+1*50 = 667
Greater Morphling - {6}{U}{U} (Creature — Shapeshifter)
510 letters + 6 new lines was too big to fit.
* lineHeight reduced 31.73% from 2.2 to 1.5020290846368953
[...]510+6*50 = 810
While not pictured above to save space, Narset Transcendent
specifically has been a pain to deal with.
Chandra, Pyromaster
355+250 = 455
Jace, Architect of Thought
370+250 = 470
Narset Transcendent
330+2*50 = 430
Chandra, Pyromaster
, Jace, Architect of Thought
, and Narset Transcendent
are all equally out of bounds. Chandra and Jace by the same number of characters, Narset by moreJace, the Mind Sculptor
are reduced.Here is a plot of plot y=1-1e^(-0.0035x) and y=sqrt(x)/30 from x=-10 to x=800 y=-0.25 to y=1.25 taken from [WolframAlpha](https://www.wolframalpha.com/input/?i=plot+y%3D1-1e%5E%28-0.0035x%29%2C+y%3Dsqrt%28x%29%2F30+from+x%3D-10+to+x%3D800+y%3D-0.25+to+y%3D1.25)
The early reduction from sqrt is valuable, but being asymptotic is nice. There is a practical maximum length of text WotC is willing to print. Bureaucracy
is a joke card meant to be as long as possible. Coming in at 644 (694 with newlines) or 617 with alnum check, it can be considered the longest possible, eliminating the need for an asymptote as long as it is handled correctly.
Maintaining a charCap of 425 and using 694 as our max, we only need to consider up to 269 extra characters
Something like y=0.65-0.58*e^(-0.0065x) may be the best?
I’m reading this on my phone now, so I may be missing something. My ideal approach would be to something like
font_size = DEFAULT_FONT_SIZE
layoutText()
while (textOverflowsContainer):
font_size = font_size - SIZE_INCREMENT
layoutText()
Definitely more straightforward and simple.
I guess the easiest way is measure the height of the text box and check that currentOffset
is less than the box height and if not, throw an exception then wrap the showWrappedText
call in a try/except, with re-running it with smaller lineHeight on except?
# Draw cardText
ctx.set_font_size(layout.cardTextH)
showWrappedText(ctx, card.cardText,
top=layout.cardTextBL[1],
left=layout.cardTextBL[0],
right=layout.cardTextBL[0] + layout.cardTextW,
lineHeight=layout.cardTextH
)
I think the best way to handle this is to draw the text to a fake surface and just measure the height. Something vaguely like
def fitText(text):
ctx = makeFakeContext()
lineHeight = MAX_LINE_HEIGHT
while True:
textHeight = showWrappedText(
ctx, text,
top=0,
left=0,
right=layout.cardTextW,
lineHeight=lineHeight)
if textHeight <= layout.cardTextH:
return lineHeight
lineHeight = lineHeight - LINE_HEIGHT_INCREMENT
Where showWrappedText
has been modified to return the final offset. Then when you draw, you just call fitText()
first ad set the text size. That way you don't to clear and redo any work on the real surface.