1 /* 2 Copyright 2008-2013 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 prepareUpdate for every stored element with a prepareUpdate method and hands over the given arguments. 76 * See {@link JXG.GeometryElement#prepareUpdate} for further description, valid parameters and return values. 77 * @name prepareUpdate 78 * @memberOf JXG.Composition.prototype 79 * @function 80 */ 81 'prepareUpdate', 82 83 /** 84 * Invokes updateRenderer for every stored element with a updateRenderer method and hands over the given arguments. 85 * See {@link JXG.GeometryElement#updateRenderer} for further description, valid parameters and return values. 86 * @name updateRenderer 87 * @memberOf JXG.Composition.prototype 88 * @function 89 */ 90 'updateRenderer', 91 92 /** 93 * Invokes update for every stored element with a update method and hands over the given arguments. 94 * See {@link JXG.GeometryElement#update} for further description, valid parameters and return values. 95 * @name update 96 * @memberOf JXG.Composition.prototype 97 * @function 98 */ 99 'update', 100 101 /** 102 * Invokes highlight for every stored element with a highlight method and hands over the given arguments. 103 * See {@link JXG.GeometryElement#highlight} for further description, valid parameters and return values. 104 * @name highlight 105 * @memberOf JXG.Composition.prototype 106 * @function 107 */ 108 'highlight', 109 110 /** 111 * Invokes noHighlight for every stored element with a noHighlight method and hands over the given arguments. 112 * See {@link JXG.GeometryElement#noHighlight} for further description, valid parameters and return values. 113 * @name noHighlight 114 * @memberOf JXG.Composition.prototype 115 * @function 116 */ 117 'noHighlight' 118 ], 119 generateMethod = function (what) { 120 return function () { 121 var i; 122 123 for (i in that.elements) { 124 if (that.elements.hasOwnProperty(i)) { 125 if (Type.exists(that.elements[i][what])) { 126 that.elements[i][what].apply(that.elements[i], arguments); 127 } 128 } 129 } 130 return that; 131 }; 132 }; 133 134 for (e = 0; e < genericMethods.length; e++) { 135 this[genericMethods[e]] = generateMethod(genericMethods[e]); 136 } 137 138 this.elements = {}; 139 this.objects = this.elements; 140 141 this.elementsByName = {}; 142 this.objectsList = []; 143 144 // unused, required for select() 145 this.groups = {}; 146 147 this.methodMap = { 148 setAttribute: 'setAttribute', 149 setProperty: 'setAttribute', 150 add: 'add', 151 remove: 'remove', 152 select: 'select' 153 }; 154 155 for (e in elements) { 156 if (elements.hasOwnProperty(e)) { 157 this.add(e, elements[e]); 158 } 159 } 160 161 this.dump = true; 162 this.subs = {}; 163 }; 164 165 JXG.extend(JXG.Composition.prototype, /** @lends JXG.Composition.prototype */ { 166 167 /** 168 * Adds an element to the composition container. 169 * @param {String} what Descriptive name for the element, e.g. <em>startpoint</em> or <em>area</em>. This is used to 170 * access the element later on. There are some reserved names: <em>elements, add, remove, update, prepareUpdate, 171 * updateRenderer, highlight, noHighlight</em>, and all names that would form invalid object property names in 172 * JavaScript. 173 * @param {JXG.GeometryElement|JXG.Composition} element A reference to the element that is to be added. This can be 174 * another composition, too. 175 * @returns {Boolean} True, if the element was added successfully. Reasons why adding the element failed include 176 * using a reserved name and providing an invalid element. 177 */ 178 add: function (what, element) { 179 var self = this; 180 181 if (!Type.exists(this[what]) && Type.exists(element)) { 182 if (Type.exists(element.id)) { 183 this.elements[element.id] = element; 184 } else { 185 this.elements[what] = element; 186 } 187 188 if (Type.exists(element.name)) { 189 this.elementsByName[element.name] = element; 190 } 191 192 element.on('attribute:name', this.nameListener, this); 193 194 this.objectsList.push(element); 195 this[what] = element; 196 this.methodMap[what] = element; 197 198 return true; 199 } 200 201 return false; 202 }, 203 204 /** 205 * Remove an element from the composition container. 206 * @param {String} what The name used to access the element. 207 * @returns {Boolean} True, if the element has been removed successfully. 208 */ 209 remove: function (what) { 210 var found = false, 211 e; 212 213 for (e in this.elements) { 214 if (this.elements.hasOwnProperty(e)) { 215 if (this.elements[e].id === this[what].id) { 216 found = true; 217 break; 218 } 219 } 220 } 221 222 if (found) { 223 delete this.elements[this[what].id]; 224 delete this[what]; 225 } 226 227 return found; 228 }, 229 230 nameListener: function (oval, nval, el) { 231 delete this.elementsByName[oval]; 232 this.elementsByName[nval] = el; 233 }, 234 235 select: function (filter) { 236 // for now, hijack JXG.Board's select() method 237 if (Type.exists(JXG.Board)) { 238 return JXG.Board.prototype.select.call(this, filter); 239 } 240 241 return new JXG.Composition(); 242 }, 243 244 getParents: function () { 245 return this.parents; 246 }, 247 248 getType: function () { 249 return this.elType; 250 }, 251 252 getAttributes: function () { 253 var attr = {}, 254 e; 255 256 for (e in this.subs) { 257 if (this.subs.hasOwnProperty(e)) { 258 attr[e] = this.subs[e].visProp; 259 } 260 } 261 262 return this.attr; 263 } 264 }); 265 266 return JXG.Composition; 267 }); 268