I'm using CorePlot to draw PieChart. I would like to display labels for slices on slices themselves. Is there a way to get coordinates of each slice and then setting the frame of CPTLayer that holds the text label to adjust to coordinates of the slice?
What I am doing so far:
-(CPRLayer*) datLabelForPlot(CPTPlot*)plot recordIndex:(NSUInteger)index {
static CPTMutableTextStyle *textStyle = nil;
NSString *string = #"Test";
if ( !textStyle) {
textStyle= [[CPTMutableTextStyle alloc] init];
textStyle.color = [CPTColor whiteColor];
}
CPTLayer *layer = [[[CPTLayer alloc] initWithFrame:CGRectMake(50,50, 100, 20)]autorelease];
CPTTextLayer *newLayer = nil;
newLayer = [[[CPTTextLayer alloc] initWithText:string style:textStyle] autorelease];
[layer addSublayer:newLayer];
return layer;
}
but regardless of the layer frame, label is always displayed at the same position (outside the chart). How to set the appropriate layer frame to display the text on the slice itself?
Here is the image of the points I would like to know:
Have you tried setting the CPPieChart labelOffset property to a negative value? May be it doesn't provide the level of precision that you need, but it's an easy solution.
Positive Offset:
Negative Offset:
The centerAnchor is expressed as a fraction of the size of the plot area, so you can use the following code to compute its pixel position (point "O" on your picture):
CPTPieChart *pieChart; // the pie chart
CGRect plotAreaBounds = pieChart.plotArea.bounds;
CGPoint anchor = pieChart.centerAnchor;
CGPoint centerPoint = CGPointMake(plotAreaBounds.origin.x + plotAreaBounds.size.width * anchor.x,
plotAreaBounds.origin.y + plotAreaBounds.size.height * anchor.y);
You can look at the Core Plot source code to see how the pie chart computes the positions of the labels. This code accounts for slices that are "exploded" and centers the label between what you called points "A" and "B", offset by the labelOffset. It hides the label if the datasource returned a missing value (NAN) for the slice. The index corresponds to the datasource index of the pie slice. The relevant bits are:
double currentWidth = [self cachedDoubleForField:CPTPieChartFieldSliceWidthNormalized recordIndex:index];
if ( isnan(currentWidth) ) {
contentLayer.hidden = YES;
}
else {
id<CPTPieChartDataSource> theDataSource = id<CPTPieChartDataSource>)self.dataSource;
BOOL dataSourceProvidesRadialOffsets = [theDataSource respondsToSelector:#selector(radialOffsetForPieChart:recordIndex:)];
CGFloat radialOffset = 0.0;
if ( dataSourceProvidesRadialOffsets ) {
radialOffset = [theDataSource radialOffsetForPieChart:self recordIndex:index];
}
CGFloat labelRadius = self.pieRadius + self.labelOffset + radialOffset;
double startingWidth = 0.0;
if ( index > 0 ) {
startingWidth = [self cachedDoubleForField:CPTPieChartFieldSliceWidthSum recordIndex:index - 1];
}
CGFloat labelAngle = [self radiansForPieSliceValue:startingWidth + currentWidth / (CGFloat)2.0];
label.displacement = CGPointMake( labelRadius * cos(labelAngle), labelRadius * sin(labelAngle) );
contentLayer.hidden = NO;
}
Related
I'm using Shinobi iOS control for drawing line charts in my app. I'm currently rendering a serious of 0s value. The resulting graph is like that:
Now, the problem is that the quantity I'm representing is a currency so it cannot be negative. How can I limit the range to start from 0 in this specific case?
This is how I create the graph:
// initiatialise line chart
ShinobiChart *chartView = [[ShinobiChart alloc]initWithFrame:frame];
chartView.clipsToBounds = NO;
//Choose the light theme for this chart
SChartLightTheme *theme = [SChartLightTheme new];
//perform any theme stylign here before applying to the chart
chartView.theme = theme;
chartView.title = #"my Title";
chartView.autoresizingMask = UIViewAutoresizingNone;
// Use a number axis for the x axis.
SChartDateTimeAxis *xAxis = [[SChartDateTimeAxis alloc] init];
xAxis.title = #"date";
xAxis.tickLabelClippingModeHigh = SChartTickLabelClippingModeTicksAndLabelsPersist;
//keep tick marks at the right end
//Make some space at the axis limits to prevent clipping of the datapoints
xAxis.rangePaddingHigh = [SChartDateFrequency dateFrequencyWithDay:1];
xAxis.rangePaddingLow = [SChartDateFrequency dateFrequencyWithDay:1];
//allow zooming and panning
xAxis.enableGesturePanning = YES;
xAxis.enableGestureZooming = YES;
xAxis.enableMomentumPanning = YES;
xAxis.enableMomentumZooming = YES;
chartView.xAxis = xAxis;
// Use a number axis for the y axis.
SChartNumberAxis *yAxis = [[SChartNumberAxis alloc] init];
yAxis.title = #"Value";
yAxis.enableGesturePanning = YES;
yAxis.enableGestureZooming = YES;
yAxis.enableMomentumPanning = YES;
yAxis.enableMomentumZooming = YES;
yAxis.title = #"Value";
yAxis.style.titleStyle.position = SChartTitlePositionBottomOrLeft;
chartView.yAxis = yAxis;
chartView.userInteractionEnabled = YES;
chartView.gesturePanType = SChartGesturePanTypeNone;
yAxis.anchorPoint = #0;
Set this and it should solve your issue.
I have a project in which I have to make a square and circles on a button clcik.
there are textfileds before button , on textfiled we give the value such as 45, on click on uibutton the action perform and 45 square will automatically adjust with the iphone scfreen itself.
suppose the screen size is 320 * 480 , so the square automatically adjust with the screen.
and if we give the value 300 on the Textfiled the 300 squares will create and adjust automatically on the screen.
It will Show like graph paper at one stage if we give value like 1500.
I dont have any idea how to do it and how to start and where to start.
I am just thinking that it will use Quartcore Framework , but I dont have any Idea from where I start the project what I search.
I want suggestions and idea from experts.
Any Idea or suggestions from experts would be highly welcome.
// Step 1 : Add QuartzCore.framework in your project
// Step 2 : Create following two files .h and .m
// Step 3 : How to Use
// Import your custom file
#import "myDrawingView.h"
// Create object and add to your viewcontroller
myDrawingView *obj = [[myDrawingView alloc] initWithFrame:self.view.frame];
[obj drawSquaresWithNumber:17 andSize:self.view.frame.size];
[self.view addSubview:obj];
//------------------------------------------------------
// filename : myDrawingView.h
#import <UIKit/UIKit.h>
#import <QuartzCore/QuartzCore.h>
#interface myDrawingView : UIView
{
int nSquares;
CGSize mazeSize;
}
- (void)drawSquaresWithNumber:(int)numberOfSquares andSize:(CGSize)screenSize;
#end
//------------------------------------------------------
// filename : myDrawingView.m
#import "myDrawingView.h"
#implementation myDrawingView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
}
return self;
}
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
// Drawing code
// Calculate height and width for each sqaure.
float area = mazeSize.height*mazeSize.width;
float squareSize = (area/nSquares)/100;
NSLog(#"row : %f %f",mazeSize.width/squareSize,mazeSize.height/squareSize);
int row, col;
row = ceil(mazeSize.width/squareSize);
col = ceil(mazeSize.height/squareSize);
float height = mazeSize.height/row;
float width = mazeSize.width/col;
NSLog(#"%d %d",row,col);
NSLog(#"h %f w %f",height,width);
NSLog(#"square size : %f",squareSize);
// Create Current Context To Draw
CGContextRef context = UIGraphicsGetCurrentContext();
// Draw Line
CGContextSetLineWidth(context, 0.5f);
CGContextSetFillColorWithColor(context, [myDrawingView randomColor].CGColor);
CGContextSetStrokeColorWithColor(context, [myDrawingView randomColor].CGColor);
int x ,y, cnt;
x = y = 0;
cnt = 1;
// A loop for number of squares
for(int i=0;i<row;i++)
{
for(int j=0;j<col;j++)
{
if(cnt<=nSquares)
{
CGRect rect = CGRectMake(x, y, width, height);
// Draws Squares
UIBezierPath *path = [UIBezierPath bezierPathWithRect:rect];
// To draw Oval uncomment
// UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:rect];
[path fill];
[path stroke];
}
x += width;
cnt++;
}
x = 0;
y += height;
}
}
+ (UIColor *) randomColor {
CGFloat red = arc4random()%256;
CGFloat blue = arc4random()%256;
CGFloat green = arc4random()%256;
return [UIColor colorWithRed:abs(red)/255.0f green:abs(green)/255.0f blue:abs(blue)/255.0f alpha:1.0];
}
- (void)drawSquaresWithNumber:(int)numberOfSquares andSize:(CGSize)screenSize
{
nSquares = numberOfSquares;
mazeSize = screenSize;
[self setNeedsDisplay];
}
#end
Create a button, a label and 2 textfield's (one for height, one for width). Set a 1pixel border on the label and set the width and height of the label to the screen size. Create an IBAction for the button and assign the width and height of the label based on the content inside the textfield's. This will create the square. To create the circle you can either use QuartzCore and set the corner radius to half of the height/width or you can draw this programatically. This is the quickest way to achieve what you are asking without getting too far into drawing on screen with GL and would be a good start for understanding how actions and inputs work.
I have a simple oval shape (comprised of CGMutablePaths) from which I'd like the user to be able to drag an object around it. Just wondering how complicated it is to do this, do I need to know a ton of math and physics, or is there some simple built in way that will allow me to do this? IE the user drags this object around the oval, and it orbits it.
This is an interesting problem. We want to drag an object, but constrain it to lie on a CGPath. You said you have “a simple oval shape”, but that's boring. Let's do it with a figure 8. It'll look like this when we're done:
So how do we do this? Given an arbitrary point, finding the nearest point on a Bezier spline is rather complicated. Let's do it by brute force. We'll just make an array of points closely spaced along the path. The object starts out on one of those points. As we try to drag the object, we'll look at the neighboring points. If either is nearer, we'll move the object to that neighbor point.
Even getting an array of closely-spaced points along a Bezier curve is not trivial, but there is a way to get Core Graphics to do it for us. We can use CGPathCreateCopyByDashingPath with a short dash pattern. This creates a new path with many short segments. We'll take the endpoints of each segment as our array of points.
That means we need to iterate over the elements of a CGPath. The only way to iterate over the elements of a CGPath is with the CGPathApply function, which takes a callback. It would be much nicer to iterate over path elements with a block, so let's add a category to UIBezierPath. We start by creating a new project using the “Single View Application” template, with ARC enabled. We add a category:
#interface UIBezierPath (forEachElement)
- (void)forEachElement:(void (^)(CGPathElement const *element))block;
#end
The implementation is very simple. We just pass the block as the info argument of the path applier function.
#import "UIBezierPath+forEachElement.h"
typedef void (^UIBezierPath_forEachElement_Block)(CGPathElement const *element);
#implementation UIBezierPath (forEachElement)
static void applyBlockToPathElement(void *info, CGPathElement const *element) {
__unsafe_unretained UIBezierPath_forEachElement_Block block = (__bridge UIBezierPath_forEachElement_Block)info;
block(element);
}
- (void)forEachElement:(void (^)(const CGPathElement *))block {
CGPathApply(self.CGPath, (__bridge void *)block, applyBlockToPathElement);
}
#end
For this toy project, we'll do everything else in the view controller. We'll need some instance variables:
#implementation ViewController {
We need an ivar to hold the path that the object follows.
UIBezierPath *path_;
It would be nice to see the path, so we'll use a CAShapeLayer to display it. (We need to add the QuartzCore framework to our target for this to work.)
CAShapeLayer *pathLayer_;
We'll need to store the array of points-along-the-path somewhere. Let's use an NSMutableData:
NSMutableData *pathPointsData_;
We'll want a pointer to the array of points, typed as a CGPoint pointer:
CGPoint const *pathPoints_;
And we need to know how many of those points there are:
NSInteger pathPointsCount_;
For the “object”, we'll have a draggable view on the screen. I'm calling it the “handle”:
UIView *handleView_;
We need to know which of the path points the handle is currently on:
NSInteger handlePathPointIndex_;
And while the pan gesture is active, we need to keep track of where the user has tried to drag the handle:
CGPoint desiredHandleCenter_;
}
Now we have to get to work initializing all those ivars! We can create our views and layers in viewDidLoad:
- (void)viewDidLoad {
[super viewDidLoad];
[self initPathLayer];
[self initHandleView];
[self initHandlePanGestureRecognizer];
}
We create the path-displaying layer like this:
- (void)initPathLayer {
pathLayer_ = [CAShapeLayer layer];
pathLayer_.lineWidth = 1;
pathLayer_.fillColor = nil;
pathLayer_.strokeColor = [UIColor blackColor].CGColor;
pathLayer_.lineCap = kCALineCapButt;
pathLayer_.lineJoin = kCALineJoinRound;
[self.view.layer addSublayer:pathLayer_];
}
Note that we haven't set the path layer's path yet! It's too soon to know the path at this time, because my view hasn't been laid out at its final size yet.
We'll draw a red circle for the handle:
- (void)initHandleView {
handlePathPointIndex_ = 0;
CGRect rect = CGRectMake(0, 0, 30, 30);
CAShapeLayer *circleLayer = [CAShapeLayer layer];
circleLayer.fillColor = nil;
circleLayer.strokeColor = [UIColor redColor].CGColor;
circleLayer.lineWidth = 2;
circleLayer.path = [UIBezierPath bezierPathWithOvalInRect:CGRectInset(rect, circleLayer.lineWidth, circleLayer.lineWidth)].CGPath;
circleLayer.frame = rect;
handleView_ = [[UIView alloc] initWithFrame:rect];
[handleView_.layer addSublayer:circleLayer];
[self.view addSubview:handleView_];
}
Again, it's too soon to know exactly where we'll need to put the handle on screen. We'll take care of that at view layout time.
We also need to attach a pan gesture recognizer to the handle:
- (void)initHandlePanGestureRecognizer {
UIPanGestureRecognizer *recognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(handleWasPanned:)];
[handleView_ addGestureRecognizer:recognizer];
}
At view layout time, we need to create the path based on the size of the view, compute the points along the path, make the path layer show the path, and make sure the handle is on the path:
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
[self createPath];
[self createPathPoints];
[self layoutPathLayer];
[self layoutHandleView];
}
In your question, you said you're using a “simple oval shape”, but that's boring. Let's draw a nice figure 8. Figuring out what I'm doing is left as an exercise for the reader:
- (void)createPath {
CGRect bounds = self.view.bounds;
CGFloat const radius = bounds.size.height / 6;
CGFloat const offset = 2 * radius * M_SQRT1_2;
CGPoint const topCenter = CGPointMake(CGRectGetMidX(bounds), CGRectGetMidY(bounds) - offset);
CGPoint const bottomCenter = { topCenter.x, CGRectGetMidY(bounds) + offset };
path_ = [UIBezierPath bezierPath];
[path_ addArcWithCenter:topCenter radius:radius startAngle:M_PI_4 endAngle:-M_PI - M_PI_4 clockwise:NO];
[path_ addArcWithCenter:bottomCenter radius:radius startAngle:-M_PI_4 endAngle:M_PI + M_PI_4 clockwise:YES];
[path_ closePath];
}
Next we're going to want to compute the array of points along that path. We'll need a helper routine to pick out the endpoint of each path element:
static CGPoint *lastPointOfPathElement(CGPathElement const *element) {
int index;
switch (element->type) {
case kCGPathElementMoveToPoint: index = 0; break;
case kCGPathElementAddCurveToPoint: index = 2; break;
case kCGPathElementAddLineToPoint: index = 0; break;
case kCGPathElementAddQuadCurveToPoint: index = 1; break;
case kCGPathElementCloseSubpath: index = NSNotFound; break;
}
return index == NSNotFound ? 0 : &element->points[index];
}
To find the points, we need to ask Core Graphics to “dash” the path:
- (void)createPathPoints {
CGPathRef cgDashedPath = CGPathCreateCopyByDashingPath(path_.CGPath, NULL, 0, (CGFloat[]){ 1.0f, 1.0f }, 2);
UIBezierPath *dashedPath = [UIBezierPath bezierPathWithCGPath:cgDashedPath];
CGPathRelease(cgDashedPath);
It turns out that when Core Graphics dashes the path, it can create segments that slightly overlap. We'll want to eliminate those by filtering out each point that's too close to its predecessor, so we'll define a minimum inter-point distance:
static CGFloat const kMinimumDistance = 0.1f;
To do the filtering, we'll need to keep track of that predecessor:
__block CGPoint priorPoint = { HUGE_VALF, HUGE_VALF };
We need to create the NSMutableData that will hold the CGPoints:
pathPointsData_ = [[NSMutableData alloc] init];
At last we're ready to iterate over the elements of the dashed path:
[dashedPath forEachElement:^(const CGPathElement *element) {
Each path element can be a “move-to”, a “line-to”, a “quadratic-curve-to”, a “curve-to” (which is a cubic curve), or a “close-path”. All of those except close-path define a segment endpoint, which we pick up with our helper function from earlier:
CGPoint *p = lastPointOfPathElement(element);
if (!p)
return;
If the endpoint is too close to the prior point, we discard it:
if (hypotf(p->x - priorPoint.x, p->y - priorPoint.y) < kMinimumDistance)
return;
Otherwise, we append it to the data and save it as the predecessor of the next endpoint:
[pathPointsData_ appendBytes:p length:sizeof *p];
priorPoint = *p;
}];
Now we can initialize our pathPoints_ and pathPointsCount_ ivars:
pathPoints_ = (CGPoint const *)pathPointsData_.bytes;
pathPointsCount_ = pathPointsData_.length / sizeof *pathPoints_;
But we have one more point we need to filter. The very first point along the path might be too close to the very last point. If so, we'll just discard the last point by decrementing the count:
if (pathPointsCount_ > 1 && hypotf(pathPoints_[0].x - priorPoint.x, pathPoints_[0].y - priorPoint.y) < kMinimumDistance) {
pathPointsCount_ -= 1;
}
}
Blammo. Point array created. Oh yeah, we also need to update the path layer. Brace yourself:
- (void)layoutPathLayer {
pathLayer_.path = path_.CGPath;
pathLayer_.frame = self.view.bounds;
}
Now we can worry about dragging the handle around and making sure it stays on the path. The pan gesture recognizer sends this action:
- (void)handleWasPanned:(UIPanGestureRecognizer *)recognizer {
switch (recognizer.state) {
If this is the start of the pan (drag), we just want to save the starting location of the handle as its desired location:
case UIGestureRecognizerStateBegan: {
desiredHandleCenter_ = handleView_.center;
break;
}
Otherwise, we need to update the desired location based on the drag, and then slide the handle along the path toward the new desired location:
case UIGestureRecognizerStateChanged:
case UIGestureRecognizerStateEnded:
case UIGestureRecognizerStateCancelled: {
CGPoint translation = [recognizer translationInView:self.view];
desiredHandleCenter_.x += translation.x;
desiredHandleCenter_.y += translation.y;
[self moveHandleTowardPoint:desiredHandleCenter_];
break;
}
We put in a default clause so clang won't warn us about the other states that we don't care about:
default:
break;
}
Finally we reset the translation of the gesture recognizer:
[recognizer setTranslation:CGPointZero inView:self.view];
}
So how do we move the handle toward a point? We want to slide it along the path. First, we have to figure out which direction to slide it:
- (void)moveHandleTowardPoint:(CGPoint)point {
CGFloat earlierDistance = [self distanceToPoint:point ifHandleMovesByOffset:-1];
CGFloat currentDistance = [self distanceToPoint:point ifHandleMovesByOffset:0];
CGFloat laterDistance = [self distanceToPoint:point ifHandleMovesByOffset:1];
It's possible that both directions would move the handle further from the desired point, so let's bail out in that case:
if (currentDistance <= earlierDistance && currentDistance <= laterDistance)
return;
OK, so at least one of the directions will move the handle closer. Let's figure out which one:
NSInteger direction;
CGFloat distance;
if (earlierDistance < laterDistance) {
direction = -1;
distance = earlierDistance;
} else {
direction = 1;
distance = laterDistance;
}
But we've only checked the nearest neighbors of the handle's starting point. We want to slide as far as we can along the path in that direction, as long as the handle is getting closer to the desired point:
NSInteger offset = direction;
while (true) {
NSInteger nextOffset = offset + direction;
CGFloat nextDistance = [self distanceToPoint:point ifHandleMovesByOffset:nextOffset];
if (nextDistance >= distance)
break;
distance = nextDistance;
offset = nextOffset;
}
Finally, update the handle's position to our newly-discovered point:
handlePathPointIndex_ += offset;
[self layoutHandleView];
}
That just leaves the small matter of computing the distance from the handle to a point, should the handle be moved along the path by some offset. Your old buddy hypotf computes the Euclidean distance so you don't have to:
- (CGFloat)distanceToPoint:(CGPoint)point ifHandleMovesByOffset:(NSInteger)offset {
int index = [self handlePathPointIndexWithOffset:offset];
CGPoint proposedHandlePoint = pathPoints_[index];
return hypotf(point.x - proposedHandlePoint.x, point.y - proposedHandlePoint.y);
}
(You could speed things up by using squared distances to avoid the square roots that hypotf is computing.)
One more tiny detail: the index into the points array needs to wrap around in both directions. That's what we've been relying on the mysterious handlePathPointIndexWithOffset: method to do:
- (NSInteger)handlePathPointIndexWithOffset:(NSInteger)offset {
NSInteger index = handlePathPointIndex_ + offset;
while (index < 0) {
index += pathPointsCount_;
}
while (index >= pathPointsCount_) {
index -= pathPointsCount_;
}
return index;
}
#end
Fin. I've put all of the code in a gist for easy downloading. Enjoy.
I have a simple jigsaw puzzle i'm making. I have a method that is called when the view is loaded and when the device is shaken. This method places 4 images in 4 specific places on screen. Below is the code:
-(void) makePieceHolders {
//create 4 points where the jigsaw pieces (images) will be placed
CGPoint holder1 = CGPointMake(80, 80);
CGPoint holder2 = CGPointMake(200, 80);
CGPoint holder3 = CGPointMake(80, 200);
CGPoint holder4 = CGPointMake(200, 200);
image1.center = holder1; //set the position of the image center to one of the newly created points
image1.alpha = 0.3; //set the image opacity back to 0.3
image2.center = holder2;
image2.alpha = 0.3;
image3.center = holder3;
image3.alpha = 0.3;
image4.center = holder4;
image4.alpha = 0.3;
}
What i'd like is to place the images randomly in the four placeholders. I have some more code written below where i get a random number between 1 and 4 and set the tag of each image to each of these random numbers.
int randomNumber;
int placeHolders[4];
int i=0;
bool numberFound;
do{ // until you get 4 unique numbers
randomNumber=arc4random()%4+1;
// Does this number exist already?
numberFound=FALSE;
for (int j=0; j<i; j++) {
if (placeHolders[j]==randomNumber)
numberFound=TRUE;
}
if (numberFound==FALSE){
placeHolders[i]=randomNumber;
i++;
}
} while (i<4);
image1.tag = placeHolders[0];
image2.tag = placeHolders[1];
image3.tag = placeHolders[2];
image4.tag = placeHolders[3];
NSLog(#"img1 tag: %i img2 tag: %i img3 tag: %i img4 tag: %i", image1.tag, image2.tag, image3.tag, image4.tag);
How do now refer to this tag information in order to move it to a placeholder?
In pseudocode i was thinking:
where image tag = 1, move that image to holder1
where image tag = 2, move that image to holder2
............
I don't know how to write this though.
If there is a better way i'd appreciate the help. Thanks
You don't need your complicated do..while / tag logic.
Just use an array:
NSMutableArray* images = [NSMutableArray arrayWithObjects: image1,image2,image3,image4,nil];
// shuffle the array
NSUInteger count = [images count];
for (NSUInteger i = 0; i < count; i++) {
// Select a random element between i and end of array to swap with.
int nElements = count - i;
int n = (arc4random() % nElements) + i;
[images exchangeObjectAtIndex:i withObjectAtIndex:n];
}
After that, you have randomly placed your images in a new order. After that assign the positions:
UIImageView* imageView1 = (UIImageView*)[images objectAtIndex: 0];
imageView.center = holder1;
UIImageView* imageView2 = (UIImageView*)[images objectAtIndex: 1];
imageView.center = holder2;
UIImageView* imageView3 = (UIImageView*)[images objectAtIndex: 2];
imageView.center = holder3;
UIImageView* imageView4 = (UIImageView*)[images objectAtIndex: 3];
imageView.center = holder4;
(You could also do this in a loop.. so it would be more general and reusable.)
this is the code in the continuation of this question....Allow horizontal scrolling only in the core-plot barchart?
-(BOOL)pointingDeviceDraggedAtPoint:(CGPoint)interactionPoint
{
if ( !self.allowsUserInteraction || !self.graph.plotArea ) {
return NO;
}
CGPoint pointInPlotArea = [self.graph.plotArea convertPoint:interactionPoint toLayer:self.graph.plotArea];
if ( isDragging ) {
pointInPlotArea.y = lastDragPoint.y;//-- Madhup Changed it for allwoing scrolling only in horizontal direction --//
//-- Madhup Changed it for allwoing scrolling only in horizontal direction --//
//CGPoint displacement = CGPointMake(pointInPlotArea.x-lastDragPoint.x, pointInPlotArea.y-lastDragPoint.y);
CGPoint displacement = CGPointMake(pointInPlotArea.x-lastDragPoint.x, 0);
//--******************************--//
CGPoint pointToUse = pointInPlotArea;
// Allow delegate to override
if ( [self.delegate respondsToSelector:#selector(plotSpace:willDisplaceBy:)] ) {
displacement = [self.delegate plotSpace:self willDisplaceBy:displacement];
pointToUse = CGPointMake(lastDragPoint.x+displacement.x, lastDragPoint.y+displacement.y);
}
NSDecimal lastPoint[2], newPoint[2];
[self plotPoint:lastPoint forPlotAreaViewPoint:lastDragPoint];
[self plotPoint:newPoint forPlotAreaViewPoint:pointToUse];
CPPlotRange *newRangeX = [[self.xRange copy] autorelease];
CPPlotRange *newRangeY = [[self.yRange copy] autorelease];
NSDecimal shiftX = CPDecimalSubtract(lastPoint[0], newPoint[0]);
NSDecimal shiftY = CPDecimalSubtract(lastPoint[1], newPoint[1]);
newRangeX.location = CPDecimalAdd(newRangeX.location, shiftX);
newRangeY.location = CPDecimalAdd(newRangeY.location, shiftY);
// Delegate override
if ( [self.delegate respondsToSelector:#selector(plotSpace:willChangePlotRangeTo:forCoordinate:)] ) {
newRangeX = [self.delegate plotSpace:self willChangePlotRangeTo:newRangeX forCoordinate:CPCoordinateX];
newRangeY = [self.delegate plotSpace:self willChangePlotRangeTo:newRangeY forCoordinate:CPCoordinateY];
}
self.xRange = newRangeX;
self.yRange = newRangeY;
//-- Madhup Changed it for keeping y axis fixed --//
NSLog(#"%#",self.graph.axisSet.axes);
NSMutableArray *axisArr= [[NSMutableArray alloc] initWithArray:self.graph.axisSet.axes];
CPXYAxis *yAxis = [axisArr objectAtIndex:1];
CGPoint point = yAxis.position;
point.y -= lastDragPoint.x;
yAxis.position = point;
[axisArr replaceObjectAtIndex:1 withObject:yAxis];
self.graph.axisSet.axes = axisArr;
[axisArr release];
NSLog(#"%#",self.graph.axisSet.axes);
//--******************************--//
lastDragPoint = pointInPlotArea;
return YES;
}
return NO;
}
Now from the code you people can see that i am able to stop the scrolling of map only in horizontal direction, but still I am not able to keep the y-axis fixed. I have written some code for that in this method too but it does not seem to be working.
if you want to fix axis when scrolling add this lines
CPTXYAxisSet *axisSet = (CPTXYAxisSet *)_graph.axisSet;
axisSet.xAxis.axisConstraints = [CPTConstraints constraintWithLowerOffset:0.0];
axisSet.yAxis.axisConstraints = [CPTConstraints constraintWithLowerOffset:0.0];
The original question now has two viable solutions that work for the latest, as of this date, code in the repository.
Allow horizontal scrolling only in the core-plot barchart?
To keep the graph only in quadrant one:
Allow horizontal scrolling only in the core-plot barchart?
To only allow scrolling in the horizontal:
Allow horizontal scrolling only in the core-plot barchart?
I've used both solutions with a scatter plot and it works great.