iPhone 与 CorePlot 的多点触控交互

标签 iphone objective-c xcode core-plot

我正在开发一个带有核心图表的 iPhone 应用程序。在一些教程的帮助下,我设法通过单击和拖动来完成它。我怎样才能通过多次触摸和拖动来制作它?有人可以帮帮我吗?

enter image description here

ViewController.m

- (void)viewDidLoad
{
    [super viewDidLoad];

    EskPlotTheme *defaultTheme = [[EskPlotTheme alloc] init];
    linePlot = [[EskLinePlot alloc] init];
    linePlot.delegate = self;
    [linePlot renderInLayer:lineHostingView withTheme:defaultTheme]; 
    [defaultTheme release];    
}

EskLinePlot.m

- (id)init
{
    self = [super init];
    if (self) 
    {
        // setting up the sample data here.
        sampleData = [[NSArray alloc] initWithObjects:[NSNumber numberWithInt:6000],
                                                      [NSNumber numberWithInt:3000],
                                                      [NSNumber numberWithInt:2000],
                                                      [NSNumber numberWithInt:5000],
                                                      [NSNumber numberWithInt:7000],
                                                      [NSNumber numberWithInt:8500],
                                                      [NSNumber numberWithInt:6500], nil];

    }
    return self;
}

- (void)renderInLayer:(CPTGraphHostingView *)layerHostingView withTheme:(CPTTheme *)theme
{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

    CGRect bounds = layerHostingView.bounds;

    // Create the graph and assign the hosting view.
    graph = [[CPTXYGraph alloc] initWithFrame:bounds];
    layerHostingView.hostedGraph = graph;
    [graph applyTheme:theme];

    graph.plotAreaFrame.masksToBorder = NO;

    // chang the chart layer orders so the axis line is on top of the bar in the chart.
    NSArray *chartLayers = [[NSArray alloc] initWithObjects:[NSNumber numberWithInt:CPTGraphLayerTypePlots],
                                                            [NSNumber numberWithInt:CPTGraphLayerTypeMajorGridLines], 
                                                            [NSNumber numberWithInt:CPTGraphLayerTypeMinorGridLines],  
                                                            [NSNumber numberWithInt:CPTGraphLayerTypeAxisLines], 
                                                            [NSNumber numberWithInt:CPTGraphLayerTypeAxisLabels], 
                                                            [NSNumber numberWithInt:CPTGraphLayerTypeAxisTitles], 
                                                            nil];
    graph.topDownLayerOrder = chartLayers;    
    [chartLayers release];

    // Add plot space for horizontal charts
    graph.paddingLeft = 60.0;
    graph.paddingTop = 70.0;
    graph.paddingRight = 20.0;
    graph.paddingBottom = 20.0;

    // Setup plot space
    CPTXYPlotSpace *plotSpace = (CPTXYPlotSpace *)graph.defaultPlotSpace;
    plotSpace.allowsUserInteraction = YES;
    plotSpace.delegate = self;
    int sampleCount = [sampleData count]-1;
    plotSpace.xRange = [CPTPlotRange plotRangeWithLocation:CPTDecimalFromFloat(0.0f) length:CPTDecimalFromFloat(sampleCount)];
    plotSpace.yRange = [CPTPlotRange plotRangeWithLocation:CPTDecimalFromFloat(0.0f) length:CPTDecimalFromFloat(10000)];

    // Setup grid line style
    CPTMutableLineStyle *majorXGridLineStyle = [CPTMutableLineStyle lineStyle];
    majorXGridLineStyle.lineWidth = 1.0f;
    majorXGridLineStyle.lineColor = [[CPTColor whiteColor] colorWithAlphaComponent:0.25f];

    CPTMutableTextStyle *whiteTextStyle = [[[CPTMutableTextStyle alloc] init] autorelease];
    whiteTextStyle.color = [CPTColor whiteColor];    

    // Setup x-Axis.
    CPTXYAxisSet *axisSet = (CPTXYAxisSet *)graph.axisSet;
    CPTXYAxis *x = axisSet.xAxis;
    x.majorGridLineStyle = majorXGridLineStyle;
    x.labelTextStyle = whiteTextStyle;
    x.majorIntervalLength = CPTDecimalFromString(@"1");
    x.minorTicksPerInterval = 1;

    NSArray *exclusionRanges = [NSArray arrayWithObjects:[CPTPlotRange plotRangeWithLocation:CPTDecimalFromInt(0) length:CPTDecimalFromInt(0)], nil];
    x.labelExclusionRanges = exclusionRanges;

    // Setup y-Axis.
    CPTMutableLineStyle *majorYGridLineStyle = [CPTMutableLineStyle lineStyle];
    majorYGridLineStyle.lineWidth = 1.0f;
    majorYGridLineStyle.lineColor = [[CPTColor whiteColor] colorWithAlphaComponent:0.25];

    CPTMutableLineStyle *minorYGridLineStyle = [CPTMutableLineStyle lineStyle];
    minorYGridLineStyle.lineWidth = 1.0f;
    minorYGridLineStyle.lineColor = [[CPTColor blackColor] colorWithAlphaComponent:0.1];

    CPTXYAxis *y = axisSet.yAxis;
    y.majorGridLineStyle = majorYGridLineStyle;
    y.minorGridLineStyle = minorYGridLineStyle;
    y.labelTextStyle = whiteTextStyle;
    y.majorIntervalLength = CPTDecimalFromString(@"1000");
    y.minorTicksPerInterval = 1;
    y.orthogonalCoordinateDecimal = CPTDecimalFromString(@"0");
    NSArray *yExlusionRanges = [NSArray arrayWithObjects:
                                [CPTPlotRange plotRangeWithLocation:CPTDecimalFromFloat(0.0) length:CPTDecimalFromFloat(0.0)],
                                nil];
    y.labelExclusionRanges = yExlusionRanges;

    // Create a high plot area
    CPTScatterPlot *highPlot = [[[CPTScatterPlot alloc] init] autorelease];
    highPlot.identifier = kHighPlot;

    CPTMutableLineStyle *highLineStyle = [[highPlot.dataLineStyle mutableCopy] autorelease];
    highLineStyle.lineWidth = 2.f;
    highLineStyle.miterLimit        = 1.0f;
    highLineStyle.lineColor = [CPTColor whiteColor];
    highPlot.dataLineStyle = highLineStyle;
    highPlot.dataSource = self;

    CPTColor *areaColor1       = [[CPTColor whiteColor] colorWithAlphaComponent:0.8f];
    CPTGradient *areaGradient1 = [CPTGradient gradientWithBeginningColor:areaColor1 endingColor:[[CPTColor whiteColor]  colorWithAlphaComponent:0.2f]];
    areaGradient1.angle = -90.0f;
    CPTFill *areaGradientFill = [CPTFill fillWithGradient:areaGradient1];
    highPlot.areaFill       = areaGradientFill;
    highPlot.areaBaseValue = [[NSDecimalNumber zero] decimalValue];
    [graph addPlot:highPlot];

    // Create the Savings Marker Plot
    selectedCoordination = 2;

    touchPlot = [[[CPTScatterPlot alloc] initWithFrame:CGRectNull] autorelease];
    touchPlot.identifier = kLinePlot;
    touchPlot.dataSource = self;
    touchPlot.delegate = self;
    [self hideTouchPlotColor];
    [graph addPlot:touchPlot];

    [pool drain];

}

- (void)hideTouchPlotColor
{
    CPTColor *touchPlotColor = [CPTColor clearColor];

    CPTMutableLineStyle *savingsPlotLineStyle = [CPTMutableLineStyle lineStyle];
    savingsPlotLineStyle.lineColor = touchPlotColor;

    CPTPlotSymbol *touchPlotSymbol = [CPTPlotSymbol ellipsePlotSymbol];
    touchPlotSymbol.fill = [CPTFill fillWithColor:touchPlotColor];
    touchPlotSymbol.lineStyle = savingsPlotLineStyle;
    touchPlotSymbol.size = CGSizeMake(12.0f, 12.0f);

    CPTMutableLineStyle *touchLineStyle = [CPTMutableLineStyle lineStyle];
    touchLineStyle.lineColor = [CPTColor clearColor];
    touchLineStyle.lineWidth = 1.0f;

    CPTMutableLineStyle *symbolLineStyle = [CPTMutableLineStyle lineStyle];
    symbolLineStyle.lineColor = [CPTColor clearColor];
    CPTPlotSymbol *plotSymbol = [CPTPlotSymbol ellipsePlotSymbol];
    plotSymbol.fill = [CPTFill fillWithColor:[CPTColor clearColor]];
    plotSymbol.lineStyle = symbolLineStyle;
    plotSymbol.size = CGSizeMake(10.0, 10.0);
    touchPlot.plotSymbol = plotSymbol;

    touchPlot.dataLineStyle = touchLineStyle;
}

// Assign different color to the touchable line symbol.
- (void)showTouchPlotColor
{
    CPTColor *touchPlotColor = [CPTColor orangeColor];

    CPTMutableLineStyle *savingsPlotLineStyle = [CPTMutableLineStyle lineStyle];
    savingsPlotLineStyle.lineColor = touchPlotColor;

    CPTPlotSymbol *touchPlotSymbol = [CPTPlotSymbol ellipsePlotSymbol];
    touchPlotSymbol.fill = [CPTFill fillWithColor:touchPlotColor];
    touchPlotSymbol.lineStyle = savingsPlotLineStyle;
    touchPlotSymbol.size = CGSizeMake(12.0f, 12.0f); 

    CPTMutableLineStyle *touchLineStyle = [CPTMutableLineStyle lineStyle];
    touchLineStyle.lineColor = [CPTColor orangeColor];
    touchLineStyle.lineWidth = 1.0f;

    CPTMutableLineStyle *symbolLineStyle = [CPTMutableLineStyle lineStyle];
    symbolLineStyle.lineColor = [CPTColor blackColor];
    CPTPlotSymbol *plotSymbol = [CPTPlotSymbol ellipsePlotSymbol];
    plotSymbol.fill = [CPTFill fillWithColor:[CPTColor orangeColor]];
    plotSymbol.lineStyle = symbolLineStyle;
    plotSymbol.size = CGSizeMake(10.0, 10.0);
    touchPlot.plotSymbol = plotSymbol;

    touchPlot.dataLineStyle = touchLineStyle;
}

// This method is call when user touch & drag on the plot space.
- (BOOL)plotSpace:(CPTPlotSpace *)space shouldHandlePointingDeviceDraggedEvent:(id)event atPoint:(CGPoint)point
{
    // Convert the touch point to plot area frame location
    CGPoint pointInPlotArea = [graph convertPoint:point toLayer:graph.plotAreaFrame];

    NSDecimal newPoint[2];
    [graph.defaultPlotSpace plotPoint:newPoint forPlotAreaViewPoint:pointInPlotArea];
    NSDecimalRound(&newPoint[0], &newPoint[0], 0, NSRoundPlain);
    int x = [[NSDecimalNumber decimalNumberWithDecimal:newPoint[0]] intValue];

    if (x < 0)
    {
        x = 0;
    }
    else if (x > [sampleData count])
    {
        x = [sampleData count];
    }

        selectedCoordination = x;
        if ([delegate respondsToSelector:@selector(linePlot:indexLocation:)])
            [delegate linePlot:self indexLocation:x];
        [touchPlot reloadData];

    return YES;
}

- (BOOL)plotSpace:(CPTPlotSpace *)space shouldHandlePointingDeviceDownEvent:(id)event 
          atPoint:(CGPoint)point
{
    [self showTouchPlotColor];
    return YES;
}

- (BOOL)plotSpace:(CPTPlotSpace *)space shouldHandlePointingDeviceUpEvent:(id)event atPoint:(CGPoint)point
{
    [self hideTouchPlotColor];
    touchPlotSelected = NO;
    return YES;
}

#pragma mark - 
#pragma mark Scatter plot delegate methods

- (void)scatterPlot:(CPTScatterPlot *)plot plotSymbolWasSelectedAtRecordIndex:(NSUInteger)index
{
    if ([(NSString *)plot.identifier isEqualToString:kLinePlot]) 
    {
        touchPlotSelected = YES;
        [self applyHighLightPlotColor:plot];
        if ([delegate respondsToSelector:@selector(linePlot:indexLocation:)])
            [delegate linePlot:self indexLocation:index];
    } 
}

#pragma mark -
#pragma mark Plot Data Source Methods

- (NSUInteger)numberOfRecordsForPlot:(CPTPlot *)plot 
{
    if ([(NSString *)plot.identifier isEqualToString:kLinePlot]) 
    {
        return kNumberOfMarkerPlotSymbols;
    }
    else {
        return [sampleData count];
    }
}

- (NSNumber *)numberForPlot:(CPTPlot *)plot field:(NSUInteger)fieldEnum recordIndex:(NSUInteger)index 
{
    NSNumber *num = nil;
    if ( [(NSString *)plot.identifier isEqualToString:kHighPlot] )
    {
        if ( fieldEnum == CPTScatterPlotFieldY ) 
        {
            num = [sampleData objectAtIndex:index];
        } 
        else if (fieldEnum == CPTScatterPlotFieldX) 
        {
            num = [NSNumber numberWithInt:index];
        }
    }
    else if ([(NSString *)plot.identifier isEqualToString:kLinePlot]) 
    {
        if ( fieldEnum == CPTScatterPlotFieldY ) 
        {
            switch (index) {
                case 0:
                    num = [NSNumber numberWithInt:-1000];
                    break;
                case 2:
                    num = [NSNumber numberWithInt:12700];
                    break;
                default:
                    num = [sampleData objectAtIndex:selectedCoordination];
                    break;
            }
        } 
        else if (fieldEnum == CPTScatterPlotFieldX) 
        {
            num = [NSNumber numberWithInt:selectedCoordination];
        }
    }

    return num;
}

最佳答案

我最近遇到了同样的问题,但找不到任何解决方案。经过一段时间的研究和编码后,我找到了一些解决方案并想分享一个非常简单的解决方案,因此它可能会帮助您了解如何解决这个问题。

我已经创建了透明的 UIView,并将其放在 CPTGraphHostingView 之上。 该 View 正在处理所需的触摸事件。 我们将其命名为 TestView

TestView.h 文件看起来像

@protocol TestViewDelegate <NSObject>
- (void)myTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)myTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)myTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;

@end

@interface TestView : UIView
@property (nonatomic, weak) id <TestViewDelegate>delegate;
@end

测试 View .m

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        // Initialization code
    }
    return self;
}

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
    [self.delegate myTouchesBegan:touches withEvent:event];
}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
    [self.delegate myTouchesMoved:touches withEvent:event];
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
    [self.delegate myTouchesEnded:touches withEvent:event];
}

TestView 委托(delegate),在我的例子中是 viewController,它包括 corePlot 托管 View ,将实现这些方法并查看下面的代码示例

- (void)myTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
    if (touches.count == 1) {
        UITouch *touch = (UITouch *)[[touches allObjects] objectAtIndex:0];
        CGPoint point = [touch locationInView:nil];
        [self plotSpace:self.plotSpace shouldHandlePointingDeviceDraggedEvent:event atPoint:point];
    }
    if (touches.count == 2) {
        UITouch *touch = (UITouch *)[[touches allObjects] objectAtIndex:1];
        CGPoint point = [touch locationInView:nil];
        [self plotSpace:self.plotSpace shouldHandlePointingDeviceDraggedEvent:event atPoint:point];
    }
}

viewController 中的 CPTPlotSpace 委托(delegate)方法看起来像

- (BOOL)plotSpace:(CPTPlotSpace *)space shouldHandlePointingDeviceDraggedEvent:(id)event atPoint:(CGPoint)point{
    NSSet *allTouches = [event allTouches];
    if ([allTouches count] >0 ) {
        UITouch *touch1 = [[allTouches allObjects] objectAtIndex:0];
        if (touch1){
            CGPoint pointInPlotArea = [self.graph convertPoint:[touch1 locationInView:self.view] toLayer:self.graph.plotAreaFrame];
//              padding
            pointInPlotArea.x -=10;
            NSDecimal newPoint[2];
            [self.graph.defaultPlotSpace plotPoint:newPoint forPlotAreaViewPoint:pointInPlotArea];
            NSDecimalRound(&newPoint[0], &newPoint[0], 0, NSRoundPlain);
            int x = [[NSDecimalNumber decimalNumberWithDecimal:newPoint[0]] intValue];
            x--;

            if (x <= 0)
                x = 0;
            else if (x >= [self.currentDatapoints count])
                x = [self.currentDatapoints count] - 1;

            selectedCoordination = x;
            self.label.text = [NSString stringWithFormat:@"%@", [self.currentDatapoints objectAtIndex:x]];
            self.differenceLabel.text = @"";
            [touchPlot reloadData];
        }
        if ([allTouches count] > 1){
            secondTouchPlot.hidden = NO;
            UITouch *touch2 = [[allTouches allObjects] objectAtIndex:1];
            if (touch2) {
                CGPoint pointInPlotArea = [self.graph convertPoint:[touch2 locationInView:self.view] toLayer:self.graph.plotAreaFrame];
                pointInPlotArea.x -= 10;
                NSDecimal newPoint[2];
                [self.graph.defaultPlotSpace plotPoint:newPoint forPlotAreaViewPoint:pointInPlotArea];
                NSDecimalRound(&newPoint[0], &newPoint[0], 0, NSRoundPlain);
                int x = [[NSDecimalNumber decimalNumberWithDecimal:newPoint[0]] intValue];
                x--;
                if (x <= 0)
                    x = 0;
                else if (x >= [self.currentDatapoints count])
                    x = [self.currentDatapoints count] - 1;

                selectedCoordination2 = x;
                self.secondLabel.text = [NSString stringWithFormat:@"%@", [self.currentDatapoints objectAtIndex:x]];
                [secondTouchPlot reloadData];
                float first = [self.label.text floatValue];
                float second = [[self.currentDatapoints objectAtIndex:x] floatValue];
                self.differenceLabel.textColor = (first - second) > 0 ? [UIColor greenColor] : [UIColor redColor];
                self.differenceLabel.text = [NSString stringWithFormat:@"%f", first - second];

            }
        }
    }
    return YES;
}

这就是结果......

enter image description here

这不是优化代码,它只是想法,正如我上面提到的,如何解决这个问题。

希望对你有帮助

关于iPhone 与 CorePlot 的多点触控交互,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10632421/

相关文章:

Objective-C block 和变量范围

ios - 从 Assets 库的图像 url 代表转到 base64

objective-c - 如何从界面生成器访问窗口 View ?

iPhone 无法支持开发

javascript - Html/javascript 页面在 iPhone 上抛出 404,但在 PC 上运行良好

jquery - 我正在构建的 Wordpress 页面正在使我的 iPhone 崩溃

ios - 将各个 View 放入选项卡的最佳方式

iphone - 如何调用 heightForRowAtIndexPath 的默认实现?

iphone - 重命名iPhone应用程序

ios - Xcode 7.3 中的自动布局 (swift 2)