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