1 /* 2 Copyright 2008-2011 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: you can redistribute it and/or modify 13 it under the terms of the GNU Lesser General Public License as published by 14 the Free Software Foundation, either version 3 of the License, or 15 (at your option) any later version. 16 17 JSXGraph is distributed in the hope that it will be useful, 18 but WITHOUT ANY WARRANTY; without even the implied warranty of 19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 GNU Lesser General Public License for more details. 21 22 You should have received a copy of the GNU Lesser General Public License 23 along with JSXGraph. If not, see <http://www.gnu.org/licenses/>. 24 */ 25 /** 26 * @fileoverview In this file the class Group is defined, a class for 27 * managing grouping of points. 28 */ 29 30 /** 31 * Creates a new instance of Group. 32 * @class In this class all group management is done. 33 * @param {String} id Unique identifier for this object. If null or an empty string is given, 34 * an unique id will be generated by Board 35 * @param {String} name Not necessarily unique name, displayed on the board. If null or an 36 * empty string is given, an unique name will be generated. 37 * @constructor 38 */ 39 JXG.Group = function(board, id, name) { 40 var number, 41 objArray, 42 i, obj, el; 43 44 this.board = board; 45 this.objects = {}; 46 number = this.board.numObjects; 47 this.board.numObjects++; 48 49 if ((id == '') || !JXG.exists(id)) { 50 this.id = this.board.id + 'Group' + number; 51 } else { 52 this.id = id; 53 } 54 this.board.groups[this.id] = this; 55 56 this.type = JXG.OBJECT_TYPE_POINT; 57 this.elementClass = JXG.OBJECT_CLASS_POINT; 58 59 if ((name == '') || !JXG.exists(name)) { 60 this.name = 'group_' + this.board.generateName(this); 61 } else { 62 this.name = name; 63 } 64 delete(this.type); 65 66 if ( (arguments.length == 4) && (JXG.isArray(arguments[3])) ) { 67 objArray = arguments[3]; 68 } else { 69 objArray = Array.prototype.slice.call(arguments, 3); 70 } 71 72 for (i = 0; i < objArray.length; i++) { 73 obj = JXG.getReference(this.board, objArray[i]); 74 if( (!obj.visProp.fixed) && ( (obj.type == JXG.OBJECT_TYPE_POINT) || (obj.type == JXG.OBJECT_TYPE_GLIDER) ) ) { 75 if (obj.group.length != 0) { 76 this.addGroup(obj.group[obj.group.length-1]); 77 } else { 78 this.addPoint(obj); 79 } 80 } 81 } 82 83 this.suspendUpdate = false; 84 this.dX = 0; 85 this.dY = 0; 86 }; 87 88 JXG.extend(JXG.Group.prototype, /** @lends JXG.Group.prototype */ { 89 /** 90 * Releases the group added to the points in this group, but only if this group is the last group. 91 */ 92 ungroup: function() { 93 var el; 94 for (el in this.objects) { 95 if (JXG.isArray(this.objects[el].point.group) && this.objects[el].point.group[this.objects[el].point.group.length-1] == this) { 96 this.objects[el].point.group.pop(); 97 } 98 this.removePoint(this.objects[el].point); 99 } 100 // Unregister the group from board 101 // delete(this.board.groups[this.id]); // Not sure if we should delete the group 102 }, 103 104 suspendUpdate: function () { 105 this.suspendUpdate = true; 106 }, 107 108 unsuspendUpdate: function () { 109 this.suspendUpdate = false; 110 }, 111 112 /** 113 * Sends an update to all group members. 114 * @param {JXG.Point} point The point that caused the update. 115 */ 116 update: function(point, dX, dY, dZ) { 117 var obj = null, 118 el; 119 120 if (!this.suspendUpdate) { 121 this.suspendUpdate = true; 122 123 for (el in this.objects) { 124 if (JXG.exists(this.board.objects[el])) { 125 obj = this.objects[el].point; 126 if (obj.id != point.id) { 127 obj.coords.setCoordinates(JXG.COORDS_BY_USER, [obj.coords.usrCoords[1] + dX, obj.coords.usrCoords[2] + dY]); 128 } 129 this.objects[el].point.prepareUpdate().update(false).updateRenderer(); 130 } else { 131 delete(this.objects[el]); 132 } 133 } 134 135 this.suspendUpdate = false; 136 } 137 138 return this; 139 }, 140 141 /** 142 * Adds an Point to this group. 143 * @param {JXG.Point} object The point added to the group. 144 */ 145 addPoint: function(object) { 146 this.objects[object.id] = { 147 point: object, 148 handler: function (ou, os) { 149 this.update(object, object.coords.usrCoords[1] - ou[1], object.coords.usrCoords[2] - ou[2], object.coords.usrCoords[0] - ou[0]); 150 } 151 }; 152 object.coords.on('update', this.objects[object.id].handler, this); 153 }, 154 155 /** 156 * Adds multiple points to this group. 157 * @param {Array} objects An array of points to add to the group. 158 */ 159 addPoints: function(objects) { 160 var p; 161 162 for (p = 0; p < objects.length; p++) { 163 this.addPoint(objects[p]); 164 } 165 }, 166 167 /** 168 * Adds all points in a group to this group. 169 * @param {JXG.Point} group The group added to this group. 170 */ 171 addGroup: function(group) { 172 var el; 173 174 for (el in group.objects) { 175 this.addPoint(group.objects[el].point); 176 } 177 }, 178 179 /** 180 * Removes a point from the group. 181 * @param {JXG.Point} point 182 */ 183 removePoint: function (point) { 184 var i; 185 186 this.objects[point.id].point.coords.off('update', this.objects[point.id].handler); 187 delete this.objects[point.id]; 188 }, 189 190 setProperty: function () { 191 var el; 192 193 for (el in this.objects) { 194 this.objects[el].point.setProperty.apply(this.objects[el].point, arguments); 195 } 196 } 197 }); 198 199 /** 200 * Groups points. 201 * @param {JXG.Board} board The board the points are on. 202 * @param {Array} parents Array of points to group. 203 * @param {Object} attributes Visual properties. 204 * @type JXG.Group 205 * @return An object of type JXG.Group. 206 */ 207 JXG.createGroup = function(board, parents, attributes) { 208 var i, g = new JXG.Group(board, attributes["id"], attributes["name"], parents); 209 210 g.elType = 'group'; 211 212 g.parents = []; 213 for (i = 0; i < parents.length; i++) { 214 g.parents.push(parents[i].id); 215 } 216 217 return g; 218 }; 219 220 JXG.JSXGraph.registerElement('group', JXG.createGroup); 221