Re: NSAttributedString in NSAffineTransform
Re: NSAttributedString in NSAffineTransform
- Subject: Re: NSAttributedString in NSAffineTransform
- From: Graham Cox <email@hidden>
- Date: Mon, 10 Nov 2008 01:46:47 +1100
On 10 Nov 2008, at 1:01 am, Joseph Ayers wrote:
I am having a tremendous problem getting the vertical text in the y
Axis of a graph. If i try to rotate text specified as
NSAttributedString it appears to get translated in nonlinear ways: I
would assume that in the below, the text would
rotate around NSMinX(rect) and NSMinY(rect) but it doesn't.
Consider:
- (void)drawYLabel:(NSRect)rect
{
NSPoint labelHere;
int xOffSet;
if(drawYLabelFlag == YES)
{
NSAffineTransform *transform = [NSAffineTransform transform];
NSGraphicsContext *context = [NSGraphicsContext currentContext];
// [transform translateXBy:NSMinY(gRect) yBy:0.0];
[transform rotateByDegrees:90.0];
[context saveGraphicsState];
[transform concat];
xOffSet =NSMinY(rect) + ((gHeight/2.0) - [ylabel size].width/2.0);
labelHere = NSMakePoint( xOffSet, NSMinY(rect) +[ylabel
size].height) ;
[ylabel drawAtPoint:labelHere];
[context restoreGraphicsState];
}
}
yLabel is a NSAttributed String
gHeight is the height of rect.
rect is a bounding rect for the graph that is smaller than the frame
of the NSView.
yLabel doesn't appear in the NSView
What am I doing wrong here
Any rotation is with respect to the origin of the coordinate system.
Thus, to rotate about a given point, you need to make that point the
origin, perform the rotation, then translate back to the actual
position you want to draw.
Thus (typed into mail):
NSAffineTransform* transform = [NSAffineTransform transform];
[transform translateXBy:myPoint.x yBy:myPoint.y];
[transform rotateByDegrees:90];
[transform translateXBy:-myPoint.x yBy:-myPoint.y];
[transform concat];
[myAttributedString drawAtPoint:myPoint];
Note that the translation to the origin and back is apparently back-to-
front. Transforms are like that - I find it sometimes helps to read
the series of translate/scale/rotate operations in reverse order to
get an idea of what it does as if in a series of steps.
Anyway, in your code you need to figure the origin of your drawing
rect and do the above. Your code refers to 'gRect' but uses 'rect' -
not clear if that's intentional or what it means. But if your label is
drawn in the rect 'rect' then you should be able to use that
information alone to handle the rotation, so I'm not sure what gRect
is or how it's being used.
Anyhoo, hope that helps.
Here's some code I have in my current app that does something similar,
labelling the axes of a grid. It refers to other methods and so on not
shown here, but will give you an idea of how I do the rotation. One
thing to note is that I do all of the positioning calculations ahead
of doing the rotation/drawing. Also, <aRect> is the updateRect that
originates in the view's -drawRect: method, not the box in which I
draw the text. This also handles both X and Y axes, hence the added
complication ;-)
- (void) drawAnnotationElement:(unsigned) indx maxElement:(unsigned)
max inRect:(NSRect) aRect atEdge:(DKOGridEdge) edge
{
//<indx> is the ordinal item to draw, starting from 0. The actual
drawn element factors in the offset and increment. <edge> specifies
which edge(s) the annotation
// should be drawn at. It will be left or right. For vertical
annotation left == top, right == bottom.
if( edge == 0 )
return; // nothing to do
NSString* str = [self annotationStringForElement:indx maxElement:max];
NSAttributedString* std = [[NSAttributedString alloc]
initWithString:str attributes:[self textAttributes]];
NSRect bbox, ir;
// get the bounding box for the string
bbox.size = [std size];
ir = [mGridRef borderRect];
// swap the box width/height if rotated
if([self isRotated])
{
float temp = bbox.size.width;
bbox.size.width = bbox.size.height;
bbox.size.height = temp;
}
// position the box
float textOffset = [mGridRef borderAllowance] + mOffset;
float sd = [mGridRef spanLength];
if([self orientationIsVertical])
{
if( edge == kDKOLeftEdge )
bbox.origin.x = NSMinX( ir ) - bbox.size.width - textOffset;
else
bbox.origin.x = NSMaxX( ir ) + textOffset;
bbox.origin.y = ( NSMinY( ir ) + ( sd * indx )) - (bbox.size.height
* 0.5);
if([self placement] == kDKOPlaceAnnotationBetweenGrid )
bbox.origin.y += sd * 0.5;
// don't draw if beyond end of interior
if( bbox.origin.y > NSMaxY( ir ))
return;
}
else
{
if( edge == kDKOLeftEdge )
bbox.origin.y = NSMinY( ir ) - bbox.size.height - ( textOffset *
0.7);
else
bbox.origin.y = NSMaxY( ir ) + ( textOffset * 0.7 );
bbox.origin.x = ( NSMinX( ir ) + ( sd * indx )) - (bbox.size.width *
0.5);
if([self placement] == kDKOPlaceAnnotationBetweenGrid )
bbox.origin.x += sd * 0.5;
if( bbox.origin.x > NSMaxX( ir ))
return;
}
// draw the text in the box
if( NSIntersectsRect( bbox, aRect ))
{
NSPoint origin = bbox.origin;
[NSGraphicsContext saveGraphicsState];
if([self isRotated])
{
NSAffineTransform* tfm = [NSAffineTransform transform];
if([self orientationIsVertical])
{
origin.x = NSMaxX( bbox );
[tfm translateXBy:origin.x yBy:origin.y];
[tfm rotateByDegrees:90];
[tfm translateXBy:-origin.x yBy:-origin.y];
}
else
{
origin.y = NSMaxY( bbox );
[tfm translateXBy:origin.x yBy:origin.y];
[tfm rotateByDegrees:-90];
[tfm translateXBy:-origin.x yBy:-origin.y];
}
[tfm concat];
}
[std drawAtPoint:origin];
[NSGraphicsContext restoreGraphicsState];
}
}
Graham
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden