1616
1717package com .androidplot .candlestick ;
1818
19- import android .graphics .Canvas ;
20- import android .graphics .PointF ;
21- import android .graphics .RectF ;
22- import com .androidplot .exception .PlotRenderException ;
19+ import android .graphics .*;
2320import com .androidplot .ui .RenderStack ;
21+ import com .androidplot .ui .SeriesAndFormatter ;
2422import com .androidplot .util .ValPixConverter ;
23+ import com .androidplot .xy .ComplexRenderer ;
2524import com .androidplot .xy .XYPlot ;
26- import com .androidplot .xy .XYSeriesRenderer ;
25+ import com .androidplot .xy .XYSeries ;
26+
27+ import java .util .List ;
2728
2829/**
29- * Renders {@link CandlestickSeries} data into an {@link com.androidplot.xy.XYPlot}.
30+ * Renders a group of {@link com.androidplot.xy.XYSeries} as a candlestick chart
31+ * into an {@link com.androidplot.xy.XYPlot}.
32+ *
33+ * Constraints:
34+ * - Exactly four series must be added using the same {@link CandlestickFormatter}.
35+ * - Each of the four series has the same x(i) value.
36+ * - Expects that series are added in the order of:
37+ * high, low, open, close
38+ *
39+ * {@link CandlestickMaker} simplified methods for setting up a candlestick chart.
3040 */
31- public class CandlestickRenderer <FormatterType extends CandlestickFormatter > extends XYSeriesRenderer <CandlestickSeries , FormatterType > {
41+ public class CandlestickRenderer <FormatterType extends CandlestickFormatter > extends ComplexRenderer <FormatterType > {
42+
43+ private static final int HIGH_INDEX = 0 ;
44+ private static final int LOW_INDEX = 1 ;
45+ private static final int OPEN_INDEX = 2 ;
46+ private static final int CLOSE_INDEX = 3 ;
3247
3348 public CandlestickRenderer (XYPlot plot ) {
3449 super (plot );
3550 }
3651
52+
3753 @ Override
38- public void onRender (Canvas canvas , RectF plotArea , CandlestickSeries series , FormatterType formatter , RenderStack stack )
39- throws PlotRenderException {
40- for (int i = 0 ; i < series .size (); i ++) {
41- Number y = series .getY (i );
42- Number x = series .getX (i );
43- Number z = series .getZ (i );
44- Number a = series .getA (i );
45- Number b = series .getB (i );
46- drawValue (canvas , plotArea , formatter , x , y , z , a , b );
54+ public void onRender (Canvas canvas , RectF plotArea , List <SeriesAndFormatter <XYSeries ,
55+ ? extends FormatterType >> sfList , int seriesSize , RenderStack stack ) {
56+
57+ for (int i = 0 ; i < seriesSize ; i ++) {
58+
59+ // x-val for all series should be identical so just grab x from the first series:
60+ Number x = sfList .get (HIGH_INDEX ).getSeries ().getX (i );
61+
62+ Number high = sfList .get (HIGH_INDEX ).getSeries ().getY (i );
63+ Number low = sfList .get (LOW_INDEX ).getSeries ().getY (i );
64+ Number open = sfList .get (OPEN_INDEX ).getSeries ().getY (i );
65+ Number close = sfList .get (CLOSE_INDEX ).getSeries ().getY (i );
66+ drawValue (canvas , plotArea , sfList .get (0 ).getFormatter (), x , high , low , open , close );
4767 }
4868 }
4969
5070 protected void drawValue (Canvas canvas , RectF plotArea , FormatterType formatter ,
51- Number x , Number y , Number z , Number a , Number b ) {
52- final PointF yPix = ValPixConverter .valToPix (
53- x , y ,
71+ Number x , Number high , Number low , Number open , Number close ) {
72+ final PointF highPix = ValPixConverter .valToPix (
73+ x , high ,
5474 plotArea ,
5575 getPlot ().getCalculatedMinX (),
5676 getPlot ().getCalculatedMaxX (),
5777 getPlot ().getCalculatedMinY (),
5878 getPlot ().getCalculatedMaxY ());
5979
60- final PointF zPix = ValPixConverter .valToPix (
61- x , z ,
80+ final PointF lowPix = ValPixConverter .valToPix (
81+ x , low ,
6282 plotArea ,
6383 getPlot ().getCalculatedMinX (),
6484 getPlot ().getCalculatedMaxX (),
6585 getPlot ().getCalculatedMinY (),
6686 getPlot ().getCalculatedMaxY ());
6787
68- final PointF aPix = ValPixConverter .valToPix (
69- x , a ,
88+ final PointF openPix = ValPixConverter .valToPix (
89+ x , open ,
7090 plotArea ,
7191 getPlot ().getCalculatedMinX (),
7292 getPlot ().getCalculatedMaxX (),
7393 getPlot ().getCalculatedMinY (),
7494 getPlot ().getCalculatedMaxY ());
7595
76- final PointF bPix = ValPixConverter .valToPix (
77- x , b ,
96+ final PointF closePix = ValPixConverter .valToPix (
97+ x , close ,
7898 plotArea ,
7999 getPlot ().getCalculatedMinX (),
80100 getPlot ().getCalculatedMaxX (),
81101 getPlot ().getCalculatedMinY (),
82102 getPlot ().getCalculatedMaxY ());
83103
84- drawWick (canvas , zPix , yPix , formatter );
85- drawBody (canvas , bPix , aPix , formatter );
86- drawUpperCap (canvas , yPix , formatter );
87- drawLowerCap (canvas , zPix , formatter );
104+ drawWick (canvas , highPix , lowPix , formatter );
105+ drawBody (canvas , openPix , closePix , formatter );
106+ drawUpperCap (canvas , highPix , formatter );
107+ drawLowerCap (canvas , lowPix , formatter );
88108 }
89109
90110 protected void drawWick (Canvas canvas , PointF min , PointF max , FormatterType formatter ) {
91111 canvas .drawLine (min .x , min .y , max .x , max .y , formatter .getWickPaint ());
92112 }
93113
94- protected void drawBody (Canvas canvas , PointF min , PointF max , FormatterType formatter ) {
114+ protected void drawBody (Canvas canvas , PointF open , PointF close , FormatterType formatter ) {
95115 final float halfWidth = formatter .getBodyWidth () / 2 ;
96- final RectF rect = new RectF (min .x - halfWidth , min .y , max .x + halfWidth , max .y );
97- canvas .drawRect (rect , formatter .getBodyFillPaint ());
98- canvas .drawRect (rect , formatter .getBodyStrokePaint ());
116+ final RectF rect = new RectF (open .x - halfWidth , open .y , close .x + halfWidth , close .y );
117+
118+ Paint bodyFillPaint = open .y >= close .y ?
119+ formatter .getRisingBodyFillPaint () : formatter .getFallingBodyFillPaint ();
120+
121+ Paint bodyStrokePaint = open .y >= close .y ?
122+ formatter .getRisingBodyStrokePaint () : formatter .getFallingBodyStrokePaint ();
123+
124+ switch (formatter .getBodyStyle ()) {
125+ case Square :
126+ canvas .drawRect (rect , bodyFillPaint );
127+ canvas .drawRect (rect , bodyStrokePaint );
128+ break ;
129+ case Triangle :
130+ drawTriangle (canvas , rect , bodyFillPaint , bodyStrokePaint );
131+ }
99132 }
100133
101134 protected void drawUpperCap (Canvas canvas , PointF val , FormatterType formatter ) {
@@ -112,4 +145,15 @@ protected void drawLowerCap(Canvas canvas, PointF val, FormatterType formatter)
112145 protected void doDrawLegendIcon (Canvas canvas , RectF rect , FormatterType formatter ) {
113146 // TODO
114147 }
148+
149+ protected void drawTriangle (Canvas canvas , RectF rect ,
150+ Paint fillPaint , Paint strokePaint ) {
151+ Path path = new Path ();
152+ path .moveTo (rect .centerX (), rect .bottom );
153+ path .lineTo (rect .left ,rect .top );
154+ path .lineTo (rect .right , rect .top );
155+ path .close ();
156+ canvas .drawPath (path , fillPaint );
157+ canvas .drawPath (path , strokePaint );
158+ }
115159}
0 commit comments