Text isn't scaling properly in frame - ios

I'm making a flowchart app and I've ran into a problem while scaling shapes containing text in them.
Depending on the scale value the relative width of string changes:
scale 6.0: scale 6.0
scale 1.0:
scale 1.0
scale 0.5:
scale 0.5
Text area class has property logFontSize, which represents constant font size (12.0 in this case).
Scaling function (zoomVal is the new scale):
func zoom(zoomVal: CGFloat){
let newSize = self.logFontSize*zoomVal
self.attributes![NSAttributedString.Key.font] = (self.attributes![NSAttributedString.Key.font] as! UIFont).withSize(newSize)
self.attributedString?.setAttributes(self.attributes, range: NSRange(location: 0, length: self.text!.count))
}
I've also checked: there is no correlation between scale value and relation between frame rectangle (red) height and string height (capHeight, lineHeight etc).
How do I scale text so that the relation between its width and its frame's width remains constant?

This is a feature that improves legibility. Text metrics like size and padding do not have simple, linear relationships. They are tweaked in numerous ways at various sizes, and in font-specific ways, to keep text easy to read.
If you want to linearly scale text, you should render it, and then scale the layer it is drawn in. For your use case, likely the best approach would be to compose a static CATextLayer with CAShapeLayers, and then apply a CAAffineTransform to the entire container CALayer to resize it. This will give you smooth zooming, and will be more performant.

Related

How to reset a Rectangle's x,y,width,height, after transform

I have an app that uses konvajs, where I set rectangles to be resizable. I have it set such that after I transform the rectangle I set the scaleX and scaleY to 1 so I can just use x, y, width, and height. I do this with the following code:
myRectangle.on('transformend', function() {
myRectangle.width(Math.round(myRectangle.width() * myRectangle.scaleX()));
myRectangle.height(Math.round(myRectangle.height() * myRectangle.scaleY()));
myRectangle.scaleX(1);
myRectangle.scaleY(1);
});
However, sometimes after I resize (usually if I "flip" the rectangle by dragging up or to the left), the x, y, width and height are strange values. Sometimes the width or height is negative, sometimes it seems like the x and y positions do not refer to the top left of the rectangle. I want to be able to extract information about the rectangle, so I would like position to be top left of the rectangle with positive width and height values. I don't mind resetting these values after the rectangle is tranformed, but I am not quite sure how konvajs is calculating the x,y,width, and height so I can't properly reset them. Is there some metric indicating when a tranform "flips" a rectangle? Or some other way to reset it?
It seems that setting flipEnabled and rotationEnabled to false on the transformer prevents rotations from happening.
To get a visual sense of what is happening to the attrs during the transform, take a look at the demo in the official docs here and pay special attention to width/height, rotation and scale as you resize by dragging the right edge first, then repeat with the bottom edge.
It will help to understand that dragging a Transformer handle changes the scale of the rectangle - not the width or height. However this is not the end of the story - if you 'flip' the shape in the horizontal axis then you will see that the rotation is changed from zero to 180 degrees and the scaleX remains positive. But if you drag and flip the shape in the vertical axis then there is no rotation effect and the scaleY switches to negative.
Long story short - at the moment I can't think of a useful use-case that requires trying to redraw the rectangle without scale or rotation affects, which I will refer to as the 'plain' rect versus the 'exotic' rect you get after using the Transformer.
If the use-case is hit detection via your own math then you have everything you need to know in the rects x & y, width & height, rotation and scaleX & scaleY. Even if you could get the attrs for a plain rect you would still have the same params to plug into your math, so recomputing the plain rect is wasted effort.
If the use-case is storage (serialization) of the rect's attrs then again the same point as above - you need to store the position, rotation, size, and scale so as to be able to redraw it later.
A legitimate use-case for resetting scale to 1 would be if your app's business case requires it. But this only covers resetting:
rect.seAttrs({
width: rect.width() * scaleX,
height: rect.height() * scaleY,
scaleX: 1,
scaleY: 1
}
and leaves the rect at the same position and rotation.
Conclusion: attempting to recompute a plain rect from an exotic rect may not be worth the effort in some cases.

Set numeric UILabel for Auto Layout to correctly compute the intrinsic content size

I have a UILabel with a font of size 50 and text 1. At runtime, its text is changed to other numbers.
If I, say, center it in its superview, the automatically detected (intrinsic content size) height is a lot bigger than the actual text, and this is because it tries not to crop other lower characters like g.
The thing is that I know I won't use other characters than digits. I also don't want to set a fixed height constraint for it.
UIFont metrics include ascender, descender, cap height, x height, etc... all of which determines how the characters fit into a container. There is a good explanation and diagram here: http://cocoanetics.com/2010/02/understanding-uifont
If you really want to get the height (and/or width) of the individual character "glyphs" you'll need to use Core Text. This will include calling CTFontGetGlyphsForCharacters() and CTFontCreatePathForGlyph() to get the "glyph path" (a CGPath object), at which point you can get the "bounding box" to determine the exact size.
Lots of discussions and example code out there... A good starting point is simply searching for CTFontCreatePathForGlyph

MINIMUM bounding rect width for NSAttributedString

I have an NSAttributedString which I draw into a rectangle (no text views here.) I allow the user to resize that rectangle thus forcing the text to wrap onto multiple lines. All is good and I'm using NSTextContainer etc to figure out the text bounding height for a given width.
The challenge I have is knowing what the MINIMUM width can be - so that I don't allow the user to resize the rectangle to be narrower than the widest character/glyph in the string.
I have a working solution which involves getting the bounding rect for each glyph (boundingRectForGlyphRange) and keeping track of the largest - but this is a real performance killer on larger strings.
Anyone know of a better way?
Thanks
When you choose your font and display language, you could compile a lookup of all possible glyph widths. Order it descending with the largest glyphs first, then use rangeOfString: != NSNotFound; breaking after you find one (this is your maximum glyph width).
Hard to say what the performance difference is like, but it is probably faster than fetching the width of all your glyphs every time since it's just a string comparison instead of a font measurement.

Scale equation for bitmap font

I have a bitmap font in which each character is 32px. I create individual characters with this font and assign them to display objects, of which each object is 32px and the objects scale value is 1.0 (full scale)
Now what I am trying to do is make my font creation routine standardised to accept font sizes in it's function call.
So i can do say :
loadFont( font, size )
So we know 32px is the base font size and that has a scale of 1.0. How would a formula work that can calculate the scale based on the size passed.
For instance, 16px would be 0.5 scale (exactly half the scale of the base font size) that one is easy.
But say I wanted 24px, 18px, 12px and so on?
Thanks in advance
This hardly requires a math guru, it's just a simple ratio. A 24px font would be 24/32 or 0.75 for example.
function loadFont (font, size)
{
scale = size / original_size;
...
}
Is this what you're looking for?

Rails Paperclip Plugin - Style Options for Resizing

So, I want to resize images to a FIXED width, but proportional height.
I have been trying a wide range of operators:
380x242#
380x242>
380!x242
380x242<
none of them have the desired effect. Any help? I want it to fill or resize to the 380 width, then resize / shrink the height by the same factor it used to shrink or resize the image to 380 wide.
Try using 380x
This should resize width to 380px and keep original aspect ratio.
For all available options for resizing images go here: http://www.imagemagick.org/script/command-line-processing.php?ImageMagick=lj6pre8q2iautc3ch6nuph1fc2#geometry
"#" is an argument used by Paperclip to know whether or not you expect the pic to be cropped. Using "100x100#" will scale and crop the picture exactly to that size. %#!<> are arguments in the Geometry String used by ImageMagick. One can use the following ImageMagick geometry strings for resizing images:
Ignore Aspect Ratio ('!')
Only Shrink Larger ('>')
Only Enlarge Smaller ('<')
Fill Given Area ('^')
Percentage Resize ('%')
Pixel Count Limit ('#')
According to the ImageMagick documentation for Image Geometry the geometry argument can be
scale% Height and width both scaled by specified percentage
scale-x%xscale-y% Height and width individually scaled by specified percent
width Height automagically selected to preserve aspect ratio
xheight Width automagically selected to preserve aspect ratio
widthxheight Maximum values of height and width given, ratio preserved
widthxheight^ Minimum values of width and height given, ratio preserved
widthxheight! Width and height emphatically given, ignore original ratio
widthxheight> Change only if an image dimension exceeds a specified dim.
widthxheight< Change only if both image dimensions exceed specified dim.
you can use , :show => '786>x447' for fixed width and prorortional height
The resizing options are limited but you can also use paperclip custom processors to resize images dynamically.
Railscasts has a good example of using a custom processor for paperclip, though his example allows a user to crop an image.
http://railscasts.com/episodes/182-cropping-images
You can calculate the height yourself:
newHeight = oldHeight * 380 / oldWidth

Resources