2016-06-06 16 views
0

Ich versuche, EChart, eine Bibliothek für Balkendiagramme auf Github für meine eigenen Zwecke anzupassen. In dieser Datei: https://github.com/zhuhuihuihui/EChart/blob/master/EChart/EColumn.mUIBezierPath Zeichnen über den vorherigen Pfad?

Ich versuche, die setGrade: Methode zu ändern, so dass anstatt den gesamten Balken von der Unterseite des Diagramms nach oben zu zeichnen, stattdessen wird es nur auf den oberen Rand der Leiste auf die nächste gewünschte Y-Position zeichnen in der Grafik. Ich habe unten ein GIF eingefügt, um das Problem zu zeigen, das ich habe.

dies der Code ist, dass diese Stange Zeichnung (zusammen mit einem CABasicAnimation darunter):

-(void)setGrade:(float)grade { 
    _grade = grade; 
    UIBezierPath *progressline = [UIBezierPath bezierPath]; 

    [progressline moveToPoint:CGPointMake(self.frame.size.width/2.0, self.frame.size.height)]; 
    [progressline addLineToPoint:CGPointMake(self.frame.size.width/2.0, (1 - grade) * self.frame.size.height)]; 
    _chartLine.path = progressline.CGPath; 
    _chartLine.strokeEnd = 1.0; 

    CABasicAnimation *pathAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"]; 
    pathAnimation.duration = 1.0; 
    pathAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; 
    pathAnimation.fromValue = [NSNumber numberWithFloat:0.0f]; 
    pathAnimation.toValue = [NSNumber numberWithFloat:1.0f]; 
    [_chartLine addAnimation:pathAnimation forKey:@"strokeEndAnimation"]; 
} 

Dieser Code aus EColumnChart.m genannt wird (https://github.com/zhuhuihuihui/EChart/blob/master/EChart/EColumnChart.m) Dies ist der relevante Teil, wenn die erste gerade initialisiert eine Bar zum ersten Mal, und die zweite I angepasst, um nur den Wert zu aktualisieren, die setGrade: Methode aufrufen

 if (nil == eColumn) { 
      eColumn = [[EColumn alloc] initWithFrame:CGRectMake(widthOfTheColumnShouldBe * 0.5 + (i * widthOfTheColumnShouldBe * 1.5), 0, widthOfTheColumnShouldBe, self.frame.size.height)]; 
      eColumn.shouldAnimate = NO; 
      eColumn.backgroundColor = [UIColor clearColor]; 
      eColumn.grade = eColumnDataModel.value/_fullValueOfTheGraph; 
      eColumn.eColumnDataModel = eColumnDataModel; 
      [eColumn setDelegate:self]; 
      [self addSubview:eColumn]; 
     } else { 
      eColumn.shouldAnimate = YES; 
      eColumn.grade = eColumnDataModel.value/_fullValueOfTheGraph; 
     } 
     [_eColumns setObject:eColumn forKey:[NSNumber numberWithInteger:currentIndex ]]; 

_fullValueOfTheGraph hat seinen eigenen Algorithmus, um zu bestimmen, wie weit die grap h die Bar sollte gezogen werden. Der eColumnDataModel.value ist nur eine Ganzzahl, die ich ihm gebe, das ist der Y-Wert der Balkenspalte.

Ich bin extrem mit Bezier-Pfade nicht vertraut. Ist der Trick, um den Bezier Pfad zu einem ivar und irgendwie den Top-Standort zu verfolgen?

enter image description here

aktualisieren: Ich habe versucht, diesen Code in dem Anfangsteil des setGrade zu verwenden: Methode aber es schafft nur die kleine Splitter Differenz zwischen dem letzten Update und der aktuellen. Ich habe einen prevGrade-Ivar hinzugefügt, der die letzte Klasse ist, die zum Aktualisieren der Leiste verwendet wurde. Es ist nah, aber es ist so, als müsste ich die Bezier-Pfade kombinieren, um die volle Balkenform zu bekommen. Irgendwelche Ideen?

  UIBezierPath *_progressline = [UIBezierPath bezierPath]; 
     if (_prevGrade != 0.0f) { 
     if (grade < _prevGrade) { //Bar graph going down 
     [_progressline moveToPoint:CGPointMake(self.frame.size.width/2.0, (1 + _prevGrade) * self.frame.size.height)]; 
     } else { //Bar graph going up 
     [_progressline moveToPoint:CGPointMake(self.frame.size.width/2.0, (1 - _prevGrade) * self.frame.size.height)]; 
     } 
     } else { 
     [_progressline moveToPoint:CGPointMake(self.frame.size.width/2.0, self.frame.size.height)]; 
     } 
     [_progressline addLineToPoint:CGPointMake(self.frame.size.width/2.0, (1 - grade) * self.frame.size.height)]; 
+0

Sie Code geschrieben, der einen Bezier-Pfad schafft, aber nicht der Kontext, in dem dieser Code verwendet wird, noch der Code, der tatsächlich zieht oder beseelt, dass Bezierkurve. Außerdem erzeugt der Code, den Sie gepostet haben, eine 1-Punkt-dicke Linie und das GIF, das Sie zeigen, ist deutlich dicker als das.Sie müssen eine klare, vollständige Beschreibung Ihres Vorgehens und Ihrer Vorgehensweise bereitstellen, wenn Sie Hilfe benötigen. –

+0

@DuncanC Alle Informationen hinzugefügt, die es unklar gemacht haben. Dieser Code enthält alle erforderlichen Code zum Zeichnen der Balkenspalte. Es gibt nichts anderes in der Bibliothek, das es zeichnet. –

Antwort

1

Ich denke, dass das, was Sie brauchen, animieren path für CAShapeLayer ist statt strokeEnd. Ich habe den Code aus dem Repo, den Sie teilen, getestet und einige Änderungen vorgenommen, um _chartLine zu animieren.

dies der Code von setGrade: Methode ist

-(void)setGrade:(float)grade 
{ 
    _grade = grade; 

    if(_chartLine.path == nil) 
    { 
     UIBezierPath *_progressline = [UIBezierPath bezierPath]; 
     if (_prevGrade != 0.0f) { 
      if (grade < _prevGrade) { //Bar graph going down 
       [_progressline moveToPoint:CGPointMake(self.frame.size.width/2.0, (1 + _prevGrade) * self.frame.size.height)]; 
      } else { //Bar graph going up 
       [_progressline moveToPoint:CGPointMake(self.frame.size.width/2.0, (1 - _prevGrade) * self.frame.size.height)]; 
      } 
     } else { 
      [_progressline moveToPoint:CGPointMake(self.frame.size.width/2.0, self.frame.size.height)]; 
     } 
     [_progressline addLineToPoint:CGPointMake(self.frame.size.width/2.0, (1 - grade) * self.frame.size.height)]; 

     _chartLine.path = _progressline.CGPath; 
     _chartLine.strokeEnd = 1.0; 
    }else 
    { 

     CAKeyframeAnimation *morph = [CAKeyframeAnimation animationWithKeyPath:@"path"]; 
     morph.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn]; 
     morph.values = [self getPathValuesForAnimation:_chartLine startGrade:_prevGrade neededGrade:_grade]; 
     morph.duration = 1; 
     morph.removedOnCompletion = YES; 
     morph.fillMode = kCAFillModeForwards; 
     morph.delegate = self; 
     [_chartLine addAnimation:morph forKey:@"pathAnimation"]; 
     _chartLine.path = (__bridge CGPathRef _Nullable)((id)[morph.values lastObject]); 
    } 

    _prevGrade = grade; 
} 


//this method return values for path animation 

-(NSArray*)getPathValuesForAnimation:(CAShapeLayer*)layer startGrade:(float)currentGrade neededGrade:(float)neededGrade 
{ 

    NSMutableArray * values = [NSMutableArray array]; 
    if(_prevGrade != 0.0f) 
     [values addObject:(id)layer.path]; 

    UIBezierPath * finalPath = [UIBezierPath bezierPath]; 

    [finalPath moveToPoint:CGPointMake(self.frame.size.width/2.0, self.frame.size.height)]; 
    [finalPath addLineToPoint:CGPointMake(self.frame.size.width/2.0,(1 - neededGrade)*self.frame.size.height)]; 

    [values addObject:(id)[finalPath CGPath]]; 

    return values; 
} 

Ich hoffe, das hilft Ihnen, gut für mich funktioniert, sieht

Dies ist, wie es funktioniert für mich, (My gif Exporteur nicht gut ist, so alle Panne, die Sie sehen, ist Problem meiner gif Exporteur)

Dies ist mit _chartLine.lineCap = kCALineCapButt;

enter image description here

Und das ist mit _chartLine.lineCap = kCALineCapRound;

enter image description here

+0

Wow das funktioniert super. Als eine schnelle Frage, wie würde man weitermachen, um die Spitze der Bar rund zu machen? Ich weiß, dass Sie einen Bezier-Pfad verwenden können, aber ist es möglich, einer bereits erstellten Kurve eine Kurve hinzuzufügen? –

+0

Sie müssen ändern '_chartLine.lineCap = kCALineCapButt;' für '_chartLine.lineCap = kCALineCapRound;', jetzt können Sie meine Antwort als akzeptiert markieren?, Grüße –

+1

Meine Antwort wurde aktualisiert! –

Verwandte Themen