      1 /*
      2  Copyright 2008-2022
      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*/
     34 /*jslint nomen: true, plusplus: true*/
     35
     36 /* depends:
     37  jxg
     38  utils/type
     39  */
     40
     41 define(['jxg', 'utils/type'], function (JXG, Type) {
     42
     43     "use strict";
     44
     45     /**
     46      * A composition is a simple container that manages none or more {@link JXG.GeometryElement}s.
     47      * @param {Object} elements A list of elements with a descriptive name for the element as the key and a reference
     48      * to the element as the value of every list entry. The name is used to access the element later on.
     49      * @example
     50      * var p1 = board.create('point', [1, 2]),
     51      *     p2 = board.create('point', [2, 3]),
     52      *     c = new JXG.Composition({
     53      *         start: p1,
     54      *         end: p2
     55      *     });
     56      *
     57      * // moves p1 to [3, 3]
     58      * c.start.moveTo([3, 3]);
     59      * @class JXG.Composition
     60      */
     61     JXG.Composition = function (elements) {
     62         var e,
     63             that = this,
     64             genericMethods = [
     65                 /**
     66                  * Invokes setAttribute for every stored element with a setAttribute method and hands over the given arguments.
     67                  * See {@link JXG.GeometryElement#setAttribute} for further description, valid parameters and return values.
     68                  * @name setAttribute
     69                  * @memberOf JXG.Composition.prototype
     70                  * @function
     71                  */
     72                 'setAttribute',
     73
     74                 /**
     75                 * Invokes setParents for every stored element with a setParents method and hands over the given arguments.
     76                 * See {@link JXG.GeometryElement#setParents} for further description, valid parameters and return values.
     77                 * @name setParents
     78                 * @memberOf JXG.Composition.prototype
     79                 * @function
     80                 */
     81                 'setParents',
     82
     83                 /**
     84                  * Invokes prepareUpdate for every stored element with a prepareUpdate method and hands over the given arguments.
     85                  * See {@link JXG.GeometryElement#prepareUpdate} for further description, valid parameters and return values.
     86                  * @name prepareUpdate
     87                  * @memberOf JXG.Composition.prototype
     88                  * @function
     89                  */
     90                 'prepareUpdate',
     91
     92                 /**
     93                  * Invokes updateRenderer for every stored element with a updateRenderer method and hands over the given arguments.
     94                  * See {@link JXG.GeometryElement#updateRenderer} for further description, valid parameters and return values.
     95                  * @name updateRenderer
     96                  * @memberOf JXG.Composition.prototype
     97                  * @function
     98                  */
     99                 'updateRenderer',
    100
    101                 /**
    102                  * Invokes update for every stored element with a update method and hands over the given arguments.
    103                  * See {@link JXG.GeometryElement#update} for further description, valid parameters and return values.
    104                  * @name update
    105                  * @memberOf JXG.Composition.prototype
    106                  * @function
    107                  */
    108                 'update',
    109
    110                 /**
    111                  * Invokes fullUpdate for every stored element with a fullUpdate method and hands over the given arguments.
    112                  * See {@link JXG.GeometryElement#fullUpdate} for further description, valid parameters and return values.
    113                  * @name fullUpdate
    114                  * @memberOf JXG.Composition.prototype
    115                  * @function
    116                  */
    117                 'fullUpdate',
    118
    119                 /**
    120                  * Invokes highlight for every stored element with a highlight method and hands over the given arguments.
    121                  * See {@link JXG.GeometryElement#highlight} for further description, valid parameters and return values.
    122                  * @name highlight
    123                  * @memberOf JXG.Composition.prototype
    124                  * @function
    125                  */
    126                 'highlight',
    127
    128                 /**
    129                  * Invokes noHighlight for every stored element with a noHighlight method and hands over the given arguments.
    130                  * See {@link JXG.GeometryElement#noHighlight} for further description, valid parameters and return values.
    131                  * @name noHighlight
    132                  * @memberOf JXG.Composition.prototype
    133                  * @function
    134                  */
    135                 'noHighlight'
    136             ],
    137             generateMethod = function (what) {
    138                 return function () {
    139                     var i;
    140
    141                     for (i in that.elements) {
    142                         if (that.elements.hasOwnProperty(i)) {
    143                             if (Type.exists(that.elements[i][what])) {
    144                                 that.elements[i][what].apply(that.elements[i], arguments);
    145                             }
    146                         }
    147                     }
    148                     return that;
    149                 };
    150             };
    151
    152         for (e = 0; e < genericMethods.length; e++) {
    153             this[genericMethods[e]] = generateMethod(genericMethods[e]);
    154         }
    155
    156         this.elements = {};
    157         this.objects = this.elements;
    158
    159         this.elementsByName = {};
    160         this.objectsList = [];
    161
    162         // unused, required for select()
    163         this.groups = {};
    164
    165         this.methodMap = {
    166             setAttribute: 'setAttribute',
    167             setProperty: 'setAttribute',
    168             setParents: 'setParents',
    169             add: 'add',
    170             remove: 'remove',
    171             select: 'select'
    172         };
    173
    174         for (e in elements) {
    175             if (elements.hasOwnProperty(e)) {
    176                 this.add(e, elements[e]);
    177             }
    178         }
    179
    180         this.dump = true;
    181         this.subs = {};
    182     };
    183
    184     JXG.extend(JXG.Composition.prototype, /** @lends JXG.Composition.prototype */ {
    185
    186         /**
    187          * Adds an element to the composition container.
    188          * @param {String} what Descriptive name for the element, e.g. <em>startpoint</em> or <em>area</em>. This is used to
    189          * access the element later on. There are some reserved names: <em>elements, add, remove, update, prepareUpdate,
    190          * updateRenderer, highlight, noHighlight</em>, and all names that would form invalid object property names in
    191          * JavaScript.
    192          * @param {JXG.GeometryElement|JXG.Composition} element A reference to the element that is to be added. This can be
    193          * another composition, too.
    194          * @returns {Boolean} True, if the element was added successfully. Reasons why adding the element failed include
    195          * using a reserved name and providing an invalid element.
    196          */
    197         add: function (what, element) {
    198             if (!Type.exists(this[what]) && Type.exists(element)) {
    199                 if (Type.exists(element.id)) {
    200                     this.elements[element.id] = element;
    201                 } else {
    202                     this.elements[what] = element;
    203                 }
    204
    205                 if (Type.exists(element.name)) {
    206                     this.elementsByName[element.name] = element;
    207                 }
    208
    209                 element.on('attribute:name', this.nameListener, this);
    210
    211                 this.objectsList.push(element);
    212                 this[what] = element;
    213                 this.methodMap[what] = element;
    214
    215                 return true;
    216             }
    217
    218             return false;
    219         },
    220
    221         /**
    222          * Remove an element from the composition container.
    223          * @param {String} what The name used to access the element.
    224          * @returns {Boolean} True, if the element has been removed successfully.
    225          */
    226         remove: function (what) {
    227             var found = false,
    228                 e;
    229
    230             for (e in this.elements) {
    231                 if (this.elements.hasOwnProperty(e)) {
    232                     if (this.elements[e].id === this[what].id) {
    233                         found = true;
    234                         break;
    235                     }
    236                 }
    237             }
    238
    239             if (found) {
    240                 delete this.elements[this[what].id];
    241                 delete this[what];
    242             }
    243
    244             return found;
    245         },
    246
    247         nameListener: function (oval, nval, el) {
    248             delete this.elementsByName[oval];
    249             this.elementsByName[nval] = el;
    250         },
    251
    252         select: function (filter) {
    253             // for now, hijack JXG.Board's select() method
    254             if (Type.exists(JXG.Board)) {
    255                 return JXG.Board.prototype.select.call(this, filter);
    256             }
    257
    258             return new JXG.Composition();
    259         },
    260
    261         getParents: function () {
    262             return this.parents;
    263         },
    264
    265         getType: function () {
    266             return this.elType;
    267         },
    268
    269         getAttributes: function () {
    270             var attr = {},
    271                 e;
    272
    273             for (e in this.subs) {
    274                 if (this.subs.hasOwnProperty(e)) {
    275                     attr[e] = this.subs[e].visProp;
    276                 }
    277             }
    278
    279             return this.attr;
    280         }
    281     });
    282
    283     return JXG.Composition;
    284 });
    285