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