2012-05-17 21 views
11

Sto sviluppando un'applicazione per iPhone con diagramma di trama principale. Con l'aiuto di alcuni tutorial, sono riuscito a farlo con un solo tocco e trascinato. Come posso farlo con più touch e trascinamento? Qualcuno per favore aiutami?iPhone Multi touch interattivo a CorePlot

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; 
} 
+1

Hai provato a usare touchesBegan: withEvent: metodo? È possibile leggere tutti i tocchi> NSSet * allTouches = [evento allTouches]; switch ([allTouches count]) { caso 1: {// Single touch ecc .. – Q8i

risposta

2

sarò molto probabilmente finirà per rispondere a questa domanda in più risposte, ma lo farò a questo punto inizia con:

Si potrebbe pensare che Apple avrebbe fornito API per aiutare con più algoritmi di tracciamento delle dita, ecc. All'interno dei propri oggetti di Riconoscimento dei gesti, ma non hanno finora. Nel gioco che ho sviluppato, avevo bisogno di avere anche più dita, fino a 4 e oltre, tutte sullo schermo e in movimento/tracciamento tutto in una volta. Ciò che ho scoperto è stato che dovevo implementare i miei algoritmi di tracciamento delle dita/down/up per ottenere risultati diversi dai semplici passaggi a dito singolo e dalle operazioni di pinch-to-zoom. Consente di individuare:

Credo che nel file EskLinePlot.m "si debbano gestire gli eventi", sarà necessario implementare un incrementatore di "quante dita sono giù". In questo modo se metti un altro dito verso il basso quando un altro è già giù, ne avrai un conteggio. Allo stesso modo è necessario implementare un decrementer nella routine "dovrebbe gestire gli eventi". Nel bel mezzo di tutto ciò, dovrà anche essere un (seppur) piccolo database (probabilmente un NSMutableArray) di tocchi. Questo database verrà utilizzato per correlare gli eventi di trascinamento a un dito. Quindi, in definitiva con questo lavoro. Su un evento inattivo, è possibile: 1) creare un nuovo record nel database touch (il numero dell'array può fungere da identificatore univoco 2) Registrare la posizione corrente del nuovo tocco nel (nuovo) record del tocco creato nel passaggio 1 come la più recente (o posizione dell'array 0). Ogni elemento tocco nel database touch dovrebbe avere una cronologia da qualche parte tra 4 e 10 delle ultime posizioni in cui il dito è stato (Tendo a registrare posizioni come 0 = più recente a 3 o 9 come la più vecchia). 3) Invece di attivare semplicemente la linea SINGLE (grafica) che hai creato, aggiungi una nuova linea (grafica) quando si è verificato l'evento down (facendo la stessa correlazione che stai facendo per posizionare il dito sullo schermo per rappresentare la posizione numerica)

Per "elaborare gli eventi di trascinamento": 1) Osservare la posizione di sceen del dito trasmesso nell'evento di trascinamento e correlarlo con un tocco all'interno del proprio database tattile internamente (il tocco nel database touch è il più vicino a quello che viene presentato in questo momento). 2) sposta tutti i punti di posizione precedenti per il touchdown correlato di 1. 0 passa a 1, 1 passa a 2, ecc ... attraverso tutto e, naturalmente, elimina l'ultimo. 3) aggiungi il nuovo punto all'elenco dei punti precedenti del tocco correalizzato come il punto più recente. 4) Spostare il) Linea (grafica che è stata correlata a quel dito in modo appropriato

Per un up evento: 1) correlare la posizione presentata ad un dito all'interno del database tocco. 2) rimuovi il tocco correlato dal tuo database touch. 3) rimuovi la linea (grafica) che hai assegnato a quel dito dallo schermo

Spero che questo aiuti, dovrei essere in grado di trovare qualche codice di esempio da qualche parte, ma non sono attualmente davanti alla mia macchina di sviluppo .

3

Recentemente ho riscontrato lo stesso problema e non sono riuscito a trovare alcuna soluzione. Dopo un po 'di tempo di ricerca e programmazione ho trovato alcune soluzioni e ne voglio condividere una, abbastanza facile, in modo che possa aiutarti a farti un'idea di come affrontarlo.

Ho creato UIView trasparente, che ho aggiunto a CPTGraphHostingView. Questa vista stava gestendo gli eventi tattili necessari. Diamo un nome che TestView

file di TestView.h sembra

@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]; 
} 

TestView delegato, nel mio caso viewController, che comprende corePlot vista hosting, implementerà questi metodi e vedere l'esempio del codice sottostante

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

CPTPlotSpace metodo delegato in viewController sarà simile

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

E questo è il risultato ...

enter image description here

Questo non è ottimizzato il codice, è solo l'idea, come ho già detto, come avvicinarsi a questo problema

Speranza che aiuta ...

Problemi correlati