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 = [];
 70         for (i=3; i<arguments.length; i++) {
 71             objArray.push(arguments[i]);
 72         }
 73     }
 74 
 75     for (i=0; i<objArray.length; i++) {
 76         obj = JXG.getReference(this.board, objArray[i]);
 77         if( (!obj.visProp.fixed) && ( (obj.type == JXG.OBJECT_TYPE_POINT) || (obj.type == JXG.OBJECT_TYPE_GLIDER) ) ) {
 78             if (obj.group.length != 0) {
 79                 this.addGroup(obj.group[obj.group.length-1]);
 80             } else {
 81                 this.addPoint(obj);
 82             }
 83         }
 84     }
 85     
 86     for (el in this.objects) {
 87         this.objects[el].group.push(this);
 88     }
 89 
 90     this.dX = 0;
 91     this.dY = 0;
 92 };
 93 
 94 JXG.extend(JXG.Group.prototype, /** @lends JXG.Group.prototype */ {
 95     /**
 96      * Releases the group added to the points in this group, but only if this group is the last group.
 97      */
 98     ungroup: function() {
 99         var el;
100         for (el in this.objects) {
101             if (this.objects[el].group[this.objects[el].group.length-1] == this) {
102                 this.objects[el].group.pop();
103             }
104             delete(this.objects[el]);
105         }
106         // Unregister the group from board
107         // delete(this.board.groups[this.id]);  // Not sure if we should delete the group
108     },
109 
110     /**
111      * Sends an update to all group members.
112      * @param {JXG.Point} point The point that caused the update.
113      */
114     update: function(point) {
115         var obj = null,
116             el;
117         
118         for (el in this.objects) {
119             obj = this.objects[el];
120             if (obj.id != point.id) {
121                 obj.coords = new JXG.Coords(JXG.COORDS_BY_SCREEN, [obj.coords.scrCoords[1] + this.dX, 
122                                                                    obj.coords.scrCoords[2] + this.dY], obj.board);
123             }
124         }
125         
126         for (el in this.objects) {
127             /* Wurde das Element vielleicht geloescht? */
128             if (JXG.exists(this.board.objects[el])) {
129                 /* Nein, wurde es nicht, also updaten */
130                 this.objects[el].update(false);
131             } else { /* es wurde geloescht, also aus dem Array entfernen */
132                 delete(this.objects[el]);
133             }
134         }
135         return this;
136     },
137 
138     /**
139      * Adds an Point to this group.
140      * @param {JXG.Point} object The object added to the group.
141      */
142     addPoint: function(object) {
143         this.objects[object.id] = object;
144     },
145 
146     /**
147      * Adds multiple points to this group.
148      * @param {Array} objects An array of points to add to the group.
149      */
150     addPoints: function(objects) {
151         var p;
152         for (p in objects)
153             this.objects[p.id] = p;
154     },
155 
156     /**
157      * Adds an Point to this group.
158      * @param {JXG.Point} object The object added to the group.
159      */
160     addGroup: function(group) {
161         var el;
162         for (el in group.objects) {
163             this.addPoint(group.objects[el]);
164         }
165     },
166 
167     setProperty: function () {
168         var el;
169 
170         for (el in this.objects) {
171             this.objects[el].setProperty.apply(this.objects[el], arguments);
172         }
173     }
174 });
175 
176 /**
177  * Groups points.
178  * @param {JXG.Board} board The board the points are on.
179  * @param {Array} parents Array of points to group.
180  * @param {Object} attributes Visual properties.
181  * @type JXG.Group
182  * @return An object of type JXG.Group.
183  */
184 JXG.createGroup = function(board, parents, attributes) {
185     var i, g = new JXG.Group(board, attributes["id"], attributes["name"], parents);
186 
187     g.elType = 'group';
188 
189     g.parents = [];
190     for (i = 0; i < parents.length; i++) {
191         g.parents.push(parents[i].id);
192     }
193 
194     return g;
195 };
196 
197 JXG.JSXGraph.registerElement('group', JXG.createGroup);
198