source: Dev/branches/rest-dojo-ui/client/dojox/calc/Grapher.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: 19.9 KB
Line 
1define([
2        "dojo/_base/declare",
3        "dojo/_base/lang",
4        "dojo/_base/window",
5        "dojo/dom-construct",
6        "dojo/dom-class",
7        "dojo/dom-style",
8        "dijit/_WidgetBase",
9        "dijit/_WidgetsInTemplateMixin",
10        "dijit/_TemplatedMixin",
11        "dojox/math/_base",
12        "dijit/registry",
13        "dijit/form/DropDownButton",
14        "dijit/TooltipDialog",
15        "dijit/form/TextBox",
16        "dijit/form/CheckBox",
17        "dijit/ColorPalette",
18        "dojox/charting/Chart",
19        "dojox/charting/axis2d/Default",
20        "dojox/charting/plot2d/Default",
21        "dojox/charting/plot2d/Lines",
22        "dojox/charting/themes/Tufte",
23        "dojo/colors",
24        "dojo/text!./templates/Grapher.html",
25        "dojox/calc/_Executor",
26        "dijit/form/Button", // template
27        "dijit/form/Select" // template
28], function(declare, lang, win, domConstruct, domClass, domStyle, WidgetBase, WidgetsInTemplateMixin, TemplatedMixin, math, registry, DropDownButton, TooltipDialog, TextBox, CheckBox, ColorPalette, Chart, axis2d, plot2d, Lines, Tufte, colors, template, calc){
29
30        // summary
31        //      provide static functions for Grapher
32        var
33                epsilon = 1e-15 / 9,
34                bigNumber = 1e200,
35                log2 = Math.log(2),
36                defaultParams = {graphNumber:0, fOfX:true, color:{stroke:"black"}};
37
38
39        /*=====
40                WidgetBase = dijit._WidgetBase;
41                WidgetsInTemplateMixin = dijit._WidgetsInTemplateMixin;
42                TemplatedMixin = dijit._TemplatedMixin;
43        =====*/
44        var Grapher = declare(
45                "dojox.calc.Grapher",
46                [WidgetBase, TemplatedMixin, WidgetsInTemplateMixin],
47        {
48                // summary:
49                //              The dialog layout for making graphs
50                //
51                templateString: template,
52
53                addXYAxes: function(chart){
54                        // summary:
55                        //              add or re-add the default x/y axes to the Chart provided
56                        // params:
57                        //      chart is an instance of dojox.charting.Chart
58
59                        return chart.addAxis("x", {
60                                max: parseInt(this.graphMaxX.get("value")),
61                                min: parseInt(this.graphMinX.get("value")),
62                                majorLabels: true,
63                                minorLabels: true,
64                                //includeZero: true,
65                                minorTicks: false,
66                                microTicks: false,
67                                //majorTickStep: 1,
68                                htmlLabels: true,
69                                labelFunc: function(value){
70                                        return value;
71                                },
72                                maxLabelSize: 30,
73                                fixUpper: "major", fixLower: "major",
74                                majorTick: { length: 3 }
75                        }).
76                        addAxis("y", {
77                                max: parseInt(this.graphMaxY.get("value")),
78                                min: parseInt(this.graphMinY.get("value")),
79                                labelFunc: function(value){
80                                        return value;
81                                },
82                                maxLabelSize: 50,
83                                vertical: true,
84                                // htmlLabels: false,
85                                microTicks: false,
86                                minorTicks: true,
87                                majorTick: { stroke: "black", length: 3 }
88                        });
89                },
90                selectAll: function(){
91                        // summary
92                        //      select all checkboxes inside the function table
93                        for(var i = 0; i < this.rowCount; i++){
94                                this.array[i][this.checkboxIndex].set("checked", true);
95                        }
96                },
97                deselectAll: function(){
98                        // summary
99                        //      deselect all checkboxes inside the function table
100                        for(var i = 0; i < this.rowCount; i++){
101                                this.array[i][this.checkboxIndex].set("checked", false);
102                        }
103                },
104                drawOne: function(i){
105                        // i is a the index to this.array
106                        // override me
107                },
108                onDraw: function(){
109                        console.log("Draw was pressed");
110                        // override me
111                },
112                erase: function(i){
113                        // summary:
114                        //      erase the chart inside this.array with the index i
115                        // params:
116                        //      i is the integer index to this.array that represents the current row number in the table
117                        var nameNum = 0;
118                        var name = "Series "+this.array[i][this.funcNumberIndex]+"_"+nameNum;
119                        while(name in this.array[i][this.chartIndex].runs){
120                                this.array[i][this.chartIndex].removeSeries(name);
121                                nameNum++;
122                                name = "Series "+this.array[i][this.funcNumberIndex]+"_"+nameNum;
123                        }
124                        this.array[i][this.chartIndex].render();
125                        this.setStatus(i, "Hidden");
126                },
127                onErase: function(){
128                        // summary:
129                        //      the erase button's onClick method
130                        //      it see's if the checkbox is checked and then erases it if it is.
131                        for(var i = 0; i < this.rowCount; i++){
132                                if(this.array[i][this.checkboxIndex].get("checked")){
133                                        this.erase(i);
134                                }
135                        }
136                },
137                onDelete: function(){
138                        // summary:
139                        //      the delete button's onClick method
140                        //      delete all of the selected rows
141                        for(var i = 0; i < this.rowCount; i++){
142                                if(this.array[i][this.checkboxIndex].get("checked")){
143                                        this.erase(i);
144                                        for(var k = 0; k < this.functionRef; k++){
145                                                if(this.array[i][k] && this.array[i][k]["destroy"]){
146                                                        this.array[i][k].destroy();
147                                                }
148                                        }
149                                        this.graphTable.deleteRow(i);
150                                        this.array.splice(i, 1);
151                                        this.rowCount--;
152                                        i--;
153                                }
154                        }
155                },
156                // attributes to name the indices of this.array
157                checkboxIndex:          0,
158                functionMode:           1,
159                expressionIndex:        2,
160                colorIndex:             3,
161                dropDownIndex:          4,
162                tooltipIndex:           5,
163                colorBoxFieldsetIndex:  6,
164                statusIndex:            7,
165                chartIndex:             8,
166                funcNumberIndex:        9,
167                evaluatedExpression:    10,
168                functionRef:            11,
169
170                createFunction: function(){
171                        // summary:
172                        //      create a new row in the table with all of the dojo objects.
173
174                        var tr = this.graphTable.insertRow(-1);
175                        this.array[tr.rowIndex] = [];
176                        var td = tr.insertCell(-1);
177                        var d = domConstruct.create('div');
178                        td.appendChild(d);
179                        var checkBox = new CheckBox({}, d);
180                        this.array[tr.rowIndex][this.checkboxIndex] = checkBox;
181                        domClass.add(d, "dojoxCalcCheckBox");
182
183                        td = tr.insertCell(-1);
184                        var funcMode = this.funcMode.get("value");
185                        d = win.doc.createTextNode(funcMode);
186                        td.appendChild(d);
187                        this.array[tr.rowIndex][this.functionMode] = funcMode;
188                        //domClass.add(d, "dojoxCalcFunctionMode");// cannot use text nodes
189
190                        td = tr.insertCell(-1);
191                        d = domConstruct.create('div');
192                        td.appendChild(d);
193                        var expression = new TextBox({}, d);
194                        this.array[tr.rowIndex][this.expressionIndex] = expression;
195                        domClass.add(d, "dojoxCalcExpressionBox");
196
197                        var b = domConstruct.create('div');
198                        var color = new ColorPalette({changedColor:this.changedColor}, b);
199                        domClass.add(b, "dojoxCalcColorPalette");
200
201                        this.array[tr.rowIndex][this.colorIndex] = color;
202
203                        var c = domConstruct.create('div');
204                        var dialog = new TooltipDialog({content:color}, c);
205                        this.array[tr.rowIndex][this.tooltipIndex] = dialog;
206                        domClass.add(c, "dojoxCalcContainerOfColor");
207
208                        td = tr.insertCell(-1);
209                        d = domConstruct.create('div');
210                        td.appendChild(d);
211
212                        var colorBoxFieldset = domConstruct.create('fieldset');
213                        domStyle.set(colorBoxFieldset, { backgroundColor: "black", width: "1em", height: "1em", display: "inline" });
214                        this.array[tr.rowIndex][this.colorBoxFieldsetIndex] = colorBoxFieldset;
215
216                        var drop = new DropDownButton({label:"Color ", dropDown:dialog}, d);
217                        drop.containerNode.appendChild(colorBoxFieldset);
218                        this.array[tr.rowIndex][this.dropDownIndex] = drop;
219                        domClass.add(d, "dojoxCalcDropDownForColor");
220
221                        /*td = tr.insertCell(-1);
222                        d = domConstruct.create('div');
223                        td.appendChild(d);
224                        var status = new TextBox({style:"width:50px", value:"Hidden", readOnly:true}, d);//hidden, drawn, or error
225                        this.array[tr.rowIndex][this.statusIndex] = status;
226                        domClass.add(d, "dojoxCalcStatusBox");*/
227
228                        td = tr.insertCell(-1);
229                        d = domConstruct.create('fieldset');
230                        d.innerHTML = "Hidden";
231                        this.array[tr.rowIndex][this.statusIndex] = d;
232                        domClass.add(d, "dojoxCalcStatusBox");
233                        td.appendChild(d);
234
235                        d = domConstruct.create('div');
236                        domStyle.set(d, { position: "absolute", left: "0px", top: "0px" })
237                        this.chartsParent.appendChild(d);
238                        this.array[tr.rowIndex][this.chartNodeIndex] = d;
239                        domClass.add(d, "dojoxCalcChart");
240                        var chart = new dojox.charting.Chart(d).setTheme(dojox.charting.themes.Tufte).
241                                addPlot("default", { type: "Lines", shadow:  {dx: 1, dy: 1, width: 2, color: [0, 0, 0, 0.3]} });
242                        this.addXYAxes(chart);
243                        this.array[tr.rowIndex][this.chartIndex] = chart;
244                        color.set("chart", chart);
245                        color.set("colorBox", colorBoxFieldset);
246                        color.set("onChange", lang.hitch(color, 'changedColor'));
247
248                        this.array[tr.rowIndex][this.funcNumberIndex] = this.funcNumber++;
249                        this.rowCount++;
250                },
251                setStatus: function(i, status){
252                        // summary:
253                        //      set the status of the row i to be status
254                        // params:
255                        //      i is an integer index of this.array as well as a row index
256                        //      status is a String, it is either Error, Hidden, or Drawn
257                        this.array[i][this.statusIndex].innerHTML = status; //this.array[i][this.statusIndex].set("value", status);
258                },
259                changedColor: function(){
260                        // summary:
261                        //      make the color of the chart the new color
262                        //      the context is changed to the colorPalette, and a reference to chart was added to it a an attribute
263                        var chart = this.get("chart");
264                        var colorBoxFieldset = this.get("colorBox");
265                        for(var i = 0; i < chart.series.length; i++){
266                                if(chart.series[i]["stroke"]){
267                                        if(chart.series[i].stroke["color"]){
268                                                chart.series[i]["stroke"].color = this.get("value");
269                                                chart.dirty = true;
270                                        }
271                                }
272                        }
273                        chart.render();
274                        domStyle.set(colorBoxFieldset, { backgroundColor: this.get("value") });
275                },
276                makeDirty: function(){
277                        // summary:
278                        //      if something in the window options is changed, this is called
279                        this.dirty = true;
280                },
281                checkDirty1: function(){
282                        // summary:
283                        //      to stay in sync with onChange, checkDirty is called with a timeout
284                        setTimeout(lang.hitch(this, 'checkDirty'), 0);
285                },
286                checkDirty: function(){
287                        // summary:
288                        //      adjust all charts in this.array according to any changes in window options
289                        if(this.dirty){
290                                // change the axes of all charts if it is dirty
291                                for(var i = 0; i < this.rowCount; i++){
292                                        this.array[i][this.chartIndex].removeAxis("x");
293                                        this.array[i][this.chartIndex].removeAxis("y");
294                                        this.addXYAxes(this.array[i][this.chartIndex]);
295                                }
296                                this.onDraw();
297                        }
298                        this.dirty = false;
299                },
300                postCreate: function(){
301                        // summary
302                        //      add Event handlers, some additional attributes, etc
303                        this.inherited(arguments);// this is super class postCreate
304                        this.createFunc.set("onClick", lang.hitch(this, 'createFunction'));
305
306                        this.selectAllButton.set("onClick", lang.hitch(this, 'selectAll'));
307                        this.deselectAllButton.set("onClick", lang.hitch(this, 'deselectAll'));
308
309                        this.drawButton.set("onClick", lang.hitch(this, 'onDraw'));
310                        this.eraseButton.set("onClick", lang.hitch(this, 'onErase'));
311                        this.deleteButton.set("onClick", lang.hitch(this, 'onDelete'));
312
313                        this.dirty = false;
314                        this.graphWidth.set("onChange", lang.hitch(this, 'makeDirty'));
315                        this.graphHeight.set("onChange", lang.hitch(this, 'makeDirty'));
316                        this.graphMaxX.set("onChange", lang.hitch(this, 'makeDirty'));
317                        this.graphMinX.set("onChange", lang.hitch(this, 'makeDirty'));
318                        this.graphMaxY.set("onChange", lang.hitch(this, 'makeDirty'));
319                        this.graphMinY.set("onChange", lang.hitch(this, 'makeDirty'));
320                        this.windowOptionsInside.set("onClose", lang.hitch(this, 'checkDirty1'));
321
322                        this.funcNumber = 0;
323                        this.rowCount = 0;
324                        this.array = [];
325
326                },
327                startup: function(){
328                        // summary
329                        //      make sure the parent has a close button if it needs to be able to close
330                        this.inherited(arguments);// this is super class startup
331                        // close is only valid if the parent is a widget with a close function
332                        var parent = registry.getEnclosingWidget(this.domNode.parentNode);
333                        if(parent && typeof parent.close == "function"){
334                                this.closeButton.set("onClick", lang.hitch(parent, 'close'));
335                        }else{
336                                domStyle.set(this.closeButton.domNode, { display: "none" }); // hide the button
337                        }
338                        // add one row at the start
339                        this.createFunction();
340
341                        // make the graph bounds appear initially
342                        this.array[0][this.checkboxIndex].set("checked", true);
343                        this.onDraw();
344                        this.erase(0);
345                        this.array[0][this.expressionIndex].value = "";
346                }
347        });
348
349        return lang.mixin(calc, {
350                draw: function(/*Chart*/ chart, /*Function*/ functionToGraph, params){
351                        // summary
352                        //      graph a chart with the given function.
353                        // params
354                        //      chart is a dojox.charting.Chart object, functionToGraph is a function with one numeric parameter (x or y typically)
355                        //      and params is an Object the can contain the number of the graph in the chart it is (an integer), a boolean saying if the functionToGraph is a function of x (otherwise y)
356                        //      and the color, which is an object with a stroke with a color's name eg: color:{stroke:"black"}
357
358                        params = lang.mixin({}, defaultParams, params);
359                        chart.fullGeometry();
360                        var x;
361                        var y;
362                        var points;
363                        if(params.fOfX==true){
364                                x = 'x';
365                                y = 'y';
366                                points = calc.generatePoints(functionToGraph, x, y, chart.axes.x.scaler.bounds.span, chart.axes.x.scaler.bounds.lower, chart.axes.x.scaler.bounds.upper, chart.axes.y.scaler.bounds.lower, chart.axes.y.scaler.bounds.upper);
367                        }else{
368                                x = 'y';
369                                y = 'x';
370                                points = calc.generatePoints(functionToGraph, x, y, chart.axes.y.scaler.bounds.span, chart.axes.y.scaler.bounds.lower, chart.axes.y.scaler.bounds.upper, chart.axes.x.scaler.bounds.lower, chart.axes.x.scaler.bounds.upper);
371                        }
372
373                        var i = 0;
374
375                        if(points.length > 0){
376                                for(; i < points.length; i++){
377                                        if(points[i].length>0){
378                                                chart.addSeries("Series "+params.graphNumber+"_"+i, points[i], params.color);
379                                        }
380                                }
381                        }
382                        // you only need to remove the excess i's
383                        var name = "Series "+params.graphNumber+"_"+i;
384                        while(name in chart.runs){
385                                chart.removeSeries(name);
386                                i++;
387                                name = "Series "+params.graphNumber+"_"+i;
388                        }
389                        chart.render();
390                        return points;
391                },
392
393                generatePoints: function(/*Function*/ funcToGraph, /*String*/ x, /*String*/ y, /*Number*/ width, /*Number*/ minX, /*Number*/ maxX, /*Number*/ minY, /*Number*/ maxY){
394                        // summary:
395                        //      create the points with information about the graph.
396                        // params:
397                        //      funcToGraph is a function with one numeric parameter (x or y typically)
398                        //      x and y are Strings which always have the values of "x" or "y".  If y="x" and x="y" then it is creating points for the function as though it was a function of y
399                        //      Number minX, Number maxX, Number minY, Number maxY are all bounds of the chart.  If x="y" then maxY should be the maximum bound of x rather than y
400                        //      Number width is the pixel width of the chart
401                        // output:
402                        //      an array of arrays of points
403                        var pow2 = (1 << Math.ceil(Math.log(width) / log2));
404                        var
405                                dx = (maxX - minX) / pow2, // divide by 2^n instead of width to avoid loss of precision
406                                points = [], // [{x:value, y:value2},...]
407                                series = 0,
408                                slopeTrend,
409                                slopeTrendTemp;
410
411                        points[series] = [];
412
413                        var i = minX, k, p;
414                        for(var counter = 0; counter <= pow2; i += dx, counter++){
415                                p = {};
416                                p[x] = i;
417                                p[y] = funcToGraph({_name:x, _value:i, _graphing:true});//funcToGraph(i);
418                                if(p[x] == null || p[y] == null){
419                                        return {};// someone pushed cancel in the val code
420                                }
421                                if(isNaN(p[y]) || isNaN(p[x])){
422                                        continue;
423                                }
424                                points[series].push(p);
425
426                                if(points[series].length == 3){
427                                        slopeTrend = getSlopePairTrend(slope(points[series][points[series].length - 3], points[series][points[series].length-2]), slope(points[series][points[series].length-2], points[series][points[series].length-1]));
428                                        continue;
429                                }
430                                if(points[series].length < 4){
431                                        continue;
432                                }
433
434                                slopeTrendTemp = getSlopePairTrend(slope(points[series][points[series].length - 3], points[series][points[series].length-2]), slope(points[series][points[series].length-2], points[series][points[series].length-1]));
435                                if(slopeTrend.inc != slopeTrendTemp.inc || slopeTrend.pos != slopeTrendTemp.pos){
436                                        // var a = asymptoteSearch(funcToGraph, points[series][points[series].length - 2], points[series][points[series].length-1]);
437                                        var a = asymptoteSearch(funcToGraph, points[series][points[series].length - 3], points[series][points[series].length-1]);
438                                        p = points[series].pop();
439                                        // this pop was added after changing the var a line above
440                                        points[series].pop();
441                                        for(var j = 0; j < a[0].length; j++){
442                                                points[series].push(a[0][j]);
443                                        }
444                                        for(k = 1; k < a.length; k++){
445                                                points[++series] = a.pop();
446                                        }
447                                        points[series].push(p);
448                                        slopeTrend = slopeTrendTemp;
449                                }
450                        }
451                        while(points.length > 1){
452                                for(k = 0; k < points[1].length; k++){
453                                        if(points[0][points[0].length - 1][x] == points[1][k][x]){
454                                                continue;
455                                        }
456                                        points[0].push(points[1][k]);
457                                }
458                                points.splice(1, 1);
459                        }
460                        points = points[0];
461
462                        // make new series when it goes off the graph
463                        var s = 0;
464                        var points2 = [ [] ];
465                        for(k = 0; k < points.length; k++){
466                                var x1, y1, b, slope1;
467                                if(isNaN(points[k][y]) || isNaN(points[k][x])){
468                                        while(isNaN(points[k][y]) || isNaN(points[k][x])){
469                                                points.splice(k, 1);
470                                        }
471                                        points2[++s] = [];
472                                        k--;
473                                }else if(points[k][y] > maxY || points[k][y] < minY){
474                                        // make the last point's y equal maxY and find a matching x
475                                        if(k > 0 && points[k - 1].y!=minY && points[k - 1].y!=maxY){
476                                                slope1 = slope(points[k - 1], points[k]);
477                                                if(slope1 > bigNumber){
478                                                        slope1 = bigNumber;
479                                                }else if(slope1 < -bigNumber){
480                                                        slope1 = -bigNumber;
481                                                }
482                                                if(points[k][y] > maxY){
483                                                        y1 = maxY;
484                                                }else{
485                                                        y1 = minY;
486                                                }
487                                                b = points[k][y] - slope1 * points[k][x];
488                                                x1 = (y1 - b) / slope1;
489
490                                                p = {};
491                                                p[x] = x1;
492                                                p[y] = funcToGraph(x1);//y1;//
493
494                                                if(p[y]!=y1){
495                                                        p = findMinOrMaxY(funcToGraph, points[k - 1], points[k], y1);
496                                                }
497
498                                                points2[s].push(p);
499                                                // setup the next series
500                                                points2[++s] = []
501                                        }
502                                        var startK = k;
503                                        while(k < points.length && (points[k][y] > maxY || points[k][y] < minY)){
504                                                k++;
505                                        }
506                                        if(k >= points.length){
507                                                if(points2[s].length == 0){
508                                                        points2.splice(s, 1);
509                                                }
510                                                break;
511                                        }
512                                        // connect the end graph
513                                        if(k > 0 && points[k].y != minY && points[k].y != maxY){
514                                                slope1 = slope(points[k - 1], points[k]);
515                                                if(slope1 > bigNumber){
516                                                        slope1 = bigNumber;
517                                                }else if(slope1 < -bigNumber){
518                                                        slope1 = -bigNumber;
519                                                }
520                                                if(points[k - 1][y] > maxY){
521                                                        y1 = maxY;
522                                                }else{
523                                                        y1 = minY;
524                                                }
525                                                b = points[k][y] - slope1 * points[k][x];
526                                                x1 = (y1 - b) / slope1;
527
528                                                p = {};
529                                                p[x] = x1;
530                                                p[y] = funcToGraph(x1);//y1;//
531                                                if(p[y]!=y1){
532                                                        p = findMinOrMaxY(funcToGraph, points[k - 1], points[k], y1);
533                                                }
534                                                points2[s].push(p);
535                                                points2[s].push(points[k]);
536                                        }
537                                }else{
538                                        points2[s].push(points[k]);
539                                }
540                        }
541                        return points2;
542
543                        function findMinOrMaxY(funcToGraph, left, right, minMaxY){
544
545                                while(left<=right){
546                                        var midX = (left[x]+right[x])/2;
547                                        var mid = {};
548                                        mid[x] = midX;
549                                        mid[y] = funcToGraph(mid[x]);
550
551                                        if(minMaxY==mid[y]||mid[x]==right[x]||mid[x]==left[x]){
552                                                return mid;
553                                        }
554
555                                        var moveTowardsLarger = true;
556                                        if(minMaxY<mid[y]){
557                                                moveTowardsLarger = false;
558                                        }
559
560                                        if(mid[y]<right[y]){
561                                                if(moveTowardsLarger){
562                                                        left = mid;
563                                                }else{
564                                                        right = mid;
565                                                }
566                                        }else if(mid[y]<left[y]){
567                                                if(!moveTowardsLarger){
568                                                        left = mid;
569                                                }else{
570                                                        right = mid;
571                                                }
572                                        }
573                                }
574                                return NaN;
575                        }
576
577                        function asymptoteSearch(funcToGraph, pointStart, pointStop){
578                                var
579                                        pointTemp = [ [], [] ],
580                                        left = pointStart,
581                                        right = pointStop,
582                                        midpoint;
583
584
585                                while(left[x] <= right[x]){
586                                        var midX = (left[x] + right[x]) / 2;
587
588                                        midpoint = {};
589                                        midpoint[x] = midX;
590                                        midpoint[y] = funcToGraph(midX);
591
592                                        var rx = nextNumber(midpoint[x]);
593                                        var rightPoint = {};
594                                        rightPoint[x] = rx;
595                                        rightPoint[y] = funcToGraph(rx);
596
597                                        if(Math.abs(rightPoint[y]) >= Math.abs(midpoint[y])){
598                                                pointTemp[0].push(midpoint);
599                                                left = rightPoint;
600                                        }else{
601                                                pointTemp[1].unshift(midpoint);
602                                                if(right[x] == midpoint[x]){
603                                                        break;
604                                                }
605                                                right = midpoint;
606                                        }
607                                               
608                                }
609                                return pointTemp;
610                        }
611
612                        function getSlopePairTrend(slope1, slope2){
613                                var
614                                        isInc = false,
615                                        isPos = false;
616
617                                if(slope1 < slope2){
618                                        isInc = true;
619                                }
620                                if(slope2 > 0){
621                                        isPos = true;
622                                }
623                                return { inc: isInc, pos: isPos };
624                        }
625
626                        function nextNumber(v){
627                                var delta;
628                                if(v > -1 && v < 1){
629                                        if(v < 0){ // special handling as we approach 0
630                                                if(v >= -epsilon){
631                                                        delta = -v; // always stop at 0
632                                                }else{
633                                                        delta = v / Math.ceil(v / epsilon); // divide distance to 0 into equal tiny chunks
634                                                }
635                                        }else{
636                                                delta = epsilon;
637                                        }
638                                }else{
639                                        delta = Math.abs(v) * epsilon;
640                                }
641                                return v + delta;
642                        }
643
644                        function slope(p1, p2){
645                                return (p2[y] - p1[y]) / (p2[x] - p1[x]);
646                        }
647                },
648                Grapher: Grapher
649        });
650});
Note: See TracBrowser for help on using the repository browser.