1 /*
  2     Copyright 2008-2021
  3         Matthias Ehmann,
  4         Michael Gerhaeuser,
  5         Carsten Miller,
  6         Bianca Valentin,
  7         Alfred Wassermann,
  8         Peter Wilfahrt
  9 
 10     This file is part of JSXGraph.
 11 
 12     JSXGraph is free software dual licensed under the GNU LGPL or MIT License.
 13 
 14     You can redistribute it and/or modify it under the terms of the
 15 
 16       * GNU Lesser General Public License as published by
 17         the Free Software Foundation, either version 3 of the License, or
 18         (at your option) any later version
 19       OR
 20       * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT
 21 
 22     JSXGraph is distributed in the hope that it will be useful,
 23     but WITHOUT ANY WARRANTY; without even the implied warranty of
 24     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 25     GNU Lesser General Public License for more details.
 26 
 27     You should have received a copy of the GNU Lesser General Public License and
 28     the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/>
 29     and <http://opensource.org/licenses/MIT/>.
 30  */
 31 
 32 
 33 /*global JXG: true, define: true, document: true*/
 34 /*jslint nomen: true, plusplus: true*/
 35 
 36 /* depends:
 37  jxg
 38  utils/type
 39  */
 40 
 41 /**
 42  * @fileoverview The JXG.DataSource is a helper class for data organization. Currently supported data sources are
 43  * javascript arrays and HTML tables.
 44  */
 45 
 46 define(['jxg', 'utils/type'], function (JXG, Type) {
 47 
 48     "use strict";
 49 
 50     JXG.DataSource = function () {
 51         this.data = [];
 52         this.columnHeaders = [];
 53         this.rowHeaders = [];
 54 
 55         return this;
 56     };
 57 
 58     JXG.extend(JXG.DataSource.prototype, /** @lends JXG.DataSource.prototype */ {
 59         loadFromArray: function (table, columnHeader, rowHeader) {
 60             var i, j, cell;
 61 
 62             if (Type.isArray(columnHeader)) {
 63                 this.columnHeaders = columnHeader;
 64                 columnHeader = false;
 65             }
 66 
 67             if (Type.isArray(rowHeader)) {
 68                 this.rowHeaders = rowHeader;
 69                 rowHeader = false;
 70             }
 71 
 72             this.data = [];
 73 
 74             if (columnHeader) {
 75                 this.columnHeaders = [];
 76             }
 77 
 78             if (rowHeader) {
 79                 this.rowHeaders = [];
 80             }
 81 
 82             if (Type.exists(table)) {
 83                 // extract the data
 84                 this.data = [];
 85 
 86                 for (i = 0; i < table.length; i++) {
 87                     this.data[i] = [];
 88 
 89                     for (j = 0; j < table[i].length; j++) {
 90                         cell = table[i][j];
 91                         if (parseFloat(cell).toString() === cell) {
 92                             this.data[i][j] = parseFloat(cell);
 93                         } else if (cell !== '-') {
 94                             this.data[i][j] = cell;
 95                         } else {
 96                             this.data[i][j] = NaN;
 97                         }
 98                     }
 99                 }
100 
101                 if (columnHeader) {
102                     this.columnHeaders = this.data[0].slice(1);
103                     this.data = this.data.slice(1);
104                 }
105 
106                 if (rowHeader) {
107                     this.rowHeaders = [];
108                     for (i = 0; i < this.data.length; i++) {
109                         this.rowHeaders.push(this.data[i][0]);
110                         this.data[i] = this.data[i].slice(1);
111                     }
112                 }
113             }
114 
115             return this;
116         },
117 
118         loadFromTable: function (table, columnHeader, rowHeader) {
119             var row, i, j, col, cell, name;
120 
121             if (Type.isArray(columnHeader)) {
122                 this.columnHeaders = columnHeader;
123                 columnHeader = false;
124             }
125 
126             if (Type.isArray(rowHeader)) {
127                 this.rowHeaders = rowHeader;
128                 rowHeader = false;
129             }
130 
131             this.data = [];
132 
133             if (columnHeader) {
134                 this.columnHeaders = [];
135             }
136 
137             if (rowHeader) {
138                 this.rowHeaders = [];
139             }
140 
141             // to adjust: examples in examples folder & wiki
142             table = document.getElementById(table);
143 
144             if (Type.exists(table)) {
145                 // extract the data
146                 row = table.getElementsByTagName('tr');
147                 this.data = [];
148 
149                 for (i = 0; i < row.length; i++) {
150                     col = row[i].getElementsByTagName('td');
151                     this.data[i] = [];
152 
153                     for (j = 0; j < col.length; j++) {
154                         cell = col[j].innerHTML;
155 
156                         if (parseFloat(cell).toString() === cell) {
157                             this.data[i][j] = parseFloat(cell);
158                         } else if (cell !== '-') {
159                             this.data[i][j] = cell;
160                         } else {
161                             this.data[i][j] = NaN;
162                         }
163                     }
164                 }
165 
166                 if (columnHeader) {
167                     this.columnHeaders = this.data[0].slice(1);
168                     this.data = this.data.slice(1);
169                 }
170 
171                 if (rowHeader) {
172                     this.rowHeaders = [];
173                     for (i = 0; i < this.data.length; i++) {
174                         this.rowHeaders.push(this.data[i][0]);
175                         this.data[i] = this.data[i].slice(1);
176                     }
177                 }
178             }
179 
180             return this;
181         },
182 
183         addColumn: function (name, pos, data) {
184             throw new Error('not implemented');
185         },
186 
187         addRow: function (name, pos, data) {
188             throw new Error('not implemented');
189         },
190 
191         getColumn: function (col) {
192             var i,
193                 result = [];
194 
195             // get column index if column is given as column header title
196             if (Type.isString(col)) {
197                 for (i = 0; i < this.columnHeaders.length; i++) {
198                     if (col === this.columnHeaders[i]) {
199                         col = i;
200                         break;
201                     }
202                 }
203             }
204 
205             // build column array
206             for (i = 0; i < this.data.length; i++) {
207                 if (this.data[i].length > col) {
208                     result[i] = parseFloat(this.data[i][col]);
209                 }
210             }
211 
212             return result;
213         },
214 
215         getRow: function (row) {
216             var result, i;
217 
218             // get column index if column is given as column header title
219             if (Type.isString(row)) {
220                 for (i = 0; i < this.rowHeaders.length; i++) {
221                     if (row === this.rowHeaders[i]) {
222                         row = i;
223                         break;
224                     }
225                 }
226             }
227 
228             // allocate memory for result array
229             result = [];
230 
231             // build column array. result = this.data[row] is a flat copy and will
232             // destroy our local data copy, that's why we're copying it element wise.
233             for (i = 0; i < this.data[row].length; i++) {
234                 result[i] = this.data[row][i];
235             }
236 
237             return result;
238         }
239     });
240 
241     return JXG.DataSource;
242 });
243