      1 /*
      2     Copyright 2008-2024
      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.js";
     41 import Type from "../utils/type.js";
     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