I am trying to create the circles below in my iOS app. I know how to make the circles but am not entirely sure on how to get the points along the arc. It has to be in code not an image. Below is also the code I currently have.
- (void)drawRect:(CGRect)rect
{
CGPoint point;
point.x = self.bounds.origin.x + self.bounds.size.width/2;
point.y = self.bounds.origin.y + self.bounds.size.height/2;
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, 2.0);
CGContextSetStrokeColorWithColor(context, [UIColor blueColor].CGColor);
CGRect circle = CGRectMake(point.x/2,point.y-point.x/2,point.x,point.x);
CGContextAddEllipseInRect(context, circle);
CGContextStrokePath(context);
for (int i = 0; i<8; i++) {
CGRect circleMini = CGRectMake(??????,??????,point.x/4,point.x/4);
CGContextAddEllipseInRect(context, circleMini);
CGContextStrokePath(context);
}
}
UPDATED TO ANSWER
float cita = 0;
for (int i = 0; i<8; i++) {
CGPoint pointCir = CGPointMake(point.x/2 + radius * cos(cita) , (point.y-point.x/2) + radius * sin(cita) );
CGRect circleMini = CGRectMake(pointCir.x,pointCir.y,radius/4,radius/4);
CGContextAddEllipseInRect(context, circleMini);
CGContextStrokePath(context);
cita += M_PI / 4.0;
}
If (x,y) is the center and r is the radius of your big circle, the center of the i-th external circle will be:
center(i) = ( x + r * cos(cita) , y + r * sin(cita) )
Start cita in 0 and increment it PI/4 radians for the next circle (or 45 degrees)
Working implementation
CGFloat cita = 0;
CGFloat bigCircleRadius = point.x / 2.0;
CGFloat smallCircleRadius = bigCircleRadius / 4.0;
for (int i = 0; i < 8; i++) {
CGPoint smallCircleCenter = CGPointMake(point.x + bigCircleRadius * cos(cita) - smallCircleRadius/2.0 , point.y + bigCircleRadius * sin(cita) - smallCircleRadius / 2.0 );
CGRect smallCircleRect = CGRectMake(smallCircleCenter.x,smallCircleCenter.y,smallCircleRadius,smallCircleRadius);
CGContextAddEllipseInRect(context, smallCircleRect);
CGContextStrokePath(context);
cita += M_PI / 4.0;
}
Edit: Added implementation and renamed variables.
- (void)drawRect:(CGRect)rect
{
const NSUInteger kNumCircles = 8u;
CGFloat height = CGRectGetHeight(rect);
CGFloat smallCircleRadius = height / 10.0f;
CGRect bigCircleRect = CGRectInset(rect, smallCircleRadius / 2.0f, smallCircleRadius / 2.0f);
CGFloat bigCircleRadius = CGRectGetHeight(bigCircleRect) / 2.0f;
CGPoint rectCenter = CGPointMake(CGRectGetMidX(rect), CGRectGetMidY(rect));
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, 2.0f);
CGContextSetStrokeColorWithColor(context, [UIColor blueColor].CGColor);
CGContextAddEllipseInRect(context, bigCircleRect);
CGContextStrokePath(context);
CGFloat alpha = 0;
for (NSUInteger i = 0; i < kNumCircles; i++)
{
CGPoint smallCircleCenter = CGPointMake(rectCenter.x + bigCircleRadius * cos(alpha) - smallCircleRadius/2.0f , rectCenter.y + bigCircleRadius * sin(alpha) - smallCircleRadius / 2.0f );
CGRect smallCircleRect = CGRectMake(smallCircleCenter.x,smallCircleCenter.y,smallCircleRadius,smallCircleRadius);
CGContextAddEllipseInRect(context, smallCircleRect);
CGContextStrokePath(context);
alpha += M_PI / (kNumCircles / 2.0f);
}
}
Related
I used CGContext to draw dashed lines in iOS.
My code is as follow.
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetStrokeColorWithColor(context, [UIColor redColor].CGColor);
CGFloat dashes[] = {5,5};
CGContextSetLineDash(context, 0, dashes, 2);
float startx = x_percentileValues[0];
float starty = orgy-numskipPixels_v*(3-minWeight);
for(int i=0; i<[MeasuredInfos.retval count]; i++) {
float x = numskipPixels_h*hoursBetweenDates*3+orgx;
float y = orgy-([[MeasuredInfos.retval objectAtIndex: i] getWeight] - minWeight)*numskipPixels_v;
CGContextMoveToPoint(context, startx, starty);
CGContextAddLineToPoint(context, x, y);
CGContextStrokePath(context);
startx = x;
starty = y;
}
It is fine if the slope of the line is steep. If not steep, the dashed line has problem as shown in the attached pictures.
I checked in this link, nothing much discussion for the CGContextSetLineDash.
I found the problem. The problem is that I used two CGContextRef in two separate functions. One is in
- (void)drawRect:(CGRect)rect {
//Get the CGContext from this view
CGContextRef context = UIGraphicsGetCurrentContext();
//Set the stroke (pen) color
CGContextSetStrokeColorWithColor(context, [UIColor whiteColor].CGColor);
//Set the width of the pen mark
CGContextSetLineWidth(context, 2.0);
float startx = x_percentileValues[0];
float starty = orgy-numskipPixels_v*(3-minWeight);
for(int i=0; i<[MeasuredInfos.retval count]; i++) {
float x = numskipPixels_h*hoursBetweenDates*3+orgx;
float y = orgy-([[MeasuredInfos.retval objectAtIndex: i] getWeight] - minWeight)*numskipPixels_v;
CGContextMoveToPoint(context, startx, starty);
CGContextAddLineToPoint(context, x, y);
CGContextStrokePath(context);
startx = x;
starty = y;
[self drawStar_atX:x andatY:y];
}
}
Another one in drawStar_atX
-(void)drawStar_atX:(float)xCenter andatY:(float)yCenter
{
int aSize = 5.0;
CGFloat color[4] = { 1.0, 0.0, 0.0, 1.0 }; // Red
CGColorRef aColor = CGColorCreate(CGColorSpaceCreateDeviceRGB(), color);
CGContextRef context1 = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context1, aSize);
float w = 15.0;
double r = w / 2.0;
float flip = -1.0;
CGContextSetFillColorWithColor(context1, aColor);
CGContextSetStrokeColorWithColor(context1, aColor);
double theta = 2.0 * M_PI * (2.0 / 5.0); // 144 degrees
CGContextMoveToPoint(context1, xCenter, r*flip+yCenter);
for (NSUInteger k=1; k<5; k++)
{
float x = r * sin(k * theta);
float y = r * cos(k * theta);
CGContextAddLineToPoint(context1, x+xCenter, y*flip+yCenter);
}
CGContextClosePath(context1);
CGContextFillPath(context1);
return;
}
I called drawStar_atX from drawRect. context and context1 in two functions have some problems and start from the second segment the dashed line's width becomes bigger. Actually they are declared in different functions with different widths, shouldn't have any relationship. Now I solved the problem as context and context1 has same width. Still learning why they have some relations.
Currently I am developing an Expense Management App. In this app, I want retrive data from the local database and make a pdf file for it in a tabular format.Guidance needed on how should I proceed on doing this.
Thanks.
You can create table in PDF by following below steps:
Step 1. Create UIGraphics PDF Context:
UIGraphicsBeginPDFContextToFile(filePath, CGRectZero, nil);
UIGraphicsBeginPDFPageWithInfo(CGRectMake(0, 0, kPageWidth, kPageHeight), nil);
[self drawTableAt:CGPointMake(6,38) withRowHeight:30 andColumnWidth:120 andRowCount:kRowsPerPage andColumnCount:5];
UIGraphicsEndPDFContext();
Step 2. Add these two helper functions to the same file (or same class implementation):
-(void)drawTableAt: (CGPoint)origin withRowHeight: (int)rowHeight andColumnWidth: (int)columnWidth andRowCount: (int)numberOfRows andColumnCount:(int)numberOfColumns{
for (int i = 0; i <= numberOfRows; i++) {
int newOrigin = origin.y + (rowHeight*i);
CGPoint from = CGPointMake(origin.x, newOrigin);
CGPoint to = CGPointMake(origin.x + (numberOfColumns*columnWidth), newOrigin);
[self drawLineFromPoint:from toPoint:to];
}
for (int i = 0; i <= numberOfColumns; i++) {
int newOrigin;
if(i==0){
newOrigin = origin.x ;
}
if(i==1){
newOrigin = origin.x + 30;
}
if(i==2){
newOrigin = origin.x + 150;
}
if(i==3){
newOrigin = origin.x + 270;
}
if(i==4){
newOrigin = origin.x + 480;
}
// newOrigin = origin.x + (columnWidth*i);
CGPoint from = CGPointMake(newOrigin, origin.y);
CGPoint to = CGPointMake(newOrigin, origin.y +(numberOfRows*rowHeight));
[self drawLineFromPoint:from toPoint:to];
}
}
-(void)drawLineFromPoint:(CGPoint)from toPoint:(CGPoint)to
{
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, 2.0);
CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
CGFloat components[] = {0.2, 0.2, 0.2, 0.3};
CGColorRef color = CGColorCreate(colorspace, components);
CGContextSetStrokeColorWithColor(context, color);
CGContextMoveToPoint(context, from.x, from.y);
CGContextAddLineToPoint(context, to.x, to.y);
CGContextStrokePath(context);
CGColorSpaceRelease(colorspace);
CGColorRelease(color);
}
How about this tutorial. Exactly what you needed. Create the Table format
http://www.raywenderlich.com/6581/how-to-create-a-pdf-with-quartz-2d-in-ios-5-tutorial-part-1
http://www.raywenderlich.com/6818/how-to-create-a-pdf-with-quartz-2d-in-ios-5-tutorial-part-2
I have an issue with drawing the following diagram.
First I draw the grid lines with CGContextMoveToPoint, CGContextAddLineToPoint and CGContextStrokePath. Afterwards, I draw the diagram bars with CGContextFillRect.
Why are the lines drawn above the diagram bars?
Here is the requested code. A bit more complex, because I want to support a couple of diagram configurations.
- (void)drawRect:(CGRect)rect
{
[super drawRect:rect];
CGContextRef context = UIGraphicsGetCurrentContext();
CGRect rectHistView = self.bounds;
CGFloat red, green, blue, alpha;
NSUInteger valueIndex = 0;
CGFloat histX, histY, histHeight;
CGFloat gridX, gridY, gridHeight;
NSString *txt;
CGSize txtSize;
// Initialize font color and set font drawing mode
CGContextSetTextDrawingMode(context, kCGTextFill);
NSDictionary *attrDictAxisValues = #{NSFontAttributeName:[UIFont systemFontOfSize:cfgAxisValuesFontSize],
NSForegroundColorAttributeName:cfgColorAxisValues};
NSDictionary *attrDictBarValues = #{NSFontAttributeName:[UIFont systemFontOfSize:cfgAxisValuesFontSize],
NSForegroundColorAttributeName:cfgColorBarValues};
// Calculate bar width and gap offset
CGFloat histWidth = rectHistView.size.width / [histValues count];
CGFloat histMaxViewHeight = bCfgShowXAxisValues ? rectHistView.size.height - cfgAxisValuesFontSize : rectHistView.size.height;
CGFloat gapOffset = histWidth * cfgBarGapPercentage / 2;
//--------------------------------------------------------
// Draw y-grid
//--------------------------------------------------------
if (bCfgShowYGrid) {
CGContextSetStrokeColorWithColor(context, HIST_CFG_UICOLOR_GRID.CGColor);
CGContextSetLineWidth(context, HIST_CFG_LINE_WIDTH_GRID);
gridHeight = bCfgShowBarValues ? histMaxViewHeight - cfgAxisValuesFontSize - HIST_CFG_FONT_GAP: histMaxViewHeight;
for (int y = 1; y <= histValueMax; y++) {
gridY = bCfgShowXAxisValues ? rectHistView.origin.y + rectHistView.size.height - (gridHeight * y / histValueMax) - cfgAxisValuesFontSize
: rectHistView.origin.y + rectHistView.size.height - (gridHeight * y / histValueMax);
CGContextMoveToPoint(context, rectHistView.origin.x, gridY);
CGContextAddLineToPoint(context, rectHistView.origin.x + rectHistView.size.width, gridY);
}
CGContextStrokePath(context);
}
//--------------------------------------------------------
// Draw histogram
//--------------------------------------------------------
for (NSString *val in histValues) {
histX = rectHistView.origin.x + (valueIndex * histWidth);
histHeight = bCfgShowBarValues ? (histMaxViewHeight - cfgAxisValuesFontSize - HIST_CFG_FONT_GAP) * [val floatValue] / histValueMax
: histMaxViewHeight * [val floatValue] / histValueMax;
histY = bCfgShowXAxisValues ? rectHistView.origin.y + rectHistView.size.height - histHeight - cfgAxisValuesFontSize
: rectHistView.origin.y + rectHistView.size.height - histHeight;
// draw x-grid
if (bCfgShowXGrid) {
gridX = rectHistView.origin.x + ((valueIndex+1) * histWidth);
gridY = bCfgShowXAxisValues ? rectHistView.origin.y + rectHistView.size.height - cfgAxisValuesFontSize
: rectHistView.origin.y + rectHistView.size.height;
CGContextSetStrokeColorWithColor(context, HIST_CFG_UICOLOR_GRID.CGColor);
CGContextSetLineWidth(context, HIST_CFG_LINE_WIDTH_GRID);
CGContextMoveToPoint(context, gridX, bCfgShowBarValues ? rectHistView.origin.y + cfgAxisValuesFontSize + HIST_CFG_FONT_GAP
: rectHistView.origin.y);
CGContextAddLineToPoint(context, gridX, gridY);
CGContextStrokePath(context);
}
// draw x-axis values
if (bCfgShowXAxisValues) {
txt = [NSString stringWithFormat:#"%lu", (unsigned long)valueIndex];
txtSize = [txt sizeWithAttributes:attrDictAxisValues];
[txt drawAtPoint:CGPointMake(rectHistView.origin.x + (valueIndex * histWidth) + (histWidth / 2.0f - txtSize.width / 2.0f),
rectHistView.origin.y + rectHistView.size.height - cfgAxisValuesFontSize)
withAttributes:attrDictAxisValues];
}
// get color from array
UIColor *color = [histColor objectAtIndex:valueIndex];
[color getRed:&red green:&green blue:&blue alpha:&alpha];
// draw histogram bar
CGContextSetRGBFillColor(context, red, green, blue, alpha);
CGContextFillRect(context, CGRectMake(histX+gapOffset, histY, histWidth-(2*gapOffset), histHeight));
// draw histogram bar values
if (bCfgShowBarValues) {
if (bCfgShowZeroBarValues || [val intValue] > 0) { // skip zero values if configured
txt = [NSString stringWithFormat:#"%d", [val intValue]];
CGSize txtSize = [txt sizeWithAttributes:attrDictBarValues];
[txt drawAtPoint:CGPointMake(rectHistView.origin.x + (valueIndex * histWidth) + (histWidth / 2.0f - txtSize.width / 2.0f),
histY - cfgAxisValuesFontSize - HIST_CFG_FONT_GAP)
withAttributes:attrDictBarValues];
}
}
valueIndex++;
}
//--------------------------------------------------------
// Draw diagram axis
//--------------------------------------------------------
CGContextSetStrokeColorWithColor(context, HIST_CFG_UICOLOR_AXIS.CGColor);
CGContextSetLineWidth(context, HIST_CFG_LINE_WIDTH_AXIS);
// draw y-axis
if (bCfgShowYAxis) {
CGContextMoveToPoint(context, rectHistView.origin.x,
bCfgShowBarValues ? rectHistView.origin.y + cfgAxisValuesFontSize + HIST_CFG_FONT_GAP: rectHistView.origin.y);
CGContextAddLineToPoint(context, rectHistView.origin.x, rectHistView.origin.y + histMaxViewHeight);
CGContextStrokePath(context);
}
// draw x-axis
if (bCfgShowXAxis) {
histY = bCfgShowXAxisValues ? rectHistView.origin.y + rectHistView.size.height - cfgAxisValuesFontSize
: rectHistView.origin.y + rectHistView.size.height;
CGContextMoveToPoint(context, rectHistView.origin.x, histY);
CGContextAddLineToPoint(context, rectHistView.origin.x + rectHistView.size.width, histY);
CGContextStrokePath(context);
}
}
I am drawing annotations on a view. The approach i am using to draw star is below.
-(void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, 2.0);
CGFloat xCenter = rect.size.width / 2;
CGFloat yCenter = rect.size.height / 2;
float width;
if(rect.size.width > rect.size.height) {
width = rect.size.height;
} else {
width = rect.size.width;
}
double r = width / 2.0;
float flip = -1.0;
double theta = 2.0 * M_PI * (2.0 / 5.0); // 144 degrees
CGContextMoveToPoint(context, xCenter, r*flip+yCenter);
for (NSUInteger k=1; k<5; k++)
{
float x = r * sin(k * theta);
float y = r * cos(k * theta);
CGContextAddLineToPoint(context, x+xCenter, y*flip+yCenter);
}
CGContextSetStrokeColorWithColor(context, self.color.CGColor);
CGContextClosePath(context);
CGContextStrokePath(context);
}
I want to have just borders of star removing other inner lines is there any way to achieve that? (apart from using moveToPoint and addLine methods)
use this code:
-(void)drawRect:(CGRect)rect
{
int aSize = 100.0;
float color[4] = { 0.0, 0.0, 1.0, 1.0 }; // Blue
CGColorRef aColor = CGColorCreate(CGColorSpaceCreateDeviceRGB(), color);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, aSize);
CGFloat xCenter = 100.0;
CGFloat yCenter = 100.0;
float w = 100.0;
double r = w / 2.0;
float flip = -1.0;
CGContextSetFillColorWithColor(context, aColor);
CGContextSetStrokeColorWithColor(context, aColor);
double theta = 2.0 * M_PI * (2.0 / 5.0); // 144 degrees
CGContextMoveToPoint(context, xCenter, r*flip+yCenter);
for (NSUInteger k=1; k<5; k++)
{
float x = r * sin(k * theta);
float y = r * cos(k * theta);
CGContextAddLineToPoint(context, x+xCenter, y*flip+yCenter);
}
CGContextClosePath(context);
CGContextFillPath(context);
}
This will create 1 blue star
With use of the UIBezierPath you can work with that in Swift 4.
let polygonPath = UIBezierPath()
let xCenter: CGFloat = 0
let yCenter: CGFloat = 0
let w = CGFloat(300)
let r = w / 2.0
let flip: CGFloat = -1.0 // use this to flip the figure 1.0 or -1.0
let polySide = CGFloat(5)
let theta = 2.0 * Double.pi * Double(2.0 / polySide)
polygonPath.move(to: CGPoint(x: xCenter, y: r * flip + yCenter))
for i in 1..<Int(polySide) {
let x: CGFloat = r * CGFloat( sin(Double(i) * theta) )
let y: CGFloat = r * CGFloat( cos(Double(i) * theta) )
polygonPath.addLine(to: CGPoint(x: x + xCenter, y: y * flip + yCenter))
}
polygonPath.close()
You can draw star by using this code:
UIBezierPath* starPath = UIBezierPath.bezierPath;
[starPath moveToPoint: CGPointMake(90, 31)];
[starPath addLineToPoint: CGPointMake(98.11, 42.06)];
[starPath addLineToPoint: CGPointMake(111.87, 45.86)];
[starPath addLineToPoint: CGPointMake(103.12, 56.49)];
[starPath addLineToPoint: CGPointMake(103.52, 69.89)];
[starPath addLineToPoint: CGPointMake(90, 65.4)];
[starPath addLineToPoint: CGPointMake(76.48, 69.89)];
[starPath addLineToPoint: CGPointMake(76.88, 56.49)];
[starPath addLineToPoint: CGPointMake(68.13, 45.86)];
[starPath addLineToPoint: CGPointMake(81.89, 42.06)];
[starPath closePath];
[UIColor.grayColor setFill];
[starPath fill];
I'm trying to draw a simple speech bubble using the following code:
#implementation SpeechBubbleView
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
self.backgroundColor = [UIColor clearColor];
}
return self;
}
- (void)drawRect:(CGRect)rect {
CGPoint triangleHeadPoint = CGPointMake(0, rect.size.height/2.0);
float triangleHeight = 5;
float triangleWidth = 10;
float maxX = rect.size.width;
float minX = 0.0;
float maxY = rect.size.height;
float minY = 0.0;
float archTangentLine = 6.0;
float archRadius = archTangentLine;
float strokeWidth = 1.0;
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, strokeWidth);
CGContextBeginPath(context);
float currentX = triangleHeadPoint.x;
float currentY = triangleHeadPoint.y;
CGContextMoveToPoint(context, currentX, currentY);
currentX += triangleWidth;
currentY += (triangleHeight / 2.0);
CGContextAddLineToPoint(context, currentX, currentY);
currentY = maxY - archTangentLine;
CGContextAddLineToPoint(context, currentX, currentY);
currentY += archTangentLine;
CGContextAddArcToPoint(context, currentX, currentY, currentX + archTangentLine, currentY, archRadius);
currentX = maxX - archTangentLine;
CGContextAddLineToPoint(context, currentX, currentY);
currentX += archTangentLine;
CGContextAddArcToPoint(context, currentX, currentY, currentX, currentY - archTangentLine, archRadius);
currentY = minY + archTangentLine;
CGContextAddLineToPoint(context, currentX, currentY);
currentY -= archTangentLine;
CGContextAddArcToPoint(context, currentX, currentY, currentX - archTangentLine, currentY, archRadius);
currentX = minX + triangleWidth + archTangentLine;
CGContextAddLineToPoint(context, currentX, currentY);
currentX -= archTangentLine;
CGContextAddArcToPoint(context, currentX, currentY, currentX, currentY + archTangentLine, archRadius);
currentY = triangleHeadPoint.y - (triangleHeight / 2.0);
CGContextAddLineToPoint(context, currentX, currentY);
CGContextClosePath(context);
[[UIColor whiteColor] setFill];
[[UIColor blackColor] setStroke];
CGContextDrawPath(context, kCGPathFillStroke);
}
#end
The result of this code is the following (not so pretty) image:
The drawing isn't as smooth as I was expecting it to be, the left side border is wider than the top, right and bottom sides, and the corners are wider than the adjacent lines.
I changed the fill color to black just to check and the result is as I was expecting:
Why does the border have a variable width? Is there a way to fix this and have a smooth border around the view?
Thanks in advance.
For future reference, I have found a way to improve the look of the border which will result in the following picture:
I simply made the border width very small (I used 0.2f) using the function CGContextSetLineWidth(context, 0.2f). And then added a shadow to the layer as following:
self.layer.shadowColor = [[UIColor blackColor] CGColor];
self.layer.shadowOffset = CGSizeMake(1.5f, 1.5f);
self.layer.shadowOpacity = 0.8f;
self.layer.shadowRadius = 1.0f;
And that's it!