I'm using CPTGraphHostingView in a Mac app and needed to be able to
print the contents of the graph. After a bit of digging on
StackOverflow and this discussion group, I came up the the following
subclass (called GraphHostingView.) The subclass adds a new property
called "printRect" and overrides some methods needed to print a view.
From your document's view controller, you'd do something like this:
- (IBAction)printDocument:(id)sender
{
DebugLog(@"%s called", __PRETTY_FUNCTION__);
NSPrintInfo *printInfo = self.printInfo;
NSRect printRect = NSZeroRect;
printRect.size.width = (printInfo.paperSize.width -
printInfo.leftMargin - printInfo.rightMargin) *
printInfo.scalingFactor;
printRect.size.height = (printInfo.paperSize.height -
printInfo.topMargin - printInfo.bottomMargin) *
printInfo.scalingFactor;
graphHostingView.printRect = printRect;
NSPrintOperation *printOperation = [NSPrintOperation
printOperationWithView:graphHostingView printInfo:printInfo];
[printOperation runOperationModalForWindow:self.window delegate:self
didRunSelector:@selector(printOperationDidRun:success:contextInfo:)
contextInfo:NULL];
}
The implementation of GraphHostingView follows. I'd like to see these
changes get added to CPTGraphHostingView (you have my permission to
use this code however you wish.)
==== GraphHostingView.h ====
#import <CorePlot/CorePlot.h>
@interface GraphHostingView : CPTGraphHostingView
{
NSRect printRect;
}
@property (nonatomic, assign) NSRect printRect;
@end
==== GraphHostingView.m ====
#import "GraphHostingView.h"
@implementation GraphHostingView
@synthesize printRect;
- (void)drawRect:(NSRect)dirtyRect
{
[super drawRect:dirtyRect];
if (! [NSGraphicsContext currentContextDrawingToScreen]) {
NSGraphicsContext *graphicsContext = [NSGraphicsContext
currentContext];
[graphicsContext saveGraphicsState];
NSRect destinationRect = self.printRect;
NSRect sourceRect = self.frame;
// scale the view isotropically so that it fits on the printed page
CGFloat widthScale = destinationRect.size.width /
sourceRect.size.width;
CGFloat heightScale = destinationRect.size.height /
sourceRect.size.height;
CGFloat scale = MIN(widthScale, heightScale);
// position the view so that its centered on the printed page
CGPoint offset = NSZeroPoint;
offset.x = ((destinationRect.size.width - (sourceRect.size.width *
scale)) / 2.0) + destinationRect.origin.x;
offset.y = ((destinationRect.size.height - (sourceRect.size.height *
scale)) / 2.0) + destinationRect.origin.y;
NSAffineTransform *transform = [NSAffineTransform transform];
[transform translateXBy:offset.x yBy:offset.y];
[transform scaleBy:scale];
[transform concat];
// render CPTLayers recursively into the graphics context used for
printing (thanks to Brad for the tip:
http://stackoverflow.com/a/2791305/132867
)
CGContextRef context = [graphicsContext graphicsPort];
[self.hostedGraph recursivelyRenderInContext:context];
[graphicsContext restoreGraphicsState];
}
}
- (BOOL)knowsPageRange:(NSRangePointer)rangePointer
{
rangePointer->location = 1;
rangePointer->length = 1;
return YES;
}
- (NSRect)rectForPage:(NSInteger)pageNumber
{
return self.printRect;
}
@end