11

I'm developing an iPhone application with core-plot chart. With the help of some tutorials, i managed to do it with single touch and drag. How can I make it with multiple touch and drag? Anybody please help me?

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;
}
4

2 に答える 2

3

最近同じ問題に遭遇し、解決策が見つかりませんでした。しばらく調査とコーディングを行った後、いくつかの解決策を見つけたので、非常に簡単な解決策を共有したいと思います。

CPTGraphHostingView の上に配置した透明な UIView を作成しました。このビューは、必要なタッチ イベントを処理していました。名前を 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

TestView.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];
}

私の場合、corePlot ホスティング ビューを含む viewController の TestView デリゲートは、これらのメソッドを実装し、以下のコードのサンプルを参照します。

- (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 デリゲート メソッドは次のようになります。

- (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;
}

で、結果は・・・

ここに画像の説明を入力

これは最適化されたコードではなく、上で述べたように、この問題にどのようにアプローチするかという単なるアイデアです。

それが役に立てば幸い...

于 2012-11-09T15:31:20.883 に答える
2

この質問にはおそらく複数の回答で回答することになりますが、この時点では次のことから始めます。

Apple は、ジェスチャー認識オブジェクト内で複数の指追跡アルゴリズムなどを支援する API を提供していたと思うかもしれませんが、これまでのところそうではありません。私が開発したゲームでは、最大 4 本以上の複数の指をすべて画面上に配置し、同時に移動/追跡する必要もありました。私が見つけたのは、単純な 1 本指のスワイプやピンチしてズームする操作以外のことを行うには、独自の指追跡/ダウン/アップ アルゴリズムを実装する必要があるということでした。掘り下げてみましょう:

私はあなたの EskLinePlot.m ファイルで「ダウン イベントを処理する必要がある」と信じています。「ダウンしている指の数」のインクリメンタを実装する必要があります。このようにして、別の指がすでに下がっているときに別の指を下ろした場合、その数がカウントされます。同様に、「イベントを処理する必要がある」ルーチンにデクリメンタを実装する必要があります。このすべての途中で、(とはいえ) タッチの小さなデータベース (おそらく NSMutableArray) も必要になります。このデータベースは、ドラッグ イベントを指に関連付けるために使用されます。では、最終的にこの作品でどうなるか。ダウン イベントでは、次のことを行います: 1) タッチ データベースに新しいレコードを作成します (アレイ番号は一意の識別子として機能します 2) 新しいタッチを記録します。の現在位置を、手順 1 で作成した (新しい) タッチ レコードに最新 (または配列位置 0) の位置として挿入します。タッチ データベース内の各タッチ項目には、指が最後に置かれた 4 ~ 10 の位置の履歴が必要です (私は位置を 0 = 最新から 3 または 9 を最も古いものとして記録する傾向があります)。3) 作成した SINGLE (グラフィカル) ラインを単にオンにする代わりに、ダウン イベントが発生したときに新しい (グラフィカル) ラインを追加します (現在スクリーンの指の位置に対して行っているのと同じ相関を行い、数値の位置をグラフにします)。

「ドラッグ イベントを処理する必要がある」の場合: 1) ドラッグ イベントで中継されている指のシーン位置を見て、それを内部で保持されているタッチ データベース内のタッチに関連付けます (タッチ データベース内のどのタッチが現在のタッチに最も近いか)。今回提示)。2) 相関するタッチダウンの以前のすべての位置ポイントを 1 だけシフトします。0 は 1 に、1 は 2 に、など... すべてを通過し、もちろん最後の 1 つをドロップします。3) 新しい点を相関タッチの以前の点のリストに最新の点として追加します。4) その指に関連付けられた (グラフィカルな) 線を適切に移動します

アップ イベントの場合: 1) 提示された位置をタッチ データベース内の指に関連付けます。2) 関連付けられたタッチをタッチ データベースから削除します。3)その指に割り当てた(グラフィカルな)線を画面から削除します

これが役立つことを願っています。どこかでサンプル コードを見つけることができるはずですが、現在、開発マシンの前にいません。

于 2012-05-21T16:22:34.220 に答える