1 | define([ |
---|
2 | "dojo/_base/kernel", |
---|
3 | "dojo/_base/declare", |
---|
4 | "dojo/_base/lang", |
---|
5 | "dojo/number", |
---|
6 | "dijit/_base/manager", |
---|
7 | "dijit/_WidgetBase", |
---|
8 | "dijit/_TemplatedMixin", |
---|
9 | "dojox/math/_base" |
---|
10 | ], function(kernel, declare, lang, number, dijit, WidgetBase, TemplatedMixin, math){ |
---|
11 | |
---|
12 | kernel.experimental("dojox.calc"); |
---|
13 | |
---|
14 | var calcEnv, calc; // private |
---|
15 | |
---|
16 | var magicBigInt = (1 << 30) - 35; // 2^30 - 35 is a prime that ensures approx(n/(2^k)) != n/(2^k) for k >= 1 and n < 2^k |
---|
17 | |
---|
18 | var Executor = declare( |
---|
19 | "dojox.calc._Executor", |
---|
20 | [WidgetBase, TemplatedMixin], |
---|
21 | { |
---|
22 | // summary: |
---|
23 | // A graphing, scientific calculator |
---|
24 | // |
---|
25 | |
---|
26 | templateString: '<iframe src="' + require.toUrl("dojox/calc/_ExecutorIframe.html") + |
---|
27 | '" style="display:none;" onload="if(arguments[0] && arguments[0].Function)'+dijit._scopeName+'.byNode(this)._onLoad(arguments[0])"></iframe>', |
---|
28 | |
---|
29 | _onLoad: function(env){ |
---|
30 | // summary: |
---|
31 | // prepare for communications between the user and the calculator by saving the calculator environment, storing the prompt function locally, and making dojox.math available |
---|
32 | |
---|
33 | calcEnv = env; |
---|
34 | env.outerPrompt = window.prompt; // for IE who can't execute the iframe's prompt method without notifying the user first |
---|
35 | // let the user call dojo math functions |
---|
36 | env.dojox = {math: {}}; |
---|
37 | for(var f in math){ env.dojox.math[f] = lang.hitch(math, f); } |
---|
38 | if("toFrac" in calc){ |
---|
39 | env.toFracCall = lang.hitch(calc, 'toFrac'); |
---|
40 | this.Function('toFrac', 'x', "return toFracCall(x)"); |
---|
41 | } |
---|
42 | |
---|
43 | env.isJavaScriptLanguage = number.format(1.5, {pattern:'#.#'}) == "1.5"; |
---|
44 | env.Ans = 0; |
---|
45 | env.pi = Math.PI; |
---|
46 | env.eps = Math.E; |
---|
47 | |
---|
48 | env.powCall = lang.hitch(calc, 'pow'); |
---|
49 | |
---|
50 | // TODO add Degrees support to trig functions |
---|
51 | |
---|
52 | |
---|
53 | //this.normalizedFunction('toString', 'number, radix', "return number.toString(radix)"); |
---|
54 | this.normalizedFunction('sqrt', 'x', "return Math.sqrt(x)"); |
---|
55 | this.normalizedFunction('sin', 'x', "return Math.sin(x)"); |
---|
56 | this.normalizedFunction('cos', 'x', "return Math.cos(x)"); |
---|
57 | this.normalizedFunction('tan', 'x', "return Math.tan(x)"); |
---|
58 | this.normalizedFunction('asin', 'x', "return Math.asin(x)"); |
---|
59 | this.normalizedFunction('acos', 'x', "return Math.acos(x)"); |
---|
60 | this.normalizedFunction('atan', 'x', "return Math.atan(x)"); |
---|
61 | this.normalizedFunction('atan2', 'y, x', "return Math.atan2(y, x)"); |
---|
62 | this.normalizedFunction('Round', 'x', "return Math.round(x)"); |
---|
63 | this.normalizedFunction('Int', 'x', "return Math.floor(x)"); |
---|
64 | this.normalizedFunction('Ceil', 'x', "return Math.ceil(x)"); |
---|
65 | this.normalizedFunction('ln', 'x', "return Math.log(x)"); |
---|
66 | this.normalizedFunction('log', 'x', "return Math.log(x)/Math.log(10)"); |
---|
67 | this.normalizedFunction('pow', 'x, y', "return powCall(x,y)"); |
---|
68 | this.normalizedFunction('permutations', 'n, r', "return dojox.math.permutations(n, r);"); |
---|
69 | this.normalizedFunction('P', 'n, r', "return dojox.math.permutations(n, r);"); |
---|
70 | this.normalizedFunction('combinations', 'n, r', "return dojox.math.combinations(n, r);"); |
---|
71 | this.normalizedFunction('C', 'n, r', "return dojox.math.combinations(n, r)"); |
---|
72 | |
---|
73 | this.normalizedFunction('toRadix', 'number, baseOut', "if(!baseOut){ baseOut = 10; } if(typeof number == 'string'){ number = parseFloat(number); }return number.toString(baseOut);"); |
---|
74 | this.normalizedFunction('toBin', 'number', "return toRadix(number, 2)"); |
---|
75 | this.normalizedFunction('toOct', 'number', "return toRadix(number, 8)"); |
---|
76 | this.normalizedFunction('toHex', 'number', "return toRadix(number, 16)"); |
---|
77 | this.onLoad(); |
---|
78 | }, |
---|
79 | |
---|
80 | onLoad: function(){ |
---|
81 | // summary: |
---|
82 | // this should be overwritten and become a great place for making user predefined functions |
---|
83 | }, |
---|
84 | Function: function(name, args, body){ |
---|
85 | // summary: |
---|
86 | // create an anonymous function to run the code the parser generates from the user input. |
---|
87 | // name: |
---|
88 | // this argument is simply a String that represents the name of the function being evaluated. It can be undefined, but in that case the function is a one time use. |
---|
89 | // args: String |
---|
90 | // the function arguments |
---|
91 | // body: String |
---|
92 | // the function body |
---|
93 | return lang.hitch(calcEnv, calcEnv.Function.apply(calcEnv, arguments)); |
---|
94 | }, |
---|
95 | normalizedFunction: function(name, args, body){ |
---|
96 | return lang.hitch(calcEnv, calcEnv.normalizedFunction.apply(calcEnv, arguments)); |
---|
97 | }, |
---|
98 | deleteFunction: function(name){ |
---|
99 | calcEnv[name] = undefined; |
---|
100 | delete calcEnv[name]; |
---|
101 | }, |
---|
102 | eval: function(text){ |
---|
103 | // summary: |
---|
104 | // create an anonymous function to run the code the parser generates from the user input. |
---|
105 | // text: String |
---|
106 | // the user input that needs to be parsed |
---|
107 | return calcEnv.eval.apply(calcEnv, arguments); |
---|
108 | }, |
---|
109 | destroy: function(){ |
---|
110 | this.inherited(arguments); |
---|
111 | calcEnv = null; // assist garbage collection |
---|
112 | } |
---|
113 | }); |
---|
114 | |
---|
115 | return calc = { |
---|
116 | pow: function(/*Number*/ base, /*Number*/ exponent){ |
---|
117 | // summary: |
---|
118 | // Computes base ^ exponent |
---|
119 | // Wrapper to Math.pow(base, exponent) to handle (-27) ^ (1/3) |
---|
120 | |
---|
121 | function isInt(n){ |
---|
122 | return Math.floor(n) == n; |
---|
123 | } |
---|
124 | |
---|
125 | if(base >= 0 || isInt(exponent)){ |
---|
126 | return Math.pow(base, exponent); |
---|
127 | }else{ // e.g. (1/3) root of -27 = -3 |
---|
128 | var inv = 1 / exponent; |
---|
129 | // e.g. 1 / (1/3) must be an odd integer |
---|
130 | return (isInt(inv) && (inv & 1)) ? -Math.pow(-base, exponent) : NaN; |
---|
131 | } |
---|
132 | }, |
---|
133 | approx: function(/*Number*/ r){ |
---|
134 | // summary: |
---|
135 | // Return a less exact approximation of r such that approx(r * (1 +- eps)) == approx(r) |
---|
136 | if(typeof r == "number"){ |
---|
137 | return Math.round(r * magicBigInt) / magicBigInt; |
---|
138 | } |
---|
139 | return r; |
---|
140 | }, |
---|
141 | _Executor: Executor |
---|
142 | }; |
---|
143 | }); |
---|