source: Dev/branches/rest-dojo-ui/client/dojox/charting/plot2d/OHLC.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.3 KB
Line 
1define(["dojo/_base/lang", "dojo/_base/array", "dojo/_base/declare", "./Base", "./common",
2        "dojox/lang/functional", "dojox/lang/functional/reversed", "dojox/lang/utils", "dojox/gfx/fx"],
3        function(lang, arr, declare, 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 }
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.OHLC", Base, {
16                //      summary:
17                //              A plot that represents typical open/high/low/close (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 chart to place
27                },
28                optionalParams: {
29                        minBarSize: 1,  // minimal bar size in pixels
30                        maxBarSize: 1,  // maximal bar size 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, OHLC 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;
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.OHLC
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(low > high){
154                                                        var tmp = high;
155                                                        high = low;
156                                                        low = tmp;
157                                                }
158
159                                                if(width >= 1){
160                                                        var hl = {x1: width/2, x2: width/2, y1: y - high, y2: y - low},
161                                                                op = {x1: 0, x2: ((width/2) + ((finalTheme.series.stroke.width||1)/2)), y1: y-open, y2: y-open},
162                                                                cl = {x1: ((width/2) - ((finalTheme.series.stroke.width||1)/2)), x2: width, y1: y-close, y2: y-close};
163                                                        var shape = s.createGroup();
164                                                        shape.setTransform({dx: x, dy: 0});
165                                                        var inner = shape.createGroup();
166                                                        inner.createLine(hl).setStroke(finalTheme.series.stroke);
167                                                        inner.createLine(op).setStroke(finalTheme.series.stroke);
168                                                        inner.createLine(cl).setStroke(finalTheme.series.stroke);
169
170                                                        //      TODO: double check this.
171                                                        run.dyn.stroke = finalTheme.series.stroke;
172                                                        if(events){
173                                                                var o = {
174                                                                        element: "candlestick",
175                                                                        index:   j,
176                                                                        run:     run,
177                                                                        shape:   inner,
178                                                                        x:       x,
179                                                                        y:       y-Math.max(open, close),
180                                                                        cx:              width/2,
181                                                                        cy:              (y-Math.max(open, close)) + (Math.max(open > close ? open-close : close-open, 1)/2),
182                                                                        width:   width,
183                                                                        height:  Math.max(open > close ? open-close : close-open, 1),
184                                                                        data:    v
185                                                                };
186                                                                this._connectEvents(o);
187                                                                eventSeries[j] = o;
188                                                        }
189                                                }
190                                                if(this.animate){
191                                                        this._animateOHLC(shape, y - low, high - low);
192                                                }
193                                        }
194                                }
195                                this._eventSeries[run.name] = eventSeries;
196                                run.dirty = false;
197                        }
198                        this.dirty = false;
199                        return this;    //      dojox.charting.plot2d.OHLC
200                },
201                _animateOHLC: function(shape, voffset, vsize){
202                        fx.animateTransform(lang.delegate({
203                                shape: shape,
204                                duration: 1200,
205                                transform: [
206                                        {name: "translate", start: [0, voffset - (voffset/vsize)], end: [0, 0]},
207                                        {name: "scale", start: [1, 1/vsize], end: [1, 1]},
208                                        {name: "original"}
209                                ]
210                        }, this.animate)).play();
211                }
212        });
213});
Note: See TracBrowser for help on using the repository browser.