4dd2a4b248e03a05b212e030a04c4c37bd54857c
[mandelbrot.git] / xulapp / chrome / mandelbrot / content / mandelbrot.js
1 var gColorPalette = getColorPalette('kairo');
2
3 function drawImage() {
4   var canvas = document.getElementById("mbrotImage");
5   if (canvas.getContext) {
6     var context = canvas.getContext("2d");
7
8     // example:
9     // context.fillStyle = "rgb(200,0,0)";
10     // context.fillRect (10, 10, 55, 50); // x, y, width, height
11     //
12     // context.fillStyle = "rgba(0, 0, 200, 0.5)";
13     // context.fillRect (30, 30, 55, 50);
14
15     var Cr_min = -2.0;
16     var Cr_max = 1.0;
17     var Cr_scale = Cr_max - Cr_min;
18
19     var Ci_min = -1.5;
20     var Ci_max = 1.5;
21     var Ci_scale = Ci_max - Ci_min;
22
23     var iterMax = 500;
24
25     for (var img_x = 0; img_x < canvas.width; img_x++) {
26       for (var img_y = 0; img_y < canvas.height; img_y++) {
27         var C = new complex(Cr_min + (img_x / canvas.width) * Cr_scale,
28                             Ci_min + (img_y / canvas.height) * Ci_scale);
29         window.setTimeout(drawPoint, 0, context, img_x, img_y, C, iterMax);
30       }
31     }
32   }
33 }
34
35 function complex(aReal, aImag) {
36   this.r = aReal;
37   this.i = aImag;
38   this.square = function() {
39     return new complex(this.r * this.r - this.i * this.i,
40                        2 * this.r * this.i);
41   }
42   this.dist = function() {
43     return Math.sqrt(this.r * this.r + this.i * this.i);
44   }
45   this.add = function(aComplex) {
46     return new complex(this.r + aComplex.r, this.i + aComplex.i);
47   }
48 }
49
50 function mandelbrotValue (aC, aIterMax) {
51   var Z = new complex(0.0, 0.0);
52   for (var iter = 0; iter < aIterMax; iter++) {
53     Z = Z.square().add(aC);
54     if (Z.r * Z.r + Z.i * Z.i > 256) { break; }
55   }
56   return iter;
57 }
58
59 function getColor(aIterValue, aIterMax) {
60   var standardizedValue = Math.round(aIterValue * 1024 / aIterMax);
61   return gColorPalette[standardizedValue];
62   if (aIterValue == aIterMax) {
63     return "rgb(0,0,0)";
64   }
65   else {
66     //return "rgb(" + img_x + "," + img_y + ",0)";
67     return "rgb(255,255,255)";
68   }
69 }
70
71 function getColorPalette(palName) {
72   var palette = [];
73   switch (palName) {
74     case 'bw':
75       for (var i = 0; i < 1024; i++) {
76         palette[i] = 'rgb(255,255,255)';
77       }
78       palette[1024] = 'rgb(0,0,0)';
79       break;
80     case 'kairo':
81       // outer areas
82       for (var i = 0; i < 32; i++) {
83         var cc1 = Math.floor(i * 127 / 31);
84         var cc2 = 170 - Math.floor(i * 43 / 31);
85         palette[i] = 'rgb(' + cc1 + ',' + cc2 + ',' + cc1 + ')';
86       }
87       // inner areas
88       for (var i = 0; i < 51; i++) {
89         var cc = Math.floor(i * 170 / 50);
90         palette[32 + i] = 'rgb(' + cc + ',0,' + (170 + cc) + ')';
91       }
92       // corona
93       for (var i = 0; i < 101; i++) {
94         var cc = Math.floor(i * 200 / 100);
95         palette[83 + i] = 'rgb(255,' + cc + ',0)';
96       }
97       // inner corona
98       for (var i = 0; i < 201; i++) {
99         var cc1 = 255 - Math.floor(i * 85 / 200);
100         var cc2 = 200 - Math.floor(i * 30 / 200);
101         var cc3 = Math.floor(i * 170 / 200);
102         palette[184 + i] = 'rgb(' + cc1 + ',' + cc2 + ',' + cc3 + ')';
103       }
104       for (var i = 0; i < 301; i++) {
105         var cc1 = 170 - Math.floor(i * 43 / 300);
106         var cc2 = 170 + Math.floor(i * 85 / 300);
107         palette[385 + i] = 'rgb(' + cc1 + ',' + cc1 + ',' + cc2 + ')';
108       }
109       for (var i = 0; i < 338; i++) {
110         var cc = 127 + Math.floor(i * 128 / 337);
111         palette[686 + i] = 'rgb(' + cc + ',' + cc + ',255)';
112       }
113       palette[1024] = 'rgb(0,0,0)';
114       break;
115     case 'rainbow-linear1':
116       for (var i = 0; i < 256; i++) {
117         palette[i] = 'rgb(' + i + ',0,0)';
118         palette[256 + i] = 'rgb(255,' + i + ',0)';
119         palette[512 + i] = 'rgb(' + (255 - i) + ',255,' + i + ')';
120         palette[768 + i] = 'rgb(' + i + ',' + (255 - i) + ',255)';
121       }
122       palette[1024] = 'rgb(0,0,0)';
123       break;
124   }
125 /*
126 Select Case palnr
127 Case 1  'Standard-Palette (QB-Colors)
128      For i = 0 To 1024
129          xx = CInt(i * 500 / 1024 + 2)
130          If xx <= 15 Then clr = xx
131          If xx > 15 Then clr = CInt(Sqr((xx - 15 + 1) * 15 ^ 2 / 485))
132          If xx >= 500 Then clr = 0
133          palette(i) = QBColor(clr)
134      Next
135 Case 3  'Regenbogen-Palette 1 (qu.)
136      For i = 0 To 33
137          clr = CInt(i * 255 / 33)
138          palette(i) = RGB(clr, 0, 0)
139      Next
140      For i = 0 To 136
141          clr = CInt(i * 255 / 136)
142          palette(34 + i) = RGB(255, clr, 0)
143      Next
144      For i = 0 To 306
145          clr = CInt(i * 255 / 306)
146          palette(171 + i) = RGB(255 - clr, 255, clr)
147      Next
148      For i = 0 To 545
149          clr = CInt(i * 255 / 545)
150          palette(478 + i) = RGB(clr, 255 - clr, 255)
151      Next
152 Case 4  'Regenbogen-Palette 2 (linear)
153      For i = 0 To 204
154          clr = CInt(i * 255 / 204)
155          palette(i) = RGB(255, clr, 0)
156          palette(204 + i) = RGB(255 - clr, 255, 0)
157          palette(409 + i) = RGB(0, 255, clr)
158          palette(614 + i) = RGB(0, 255 - clr, 255)
159          palette(819 + i) = RGB(clr, 0, 255)
160      Next
161 Case 5  'Regenbogen-Palette 2 (qu.)
162      For i = 0 To 18
163          clr = CInt(i * 255 / 18)
164          palette(i) = RGB(255, clr, 0)
165      Next
166      For i = 0 To 73
167          clr = CInt(i * 255 / 73)
168          palette(20 + i) = RGB(255 - clr, 255, 0)
169      Next
170      For i = 0 To 167
171          clr = CInt(i * 255 / 167)
172          palette(93 + i) = RGB(0, 255, clr)
173      Next
174      For i = 0 To 297
175          clr = CInt(i * 255 / 297)
176          palette(261 + i) = RGB(0, 255 - clr, 255)
177      Next
178      For i = 0 To 464
179          clr = CInt(i * 255 / 464)
180          palette(559 + i) = RGB(clr, 0, 255)
181      Next
182 */
183   return palette;
184 }
185
186 function drawPoint(context, img_x, img_y, C, iterMax) {
187   var itVal = mandelbrotValue(C, iterMax);
188   context.fillStyle = getColor(itVal, iterMax);
189   context.fillRect (img_x, img_y, 1, 1); // x, y, width, height
190 }
191
192 function saveImage() {
193   // should call filepicker!
194   saveCanvas(document.getElementById("mbrotImage"), "/home/robert/temp/canvas-save.png")
195 }
196
197 // function below is from from http://developer.mozilla.org/en/docs/Code_snippets:Canvas
198 function saveCanvas(canvas, destFile) {
199   // convert string filepath to an nsIFile
200   var file = Components.classes["@mozilla.org/file/local;1"]
201                        .createInstance(Components.interfaces.nsILocalFile);
202   file.initWithPath(destFile);
203
204   // create a data url from the canvas and then create URIs of the source and targets  
205   var io = Components.classes["@mozilla.org/network/io-service;1"]
206                      .getService(Components.interfaces.nsIIOService);
207   var source = io.newURI(canvas.toDataURL("image/png", ""), "UTF8", null);
208   var target = io.newFileURI(file);
209
210   // prepare to save the canvas data
211   var persist = Components.classes["@mozilla.org/embedding/browser/nsWebBrowserPersist;1"]
212                           .createInstance(Components.interfaces.nsIWebBrowserPersist);
213
214   persist.persistFlags = Components.interfaces.nsIWebBrowserPersist.PERSIST_FLAGS_REPLACE_EXISTING_FILES;
215   persist.persistFlags |= Components.interfaces.nsIWebBrowserPersist.PERSIST_FLAGS_AUTODETECT_APPLY_CONVERSION;
216
217   // displays a download dialog (remove these 3 lines for silent download)
218   var xfer = Components.classes["@mozilla.org/transfer;1"]
219                        .createInstance(Components.interfaces.nsITransfer);
220   xfer.init(source, target, "", null, null, null, persist);
221   persist.progressListener = xfer;
222
223   // save the canvas data to the file
224   persist.saveURI(source, null, null, null, null, file);
225 }
226
227 // function below is from http://developer.mozilla.org/en/docs/How_to_Quit_a_XUL_Application
228 function quitApp(aForceQuit) {
229   var appStartup = Components.classes['@mozilla.org/toolkit/app-startup;1']
230                              .getService(Components.interfaces.nsIAppStartup);
231
232   // eAttemptQuit will try to close each XUL window, but the XUL window can cancel the quit
233   // process if there is unsaved data. eForceQuit will quit no matter what.
234   var quitSeverity = aForceQuit ? Components.interfaces.nsIAppStartup.eForceQuit :
235                                   Components.interfaces.nsIAppStartup.eAttemptQuit;
236   appStartup.quit(quitSeverity);
237 }