1 /*
  2     Copyright 2008,2009
  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  * @author graphjs
 29  * @version 0.1
 30  */
 31  
 32 /**
 33  * Creates a new instance of Group.
 34  * @class In this class all group management is done.
 35  * @param {String} id Unique identifier for this object.  If null or an empty string is given,
 36  * an unique id will be generated by Board
 37  * @param {String} name Not necessarily unique name, displayed on the board.  If null or an
 38  * empty string is given, an unique name will be generated.
 39  * @constructor
 40  */
 41 JXG.Group = function(board, id, name) {
 42     var number,
 43         objArray,
 44         i, obj, el;
 45         
 46     this.board = board;
 47     this.objects = {};
 48     number = this.board.numObjects;
 49     this.board.numObjects++;
 50 
 51     if ((id == '') || !JXG.exists(id)) {
 52         this.id = this.board.id + 'Group' + number;
 53     } else {
 54         this.id = id;
 55     }
 56     
 57     this.type = JXG.OBJECT_TYPE_POINT;
 58     this.elementClass = JXG.OBJECT_CLASS_POINT;                
 59 
 60     if ((name == '') || !JXG.exists(name)) {
 61         this.name = 'group_' + this.board.generateName(this);
 62     } else {
 63         this.name = name;
 64     }
 65     delete(this.type);
 66 
 67     if ( (arguments.length == 4) && (JXG.isArray(arguments[3])) )
 68         objArray = arguments[3];
 69     else {
 70         objArray = [];
 71         for (i=3; i<arguments.length; i++) {
 72             objArray.push(arguments[i]);
 73         }
 74     }
 75 
 76     for (i=0; i<objArray.length; i++) {
 77         obj = JXG.getReference(this.board, objArray[i]);
 78         if( (!obj.fixed) && ( (obj.type == JXG.OBJECT_TYPE_POINT) || (obj.type == JXG.OBJECT_TYPE_GLIDER) ) ) {
 79             if (obj.group.length != 0) {
 80                 this.addGroup(obj.group[obj.group.length-1]);
 81             } else {
 82                 this.addPoint(obj);
 83             }
 84         }
 85     }
 86     
 87     for (el in this.objects) {
 88         this.objects[el].group.push(this);
 89     }
 90 
 91     this.dX = 0;
 92     this.dY = 0;
 93 };
 94 
 95 /**
 96  * Releases the group added to the points in this group, but only if this group is the last group.
 97  */
 98 JXG.Group.prototype.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 };
107 
108 /**
109  * Sends an update to all group members.
110  * @param {JXG.Point} point The point that caused the update.
111  */
112 JXG.Group.prototype.update = function(point) {
113     var obj = null,
114         el;
115     
116     for (el in this.objects) {
117         obj = this.objects[el];
118         if (obj.id != point.id) {
119             obj.coords = new JXG.Coords(JXG.COORDS_BY_SCREEN, [obj.coords.scrCoords[1] + this.dX, obj.coords.scrCoords[2] + this.dY], obj.board);
120         }
121     }
122     
123     for (el in this.objects) {
124         /* Wurde das Element vielleicht geloescht? */
125         if (JXG.exists(this.board.objects[el])) {
126             /* Nein, wurde es nicht, also updaten */
127             this.objects[el].update(false);
128         } else { /* es wurde geloescht, also aus dem Array entfernen */
129             delete(this.objects[el]);
130         }
131     }
132 };
133 
134 /**
135  * Adds an Point to this group.
136  * @param {JXG.Point} object The object added to the group.
137  */
138 JXG.Group.prototype.addPoint = function(object) {
139     this.objects[object.id] = object;
140 };
141 
142 /**
143  * Adds an multiple points to this group.
144  * @param {Array} objects An array of points to add to the group.
145  */
146 JXG.Group.prototype.addPoints = function(objects) {
147     var p;
148     for (p in objects)
149         this.objects[p.id] = p;
150 };
151 
152 /**
153  * Adds an Pint to this group.
154  * @param {JXG.Point} object The object added to the group.
155  */
156 JXG.Group.prototype.addGroup = function(group) {
157     var el;
158     for (el in group.objects) {
159         this.addPoint(group.objects[el]);
160     }
161 };
162 
163 /**
164  * Groups points.
165  * @param {JXG.Board} board The board the points are on.
166  * @param {Array} parents Array of points to group.
167  * @param {Object} attributes Visual properties.
168  * @type JXG.Group
169  * @return An object of type JXG.Group.
170  */
171 JXG.createGroup = function(board, parents, attributes) {
172     return new JXG.Group(board, attributes["id"], attributes["name"], parents);
173 };
174 
175 JXG.JSXGraph.registerElement('group', JXG.createGroup);