1 /*
  2     Copyright 2008-2023
  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 <https://www.gnu.org/licenses/>
 29     and <https://opensource.org/licenses/MIT/>.
 30  */
 31 
 32 /*global JXG: true, define: true, document: true*/
 33 /*jslint nomen: true, plusplus: true*/
 34 
 35 /**
 36  * @fileoverview The JXG.DataSource is a helper class for data organization. Currently supported data sources are
 37  * javascript arrays and HTML tables.
 38  */
 39 
 40 import JXG from "../jxg";
 41 import Type from "../utils/type";
 42 
 43 JXG.DataSource = function () {
 44     this.data = [];
 45     this.columnHeaders = [];
 46     this.rowHeaders = [];
 47 
 48     return this;
 49 };
 50 
 51 JXG.extend(
 52     JXG.DataSource.prototype,
 53     /** @lends JXG.DataSource.prototype */ {
 54         loadFromArray: function (table, columnHeader, rowHeader) {
 55             var i, j, cell;
 56 
 57             if (Type.isArray(columnHeader)) {
 58                 this.columnHeaders = columnHeader;
 59                 columnHeader = false;
 60             }
 61 
 62             if (Type.isArray(rowHeader)) {
 63                 this.rowHeaders = rowHeader;
 64                 rowHeader = false;
 65             }
 66 
 67             this.data = [];
 68 
 69             if (columnHeader) {
 70                 this.columnHeaders = [];
 71             }
 72 
 73             if (rowHeader) {
 74                 this.rowHeaders = [];
 75             }
 76 
 77             if (Type.exists(table)) {
 78                 // extract the data
 79                 this.data = [];
 80 
 81                 for (i = 0; i < table.length; i++) {
 82                     this.data[i] = [];
 83 
 84                     for (j = 0; j < table[i].length; j++) {
 85                         cell = table[i][j];
 86                         if (parseFloat(cell).toString() === cell) {
 87                             this.data[i][j] = parseFloat(cell);
 88                         } else if (cell !== "-") {
 89                             this.data[i][j] = cell;
 90                         } else {
 91                             this.data[i][j] = NaN;
 92                         }
 93                     }
 94                 }
 95 
 96                 if (columnHeader) {
 97                     this.columnHeaders = this.data[0].slice(1);
 98                     this.data = this.data.slice(1);
 99                 }
100 
101                 if (rowHeader) {
102                     this.rowHeaders = [];
103                     for (i = 0; i < this.data.length; i++) {
104                         this.rowHeaders.push(this.data[i][0]);
105                         this.data[i] = this.data[i].slice(1);
106                     }
107                 }
108             }
109 
110             return this;
111         },
112 
113         loadFromTable: function (table, columnHeader, rowHeader) {
114             var row, i, j, col, cell;
115 
116             if (Type.isArray(columnHeader)) {
117                 this.columnHeaders = columnHeader;
118                 columnHeader = false;
119             }
120 
121             if (Type.isArray(rowHeader)) {
122                 this.rowHeaders = rowHeader;
123                 rowHeader = false;
124             }
125 
126             this.data = [];
127 
128             if (columnHeader) {
129                 this.columnHeaders = [];
130             }
131 
132             if (rowHeader) {
133                 this.rowHeaders = [];
134             }
135 
136             // to adjust: examples in examples folder & wiki
137             table = document.getElementById(table);
138 
139             if (Type.exists(table)) {
140                 // extract the data
141                 row = table.getElementsByTagName("tr");
142                 this.data = [];
143 
144                 for (i = 0; i < row.length; i++) {
145                     col = row[i].getElementsByTagName("td");
146                     this.data[i] = [];
147 
148                     for (j = 0; j < col.length; j++) {
149                         cell = col[j].innerHTML;
150 
151                         if (parseFloat(cell).toString() === cell) {
152                             this.data[i][j] = parseFloat(cell);
153                         } else if (cell !== "-") {
154                             this.data[i][j] = cell;
155                         } else {
156                             this.data[i][j] = NaN;
157                         }
158                     }
159                 }
160 
161                 if (columnHeader) {
162                     this.columnHeaders = this.data[0].slice(1);
163                     this.data = this.data.slice(1);
164                 }
165 
166                 if (rowHeader) {
167                     this.rowHeaders = [];
168                     for (i = 0; i < this.data.length; i++) {
169                         this.rowHeaders.push(this.data[i][0]);
170                         this.data[i] = this.data[i].slice(1);
171                     }
172                 }
173             }
174 
175             return this;
176         },
177 
178         addColumn: function (name, pos, data) {
179             throw new Error("not implemented");
180         },
181 
182         addRow: function (name, pos, data) {
183             throw new Error("not implemented");
184         },
185 
186         getColumn: function (col) {
187             var i,
188                 result = [];
189 
190             // get column index if column is given as column header title
191             if (Type.isString(col)) {
192                 for (i = 0; i < this.columnHeaders.length; i++) {
193                     if (col === this.columnHeaders[i]) {
194                         col = i;
195                         break;
196                     }
197                 }
198             }
199 
200             // build column array
201             for (i = 0; i < this.data.length; i++) {
202                 if (this.data[i].length > col) {
203                     result[i] = parseFloat(this.data[i][col]);
204                 }
205             }
206 
207             return result;
208         },
209 
210         getRow: function (row) {
211             var result, i;
212 
213             // get column index if column is given as column header title
214             if (Type.isString(row)) {
215                 for (i = 0; i < this.rowHeaders.length; i++) {
216                     if (row === this.rowHeaders[i]) {
217                         row = i;
218                         break;
219                     }
220                 }
221             }
222 
223             // allocate memory for result array
224             result = [];
225 
226             // build column array. result = this.data[row] is a flat copy and will
227             // destroy our local data copy, that's why we're copying it element wise.
228             for (i = 0; i < this.data[row].length; i++) {
229                 result[i] = this.data[row][i];
230             }
231 
232             return result;
233         }
234     }
235 );
236 
237 export default JXG.DataSource;
238