source: Dev/branches/rest-dojo-ui/client/dojox/charting/plot2d/Candlesticks.js @ 256

Last change on this file since 256 was 256, checked in by hendrikvanantwerpen, 13 years ago

Reworked project structure based on REST interaction and Dojo library. As
soon as this is stable, the old jQueryUI branch can be removed (it's
kept for reference).

File size: 7.8 KB
Line 
1define(["dojo/_base/lang", "dojo/_base/declare", "dojo/_base/array", "./Base", "./common",
2                "dojox/lang/functional", "dojox/lang/functional/reversed", "dojox/lang/utils", "dojox/gfx/fx"],
3        function(lang, declare, arr, Base, dc, df, dfr, du, fx){
4/*=====
5var Base = dojox.charting.plot2d.Base;
6=====*/
7
8        var purgeGroup = dfr.lambda("item.purgeGroup()");
9
10        //      Candlesticks are based on the Bars plot type; we expect the following passed
11        //      as values in a series:
12        //      { x?, open, close, high, low, mid? }
13        //      if x is not provided, the array index is used.
14        //      failing to provide the OHLC values will throw an error.
15        return declare("dojox.charting.plot2d.Candlesticks", Base, {
16                //      summary:
17                //              A plot that represents typical candlesticks (financial reporting, primarily).
18                //              Unlike most charts, the Candlestick expects data points to be represented by
19                //              an object of the form { x?, open, close, high, low, mid? }, where both
20                //              x and mid are optional parameters.  If x is not provided, the index of the
21                //              data array is used.
22                defaultParams: {
23                        hAxis: "x",             // use a horizontal axis named "x"
24                        vAxis: "y",             // use a vertical axis named "y"
25                        gap:    2,              // gap between columns in pixels
26                        animate: null   // animate bars into place
27                },
28                optionalParams: {
29                        minBarSize:     1,      // minimal candle width in pixels
30                        maxBarSize:     1,      // maximal candle width in pixels
31                        // theme component
32                        stroke:         {},
33                        outline:        {},
34                        shadow:         {},
35                        fill:           {},
36                        font:           "",
37                        fontColor:      ""
38                },
39
40                constructor: function(chart, kwArgs){
41                        //      summary:
42                        //              The constructor for a candlestick chart.
43                        //      chart: dojox.charting.Chart
44                        //              The chart this plot belongs to.
45                        //      kwArgs: dojox.charting.plot2d.__BarCtorArgs?
46                        //              An optional keyword arguments object to help define the plot.
47                        this.opt = lang.clone(this.defaultParams);
48                        du.updateWithObject(this.opt, kwArgs);
49                        du.updateWithPattern(this.opt, kwArgs, this.optionalParams);
50                        this.series = [];
51                        this.hAxis = this.opt.hAxis;
52                        this.vAxis = this.opt.vAxis;
53                        this.animate = this.opt.animate;
54                },
55
56                collectStats: function(series){
57                        //      summary:
58                        //              Collect all statistics for drawing this chart.  Since the common
59                        //              functionality only assumes x and y, Candlesticks must create it's own
60                        //              stats (since data has no y value, but open/close/high/low instead).
61                        //      series: dojox.charting.Series[]
62                        //              The data series array to be drawn on this plot.
63                        //      returns: Object
64                        //              Returns an object in the form of { hmin, hmax, vmin, vmax }.
65
66                        //      we have to roll our own, since we need to use all four passed
67                        //      values to figure out our stats, and common only assumes x and y.
68                        var stats = lang.delegate(dc.defaultStats);
69                        for(var i=0; i<series.length; i++){
70                                var run = series[i];
71                                if(!run.data.length){ continue; }
72                                var old_vmin = stats.vmin, old_vmax = stats.vmax;
73                                if(!("ymin" in run) || !("ymax" in run)){
74                                        arr.forEach(run.data, function(val, idx){
75                                                if(val !== null){
76                                                        var x = val.x || idx + 1;
77                                                        stats.hmin = Math.min(stats.hmin, x);
78                                                        stats.hmax = Math.max(stats.hmax, x);
79                                                        stats.vmin = Math.min(stats.vmin, val.open, val.close, val.high, val.low);
80                                                        stats.vmax = Math.max(stats.vmax, val.open, val.close, val.high, val.low);
81                                                }
82                                        });
83                                }
84                                if("ymin" in run){ stats.vmin = Math.min(old_vmin, run.ymin); }
85                                if("ymax" in run){ stats.vmax = Math.max(old_vmax, run.ymax); }
86                        }
87                        return stats;   //      Object
88                },
89
90                getSeriesStats: function(){
91                        //      summary:
92                        //              Calculate the min/max on all attached series in both directions.
93                        //      returns: Object
94                        //              {hmin, hmax, vmin, vmax} min/max in both directions.
95                        var stats = this.collectStats(this.series);
96                        stats.hmin -= 0.5;
97                        stats.hmax += 0.5;
98                        return stats;
99                },
100
101                render: function(dim, offsets){
102                        //      summary:
103                        //              Run the calculations for any axes for this plot.
104                        //      dim: Object
105                        //              An object in the form of { width, height }
106                        //      offsets: Object
107                        //              An object of the form { l, r, t, b}.
108                        //      returns: dojox.charting.plot2d.Candlesticks
109                        //              A reference to this plot for functional chaining.
110                        if(this.zoom && !this.isDataDirty()){
111                                return this.performZoom(dim, offsets);
112                        }
113                        this.resetEvents();
114                        this.dirty = this.isDirty();
115                        if(this.dirty){
116                                arr.forEach(this.series, purgeGroup);
117                                this._eventSeries = {};
118                                this.cleanGroup();
119                                var s = this.group;
120                                df.forEachRev(this.series, function(item){ item.cleanGroup(s); });
121                        }
122                        var t = this.chart.theme, f, gap, width,
123                                ht = this._hScaler.scaler.getTransformerFromModel(this._hScaler),
124                                vt = this._vScaler.scaler.getTransformerFromModel(this._vScaler),
125                                baseline = Math.max(0, this._vScaler.bounds.lower),
126                                baselineHeight = vt(baseline),
127                                events = this.events();
128                        f = dc.calculateBarSize(this._hScaler.bounds.scale, this.opt);
129                        gap = f.gap;
130                        width = f.size;
131                        for(var i = this.series.length - 1; i >= 0; --i){
132                                var run = this.series[i];
133                                if(!this.dirty && !run.dirty){
134                                        t.skip();
135                                        this._reconnectEvents(run.name);
136                                        continue;
137                                }
138                                run.cleanGroup();
139                                var theme = t.next("candlestick", [this.opt, run]), s = run.group,
140                                        eventSeries = new Array(run.data.length);
141                                for(var j = 0; j < run.data.length; ++j){
142                                        var v = run.data[j];
143                                        if(v !== null){
144                                                var finalTheme = t.addMixin(theme, "candlestick", v, true);
145
146                                                //      calculate the points we need for OHLC
147                                                var x = ht(v.x || (j+0.5)) + offsets.l + gap,
148                                                        y = dim.height - offsets.b,
149                                                        open = vt(v.open),
150                                                        close = vt(v.close),
151                                                        high = vt(v.high),
152                                                        low = vt(v.low);
153                                                if("mid" in v){
154                                                        var mid = vt(v.mid);
155                                                }
156                                                if(low > high){
157                                                        var tmp = high;
158                                                        high = low;
159                                                        low = tmp;
160                                                }
161
162                                                if(width >= 1){
163                                                        //      draw the line and rect, set up as a group and pass that to the events.
164                                                        var doFill = open > close;
165                                                        var line = { x1: width/2, x2: width/2, y1: y - high, y2: y - low },
166                                                                rect = {
167                                                                        x: 0, y: y-Math.max(open, close),
168                                                                        width: width, height: Math.max(doFill ? open-close : close-open, 1)
169                                                                };
170                                                        var shape = s.createGroup();
171                                                        shape.setTransform({dx: x, dy: 0 });
172                                                        var inner = shape.createGroup();
173                                                        inner.createLine(line).setStroke(finalTheme.series.stroke);
174                                                        inner.createRect(rect).setStroke(finalTheme.series.stroke).
175                                                                setFill(doFill ? finalTheme.series.fill : "white");
176                                                        if("mid" in v){
177                                                                //      add the mid line.
178                                                                inner.createLine({
179                                                                        x1: (finalTheme.series.stroke.width||1), x2: width - (finalTheme.series.stroke.width || 1),
180                                                                        y1: y - mid, y2: y - mid
181                                                                }).setStroke(doFill ? "white" : finalTheme.series.stroke);
182                                                        }
183
184                                                        //      TODO: double check this.
185                                                        run.dyn.fill   = finalTheme.series.fill;
186                                                        run.dyn.stroke = finalTheme.series.stroke;
187                                                        if(events){
188                                                                var o = {
189                                                                        element: "candlestick",
190                                                                        index:   j,
191                                                                        run:     run,
192                                                                        shape:   inner,
193                                                                        x:       x,
194                                                                        y:       y-Math.max(open, close),
195                                                                        cx:              width/2,
196                                                                        cy:              (y-Math.max(open, close)) + (Math.max(doFill ? open-close : close-open, 1)/2),
197                                                                        width:   width,
198                                                                        height:  Math.max(doFill ? open-close : close-open, 1),
199                                                                        data:    v
200                                                                };
201                                                                this._connectEvents(o);
202                                                                eventSeries[j] = o;
203                                                        }
204                                                }
205                                                if(this.animate){
206                                                        this._animateCandlesticks(shape, y - low, high - low);
207                                                }
208                                        }
209                                }
210                                this._eventSeries[run.name] = eventSeries;
211                                run.dirty = false;
212                        }
213                        this.dirty = false;
214                        return this;    //      dojox.charting.plot2d.Candlesticks
215                },
216                _animateCandlesticks: function(shape, voffset, vsize){
217                        fx.animateTransform(lang.delegate({
218                                shape: shape,
219                                duration: 1200,
220                                transform: [
221                                        {name: "translate", start: [0, voffset - (voffset/vsize)], end: [0, 0]},
222                                        {name: "scale", start: [1, 1/vsize], end: [1, 1]},
223                                        {name: "original"}
224                                ]
225                        }, this.animate)).play();
226                }
227        });
228});
Note: See TracBrowser for help on using the repository browser.