I am using iOS Charts (Daniel Gindi) to generate graphs in an iOS app and I want to be able to generate a PDF report with those graphs included in the body of the report. Can anyone explain how to go about doing this. Ideally I don't want to generate an image from the UIView that shows in the app because the size/resolution would not be suitable for the PDF document.
As I understand it there are a few options:
It seems like option 1 is probably the preferred way to get best resolution/control - somewhat speculative - doing it this way means you should be able to specify the exact position and size and get the correct font sizes, line thicknesses, etc..
Using option 2 means you have to figure out the scaling between a UIView and the PDF page view and I am not sure how these would map to each other.
Can anyone provide any suggestions on the following:
OK so here is what I have done
Option 1: Using a UIView.layer to render on the PDF CGContect
func drawLineGraph(x: CGFloat, y: CGFloat)->CGRect{
let width = (pageSize.width - 2*kBorderInset - 2*kMarginInset)/2.0 - 50.0
let renderingRect = CGRect(x: x, y: y + 50.0, width: width, height: 150.0)
// Create a view for the Graph
let graphController = LineChartController(rect: renderingRect, building: self.building)
if let currentContext = UIGraphicsGetCurrentContext() {
let frame = graphController.chartView.frame
currentContext.saveGState()
currentContext.translateBy(x:frame.origin.x, y:frame.origin.y);
graphController.chartView.layer.render(in: currentContext)
currentContext.restoreGState()
}
return renderingRect
}
The graphController
is just an object that has essentially the same function as the usual parent ViewController
that would contain the graph. Sets the graph parameters and data.
Once that has been done the function below is called to render on the PDF page context.
A bit of translation required to put the graphs in the correct position.
Option 2: Drawing on the PDF Page CGContect
And the solution is...ta da...
func drawBarGraph(x: CGFloat, y: CGFloat)->CGRect{
let width = (pageSize.width - 2*kBorderInset - 2*kMarginInset)/2.0 - 50.0
let renderingRect = CGRect(x: x + width + 50, y: y + 50.0, width: width, height: 150.0)
// Create a view for the Graph
let graphController = BarChartController(rect: renderingRect, building: self.building)
if let currentContext = UIGraphicsGetCurrentContext() {
let frame = graphController.chartView.frame
currentContext.saveGState()
currentContext.translateBy(x:frame.origin.x, y:frame.origin.y)
//graphController.chartView.layer.render(in: currentContext)
graphController.chartView.draw(frame)
currentContext.restoreGState()
}
return renderingRect
}
Since the current context is set to the PDF page's context just call the charts draw()
function directly passing the frame rectangle.
What have I missed here, can it be this easy ?
You can find a copy of the generated PDF here as well as sample code.