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 JXG.OBJECT_TYPE_ARC = 0x4F544143; // Hex fuer OTAC = Object Type ArC 26 JXG.OBJECT_TYPE_ARROW = 0x4F544157; // Hex fuer OTAW = Object Type ArroW 27 JXG.OBJECT_TYPE_AXIS = 0x4F544158; // Hex fuer OTAX = Object Type AXis 28 JXG.OBJECT_TYPE_TICKS = 0x4F545458; // Hex fuer OTTX = Object Type TiX 29 JXG.OBJECT_TYPE_CIRCLE = 0x4F54434C; // Hex fuer OTCC = Object Type CirCle 30 JXG.OBJECT_TYPE_CONIC = 0x4F54434F; // Hex fuer OTCC = Object Type COnic 31 JXG.OBJECT_TYPE_CURVE = 0x4F544750; // Hex fuer OTGP = Object Type GraphPlot 32 JXG.OBJECT_TYPE_GLIDER = 0x4F54474C; // Hex fuer OTGL = Object Type GLider 33 JXG.OBJECT_TYPE_IMAGE = 0x4F54524D; // Hex fuer OTIM = Object Type IMage 34 JXG.OBJECT_TYPE_LINE = 0x4F544C4E; // Hex fuer OTLN = Object Type LiNe 35 JXG.OBJECT_TYPE_POINT = 0x4F545054; // Hex fuer OTPT = Object Type PoinT 36 JXG.OBJECT_TYPE_SLIDER = 0x4F545344; // Hex fuer OTSD = Object Type SliDer 37 JXG.OBJECT_TYPE_CAS = 0x4F544350; // Hex fuer OTCP = Object Type CasPoint 38 JXG.OBJECT_TYPE_POLYGON = 0x4F545059; // Hex fuer OTPY = Object Type PolYgon 39 JXG.OBJECT_TYPE_SECTOR = 0x4F545343; // Hex fuer OTSC = Object Type SeCtor 40 JXG.OBJECT_TYPE_TEXT = 0x4F545445; // Hex fuer OTTE = Object Type TextElement 41 JXG.OBJECT_TYPE_ANGLE = 0x4F544147; // Hex fuer OTAG = Object Type AnGle 42 JXG.OBJECT_TYPE_INTERSECTION = 0x4F54524E; // Hex fuer OTIN = Object Type INtersection 43 JXG.OBJECT_TYPE_TURTLE = 0x4F5455; // Hex fuer OTTU = Object Type TUrtle 44 JXG.OBJECT_TYPE_VECTOR = 0x4F545654; //Hex fuer OTVT 0 Object Type VecTor 45 46 JXG.OBJECT_CLASS_POINT = 1; 47 JXG.OBJECT_CLASS_LINE = 2; 48 JXG.OBJECT_CLASS_CIRCLE = 3; 49 JXG.OBJECT_CLASS_CURVE = 4; 50 JXG.OBJECT_CLASS_AREA = 5; 51 JXG.OBJECT_CLASS_OTHER = 6; 52 53 /** 54 * Constructs a new GeometryElement object. 55 * @class This is the basic class for geometry elements like points, circles and lines. 56 * @constructor 57 * of identical elements on the board. Is not yet implemented for all elements, only points, lines and circle can be traced. 58 */ 59 JXG.GeometryElement = function() { 60 /** 61 * Reference to board where the element is drawn 62 * @type JXG.Board 63 * @default null 64 * @see JXG.Board 65 */ 66 this.board = null; 67 68 /** 69 * Unique identifier for the element. Equivalent to id-attribute of renderer element. 70 * @type String 71 * @default empty string 72 */ 73 this.id = ''; 74 75 /** 76 * Controls if updates are necessary 77 * @type Boolean 78 * @default true 79 */ 80 this.needsUpdate = true; 81 82 /** 83 * Not necessarily unique name for the element. 84 * @type String 85 * @default Name generated by {@link JXG.Board#generateName}. 86 * @see JXG.Board#generateName 87 */ 88 this.name = ''; 89 90 /** 91 * An associative array containing all visual properties. 92 * @type Object 93 * @default empty object 94 */ 95 this.visProp = {}; 96 97 JXG.clearVisPropOld(this); // create this.visPropOld and set default values 98 99 /** 100 * If element is in two dimensional real space this is true, else false. 101 * @type Boolean 102 * @default true 103 */ 104 this.isReal = true; 105 106 /** 107 * Determines the elements border-style. 108 * Possible values are: 109 * <ul><li>0 for a solid line</li> 110 * <li>1 for a dotted line</li> 111 * <li>2 for a line with small dashes</li> 112 * <li>3 for a line with medium dashes</li> 113 * <li>4 for a line with big dashes</li> 114 * <li>5 for a line with alternating medium and big dashes and large gaps</li> 115 * <li>6 for a line with alternating medium and big dashes and small gaps</li></ul> 116 * @type Number 117 * @name JXG.GeometryElement#dash 118 * @default 0 119 */ 120 this.visProp['dash'] = 0; 121 122 /** 123 * Stores all dependent objects to be updated when this point is moved. 124 * @type Object 125 */ 126 this.childElements = {}; 127 128 /** 129 * If element has a label subelement then this property will be set to true. 130 * @type Boolean 131 * @default false 132 */ 133 this.hasLabel = false; 134 135 /** 136 * display layer which will conting the element. 137 * Controlled in JXG.Options. 138 */ 139 this.layer = 9; 140 141 /** 142 * Stores all Intersection Objects which in this moment are not real and 143 * so hide this element. 144 * @type Object 145 */ 146 this.notExistingParents = {}; 147 148 /** 149 * If true the element will be traced, i.e. on every movement the element will be copied 150 * to the background. Use {@link JXG.GeometryElement#clearTrace} to delete the trace elements. 151 * @see JXG.GeometryElement#clearTrace 152 * @see JXG.GeometryElement#traces 153 * @see JXG.GeometryElement#numTraces 154 * @type Boolean 155 * @default false 156 * @name JXG.GeometryElement#trace 157 */ 158 this.traced = false; 159 160 /** 161 * If true the element is fixed and can not be dragged around. The element 162 * will be repositioned on zoom and moveOrigin events. 163 * @type Boolean 164 * @default false 165 * @name JXG.GeometryElement#fixed 166 */ 167 this.fixed = false; 168 169 /** 170 * If true the element is fixed and can not be dragged around. The element 171 * will even stay at its position on zoom and moveOrigin events. 172 * Only free elements like points, texts, curves can be frozen. 173 * @type Boolean 174 * @default false 175 * @name JXG.GeometryElement#fixed 176 */ 177 this.frozen = false; 178 179 /** 180 * Keeps track of all objects drawn as part of the trace of the element. 181 * @see JXG.GeometryElement#traced 182 * @see JXG.GeometryElement#clearTrace 183 * @see JXG.GeometryElement#numTraces 184 * @type Object 185 */ 186 this.traces = {}; 187 188 /** 189 * Counts the number of objects drawn as part of the trace of the element. 190 * @see JXG.GeometryElement#traced 191 * @see JXG.GeometryElement#clearTrace 192 * @see JXG.GeometryElement#traces 193 * @type Number 194 */ 195 this.numTraces = 0; 196 197 /** 198 * Stores the transformations which are applied during update in an array 199 * @type Array 200 * @see JXG.Transformation 201 */ 202 this.transformations = []; 203 204 /** TODO 205 * @type JXG.GeometryElement 206 * @default null 207 * @private 208 */ 209 this.baseElement = null; 210 211 /** 212 * Elements depending on this element are stored here. 213 * @type Object 214 */ 215 this.descendants = {}; 216 217 /** 218 * Elements on which this elements depends on are stored here. 219 * @type Object 220 */ 221 this.ancestors = {}; 222 223 /** 224 * Stores variables for symbolic computations 225 * @type Object 226 */ 227 this.symbolic = {}; 228 229 /** 230 * [c,b0,b1,a,k,r,q0,q1] 231 * 232 * See 233 * A.E. Middleditch, T.W. Stacey, and S.B. Tor: 234 * "Intersection Algorithms for Lines and Circles", 235 * ACM Transactions on Graphics, Vol. 8, 1, 1989, pp 25-40. 236 * 237 * The meaning of the parameters is: 238 * Circle: points p=[p0,p1] on the circle fulfill 239 * a<p,p> + <b,p> + c = 0 240 * For convenience we also store 241 * r: radius 242 * k: discriminant = sqrt(<b,b>-4ac) 243 * q=[q0,q1] center 244 * 245 * Points have radius = 0. 246 * Lines have radius = infinity. 247 * b: normalized vector, representing the direction of the line. 248 * 249 * Should be put into Coords, when all elements possess Coords. 250 * @type Array 251 * @default [1, 0, 0, 0, 1, 1, 0, 0] 252 */ 253 this.stdform = [1,0,0,0,1, 1,0,0]; 254 255 /** 256 * Quadratic form representation of circles (and conics) 257 * @type Array 258 * @default [[1,0,0],[0,1,0],[0,0,1]] 259 */ 260 this.quadraticform = [[1,0,0],[0,1,0],[0,0,1]]; 261 262 /** 263 * If this is set to true, the element is updated in every update 264 * call of the board. If set to false, the element is updated only after 265 * zoom events or more generally, when the bounding box has been changed. 266 * Examples for the latter behaviour should be axes. 267 * @type Boolean 268 * @default true 269 */ 270 this.needsRegularUpdate = true; 271 272 }; 273 274 /** 275 * Initializes board, id and name which cannot be initialized properly in the constructor. 276 * @param {JXG.Board} board The board the new point is drawn on. 277 * @param {String} id Unique identifier for the point. If null or an empty string is given, 278 * an unique id will be generated by Board 279 * @param {String} name Not necessarily unique name for the point. If null or an 280 * empty string is given, an unique name will be generated 281 * @private 282 */ 283 JXG.GeometryElement.prototype.init = function(board, id, name) { 284 this.board = board; 285 this.id = id; 286 287 /* If name is not set or null or even undefined, generate an unique name for this object */ 288 if (!JXG.exists(name)) { 289 name = this.board.generateName(this); 290 } 291 this.board.elementsByName[name] = this; 292 293 this.name = name; 294 295 /** 296 * The stroke color of the given geometry element. 297 * @type string 298 * @name JXG.GeometryElement#strokeColor 299 * @see #highlightStrokeColor 300 * @see #strokeWidth 301 * @see #strokeOpacity 302 * @see #highlightStrokeOpacity 303 * @default {@link JXG.Options.elements.color#strokeColor} 304 */ 305 this.visProp.strokeColor = this.board.options.elements.strokeColor; //'#36393D'; 306 307 /** 308 * The stroke color of the given geometry element when the user moves the mouse over it. 309 * @type string 310 * @name JXG.GeometryElement#highlightStrokeColor 311 * @see #sstrokeColor 312 * @see #strokeWidth 313 * @see #strokeOpacity 314 * @see #highlightStrokeOpacity 315 * @default {@link JXG.Options.elements.color#highlightStrokeColor} 316 */ 317 this.visProp.highlightStrokeColor = this.board.options.elements.highlightStrokeColor; 318 319 /** 320 * The fill color of this geometry element. 321 * @type string 322 * @name JXG.GeometryElement#fillColor 323 * @see #highlightFillColor 324 * @see #fillOpacity 325 * @see #highlightFillOpacity 326 * @default {@link JXG.Options.elements.color#fillColor} 327 */ 328 this.visProp.fillColor = this.board.options.elements.fillColor; 329 330 /** 331 * The fill color of the given geometry element when the mouse is pointed over it. 332 * @type string 333 * @name JXG.GeometryElement#highlightFillColor 334 * @see #fillColor 335 * @see #fillOpacity 336 * @see #highlightFillOpacity 337 * @default {@link JXG.Options.elements.color#highlightFillColor} 338 */ 339 this.visProp.highlightFillColor = this.board.options.elements.highlightFillColor; 340 341 /** 342 * Width of the element's stroke. 343 * @type number 344 * @name JXG.GeometryElement#strokeWidth 345 * @see #strokeColor 346 * @see #highlightStrokeColor 347 * @see #strokeOpacity 348 * @see #highlightStrokeOpacity 349 * @default {@link JXG.Options.elements#strokeWidth} 350 */ 351 this.visProp.strokeWidth = this.board.options.elements.strokeWidth; 352 353 /** 354 * Width of the element's stroke when the mouse is pointed over it. 355 * @type number 356 * @name JXG.GeometryElement#highlightStrokeWidth 357 * @see #strokeColor 358 * @see #highlightStrokeColor 359 * @see #strokeOpacity 360 * @see #highlightStrokeOpacity 361 * @see #highlightFillColor 362 * @default {@#strokeWidth} 363 */ 364 this.visProp.highlightStrokeWidth = this.visProp.strokeWidth; 365 366 /** 367 * Opacity for element's stroke color. 368 * @type number 369 * @name JXG.GeometryElement#strokeOpacity 370 * @see #strokeColor 371 * @see #highlightStrokeColor 372 * @see #strokeWidth 373 * @see #highlightStrokeOpacity 374 * @default {@link JXG.Options.elements#strokeOpacity} 375 */ 376 this.visProp.strokeOpacity = this.board.options.elements.strokeOpacity; 377 378 /** 379 * Opacity for stroke color when the object is highlighted. 380 * @type number 381 * @name JXG.GeometryElement#highlightStrokeOpacity 382 * @see #strokeColor 383 * @see #highlightStrokeColor 384 * @see #strokeWidth 385 * @see #strokeOpacity 386 * @default {@link JXG.Options.elements#highlightStrokeOpacity} 387 */ 388 this.visProp.highlightStrokeOpacity = this.board.options.elements.highlightStrokeOpacity; 389 390 /** 391 * Opacity for fill color. 392 * @type number 393 * @name JXG.GeometryElement#fillOpacity 394 * @see #fillColor 395 * @see #highlightFillColor 396 * @see #highlightFillOpacity 397 * @default {@link JXG.Options.elements.color#fillOpacity} 398 */ 399 this.visProp.fillOpacity = this.board.options.elements.fillOpacity; 400 401 /** 402 * Opacity for fill color when the object is highlighted. 403 * @type number 404 * @name JXG.GeometryElement#highlightFillOpacity 405 * @see #fillColor 406 * @see #highlightFillColor 407 * @see #fillOpacity 408 * @default {@link JXG.Options.elements.color#highlightFillOpacity} 409 */ 410 this.visProp.highlightFillOpacity = this.board.options.elements.highlightFillOpacity; 411 412 /** 413 * If true the element will be drawn in grey scale colors to visualize that it's only a draft. 414 * @type boolean 415 * @name JXG.GeometryElement#draft 416 * @default {@link JXG.Options.elements.draft#draft} 417 */ 418 this.visProp.draft = this.board.options.elements.draft.draft; 419 420 /** 421 * If false the element won't be visible on the board, otherwise it is shown. 422 * @type boolean 423 * @name JXG.GeometryElement#visible 424 * @see #hideElement 425 * @see #showElement 426 * @default true 427 */ 428 this.visProp.visible = true; 429 430 /** 431 * If true the element will get a shadow. 432 * @type boolean 433 * @name JXG.GeometryElement#shadow 434 * @default false 435 */ 436 this.visProp['shadow'] = false; 437 438 // TODO: withLabel 439 440 // TODO: comment gradient possibilities 441 this.visProp['gradient'] = 'none'; 442 this.visProp['gradientSecondColor'] = 'black'; 443 this.visProp['gradientAngle'] = '270'; 444 this.visProp['gradientSecondOpacity'] = this.visProp['fillOpacity']; 445 this.visProp['gradientPositionX'] = 0.5; 446 this.visProp['gradientPositionY'] = 0.5; 447 }; 448 449 /** 450 * Add an element as a child to the current element. Can be used to model dependencies between geometry elements. 451 * @param {JXG.GeometryElement} obj The dependent object. 452 */ 453 JXG.GeometryElement.prototype.addChild = function (obj) { 454 var el, el2; 455 456 this.childElements[obj.id] = obj; 457 458 this.addDescendants(obj); 459 460 obj.ancestors[this.id] = this; 461 for(el in this.descendants) { 462 this.descendants[el].ancestors[this.id] = this; 463 for(el2 in this.ancestors) { 464 this.descendants[el].ancestors[this.ancestors[el2].id] = this.ancestors[el2]; 465 } 466 } 467 for(el in this.ancestors) { 468 for(el2 in this.descendants) { 469 this.ancestors[el].descendants[this.descendants[el2].id] = this.descendants[el2]; 470 } 471 } 472 return this; 473 }; 474 475 /** 476 * Adds the given object to the descendants list of this object and all its child objects. 477 * @param {JXG.GeometryElement} obj The element that is to be added to the descendants list. 478 * @private 479 * @return 480 */ 481 JXG.GeometryElement.prototype.addDescendants = function (obj) { 482 var el; 483 484 this.descendants[obj.id] = obj; 485 for(el in obj.childElements) { 486 this.addDescendants(obj.childElements[el]); 487 } 488 return this; 489 }; 490 491 /** 492 * Array of strings containing the polynomials defining the element. 493 * Used for determining geometric loci the groebner way. 494 * @type Array 495 * @return An array containing polynomials describing the locus of the current object. 496 * @private 497 */ 498 JXG.GeometryElement.prototype.generatePolynomial = function () { 499 return []; 500 }; 501 502 /** 503 * Animates properties for that object like stroke or fill color, opacity and maybe 504 * even more later. 505 * @param {Object} hash Object containing propiertes with target values for the animation. 506 * @param {number} time Number of milliseconds to complete the animation. 507 * @return A reference to the object 508 * @type JXG.GeometryElement 509 */ 510 JXG.GeometryElement.prototype.animate = function(hash, time) { 511 var r, p, 512 delay = 35, 513 steps = Math.ceil(time/(delay * 1.0)), 514 i, self = this; 515 516 this.animationData = {}; 517 518 var animateColor = function(startRGB, endRGB, property) { 519 var hsv1, hsv2, sh, ss, sv; 520 hsv1 = JXG.rgb2hsv(startRGB); 521 hsv2 = JXG.rgb2hsv(endRGB); 522 523 sh = (hsv2[0]-hsv1[0])/(1.*steps); 524 ss = (hsv2[1]-hsv1[1])/(1.*steps); 525 sv = (hsv2[2]-hsv1[2])/(1.*steps); 526 self.animationData[property] = new Array(steps); 527 for(i=0; i<steps; i++) { 528 self.animationData[property][steps-i-1] = JXG.hsv2rgb(hsv1[0]+(i+1)*sh, hsv1[1]+(i+1)*ss, hsv1[2]+(i+1)*sv); 529 } 530 }, 531 532 animateFloat = function(start, end, property) { 533 start = parseFloat(start); 534 end = parseFloat(end); 535 536 // we can't animate without having valid numbers. 537 // And parseFloat returns NaN if the given string doesn't contain 538 // a valid float number. 539 if(isNaN(start) || isNaN(end)) 540 return; 541 542 var s = (end - start)/(1.*steps); 543 self.animationData[property] = new Array(steps); 544 for(i=0; i<steps; i++) { 545 self.animationData[property][steps-i-1] = start + (i+1)*s; 546 } 547 }; 548 549 for(r in hash) { 550 p = r.toLowerCase(); 551 switch(p) { 552 case 'strokecolor': 553 animateColor(this.visProp['strokeColor'], hash[r], 'strokeColor'); 554 break; 555 case 'strokeopacity': 556 animateFloat(this.visProp['strokeOpacity'], hash[r], 'strokeOpacity'); 557 break; 558 case 'strokewidth': 559 animateFloat(this.visProp['strokeWidth'], hash[r], 'strokeWidth'); 560 break; 561 case 'fillcolor': 562 animateColor(this.visProp['fillColor'], hash[r], 'fillColor'); 563 break; 564 case 'fillopacity': 565 animateFloat(this.visProp['fillOpacity'], hash[r], 'fillOpacity'); 566 break; 567 } 568 } 569 570 this.board.addAnimation(this); 571 return this; 572 }; 573 574 /** 575 * General update method. Should be overwritten by the element itself. 576 * Can be used sometimes to commit changes to the object. 577 */ 578 JXG.GeometryElement.prototype.update = function() { 579 if(this.traced) { 580 this.cloneToBackground(true); 581 } 582 return this; 583 }; 584 585 /** 586 * Provide updateRenderer method. 587 * @private 588 */ 589 JXG.GeometryElement.prototype.updateRenderer = function() { 590 }; 591 592 /** 593 * Hide the element. It will still exist but not visible on the board. 594 */ 595 JXG.GeometryElement.prototype.hideElement = function() { 596 this.visProp['visible'] = false; 597 this.board.renderer.hide(this); 598 if (this.label!=null && this.hasLabel) { 599 this.label.hiddenByParent = true; 600 if(this.label.content.visProp['visible']) { 601 this.board.renderer.hide(this.label.content); 602 } 603 } 604 return this; 605 }; 606 607 /** 608 * Make the element visible. 609 */ 610 JXG.GeometryElement.prototype.showElement = function() { 611 this.visProp['visible'] = true; 612 this.board.renderer.show(this); 613 if (this.label!=null && this.hasLabel && this.label.hiddenByParent) { 614 this.label.hiddenByParent = false; 615 if(this.label.content.visProp['visible']) { 616 this.board.renderer.show(this.label.content); 617 } 618 } 619 return this; 620 }; 621 622 623 /* this list is left from the comment below. just to have a list of properties. 624 * <ul>Possible keys:</ul> 625 *<li>strokeWidth</li> 626 *<li>strokeColor</li> 627 *<li>fillColor</li> 628 *<li>highlightFillColor</li> 629 *<li>highlightStrokeColor</li> 630 *<li>strokeOpacity</li> 631 *<li>fillOpacity</li> 632 *<li>highlightFillOpacity</li> 633 *<li>highlightStrokeOpacity</li> 634 *<li>labelColor</li> 635 *<li>visible</li> 636 *<li>dash</li> 637 *<li>trace</li> 638 *<li>style <i>(Point)</i></li> 639 *<li>fixed</li> 640 *<li>frozen</li> 641 *<li>draft</li> 642 *<li>showInfobox</li> 643 *<li>straightFirst <i>(Line)</i></li> 644 *<li>straightLast <i>(Line)</i></li> 645 *<li>firstArrow <i>(Line,Arc)</li> 646 *<li>lastArrow <i>(Line,Arc)</li> 647 *<li>withTicks <i>(Line)</li> 648 *<li>fontSize</li> 649 *<li>color</li> 650 *<li>opacity</li> 651 * <li>needsRegularUpdate</li> 652 *</ul>*/ 653 654 /** 655 * Sets an arbitrary number of properties. 656 * @param % Arbitrary number of strings, containing "key:value" pairs. 657 * The possible key values are the element and class fields in this documentation. 658 * @example 659 * // Set property directly on creation of an element using the attributes object parameter 660 * var board = JXG.JSXGraph.initBoard('jxgbox', {boundingbox: [-1, 5, 5, 1]}; 661 * var p = board.create('point', [2, 2], {visible: false}); 662 * 663 * // Now make this point visible and fixed: 664 * p.setProperty('fixed:true', 'visible:true'); 665 * 666 * // Alternatively you can use #hideElement resp. #showElement: 667 * p.hideElement(); 668 */ 669 JXG.GeometryElement.prototype.setProperty = function () { 670 var i, key, color, pairRaw, 671 opacity, 672 pair; 673 674 for (i=0; i<arguments.length; i++) { 675 pairRaw = arguments[i]; 676 if (typeof pairRaw == 'string') { // pairRaw is string of the form 'key:value' 677 pair = pairRaw.split(':'); 678 // trim pair[0] and pair[1] 679 pair[0] = pair[0].replace (/^\s+/, '').replace (/\s+$/, ''); 680 pair[1] = pair[1].replace (/^\s+/, '').replace (/\s+$/, ''); 681 } else if (!JXG.isArray(pairRaw)) { // pairRaw consists of objects of the form {key1:value1,key2:value2,...} 682 /* 683 for (var i=0; i<Object.keys(pairRaw).length;i++) { // Here, the prototype lib is used (Object.keys, Object.isArray) 684 var key = Object.keys(pairRaw)[i]; 685 this.setProperty([key,pairRaw[key]]); 686 } 687 */ 688 for (key in pairRaw) { 689 this.setProperty([key,pairRaw[key]]); 690 } 691 return this; 692 } else { // pairRaw consists of array [key,value] 693 pair = pairRaw; 694 } 695 if (pair[1]==null) continue; 696 switch(pair[0].replace(/\s+/g, '').toLowerCase()) { // Whitespace entfernt und in Kleinbuchstaben umgewandelt. 697 case 'needsregularupdate': 698 this.needsRegularUpdate = !(pair[1] == 'false' || pair[1] == false); 699 700 this.board.renderer.setBuffering(this, this.needsRegularUpdate ? 'auto' : 'static'); 701 break; 702 case 'color': 703 this.setProperty({strokeColor: pair[1], fillColor: pair[1]}); 704 break; 705 case 'opacity': 706 this.setProperty({strokeOpacity: pair[1], fillOpacity: pair[1]}); 707 break; 708 case 'strokewidth': 709 this.visProp['strokeWidth'] = pair[1]; 710 this.visProp['highlightStrokeWidth'] = pair[1]; 711 this.board.renderer.setObjectStrokeWidth(this, this.visProp['strokeWidth']); 712 break; 713 case 'strokecolor': 714 color = pair[1]; 715 if (color.length=='9' && color.substr(0,1)=='#') { 716 opacity = color.substr(7,2); 717 color = color.substr(0,7); 718 } 719 else { 720 opacity = 'FF'; 721 } 722 this.visProp['strokeColor'] = color; 723 this.visProp['strokeOpacity'] = parseInt(opacity.toUpperCase(),16)/255; 724 this.board.renderer.setObjectStrokeColor(this, this.visProp['strokeColor'], this.visProp['strokeOpacity']); 725 break; 726 case 'fillcolor': 727 color = pair[1]; 728 if (color.length=='9' && color.substr(0,1)=='#') { 729 opacity = color.substr(7,2); 730 color = color.substr(0,7); 731 } 732 else { 733 opacity = 'FF'; 734 } 735 this.visProp['fillColor'] = color; 736 this.visProp['fillOpacity'] = parseInt(opacity.toUpperCase(),16)/255; 737 this.board.renderer.setObjectFillColor(this, this.visProp['fillColor'], this.visProp['fillOpacity']); 738 break; 739 case 'highlightstrokewidth': 740 this.visProp['highlightStrokeWidth'] = pair[1]; 741 break; 742 case 'highlightstrokecolor': 743 color = pair[1]; 744 if (color.length=='9' && color.substr(0,1)=='#') { 745 opacity = color.substr(7,2); 746 color = color.substr(0,7); 747 } 748 else { 749 opacity = 'FF'; 750 } 751 this.visProp['highlightStrokeColor'] = color; 752 this.visProp['highlightStrokeOpacity'] = parseInt(opacity.toUpperCase(),16)/255; 753 break; 754 case 'highlightfillcolor': 755 color = pair[1]; 756 if (color.length=='9' && color.substr(0,1)=='#') { 757 opacity = color.substr(7,2); 758 color = color.substr(0,7); 759 } 760 else { 761 opacity = 'FF'; 762 } 763 this.visProp['highlightFillColor'] = color; 764 this.visProp['highlightFillOpacity'] = parseInt(opacity.toUpperCase(),16)/255; 765 break; 766 case 'fillopacity': 767 this.visProp['fillOpacity'] = pair[1]; 768 this.board.renderer.setObjectFillColor(this, this.visProp['fillColor'], this.visProp['fillOpacity']); 769 break; 770 case 'strokeopacity': 771 this.visProp['strokeOpacity'] = pair[1]; 772 this.board.renderer.setObjectStrokeColor(this, this.visProp['strokeColor'], this.visProp['strokeOpacity']); 773 break; 774 case 'highlightfillopacity': 775 this.visProp['highlightFillOpacity'] = pair[1]; 776 break; 777 case 'highlightstrokeopacity': 778 this.visProp['highlightStrokeOpacity'] = pair[1]; 779 break; 780 case 'labelcolor': 781 color = pair[1]; 782 if (color.length=='9' && color.substr(0,1)=='#') { 783 opacity = color.substr(7,2); 784 color = color.substr(0,7); 785 } 786 else { 787 opacity = 'FF'; 788 } 789 if(opacity == '00') { 790 if (this.label!=null && this.hasLabel) { 791 this.label.content.hideElement(); 792 } 793 } 794 if(this.label!=null && this.hasLabel) { 795 this.label.color = color; 796 this.board.renderer.setObjectStrokeColor(this.label.content, color, opacity); 797 } 798 if(this.type == JXG.OBJECT_TYPE_TEXT) { 799 this.visProp['strokeColor'] = color; 800 this.board.renderer.setObjectStrokeColor(this, this.visProp['strokeColor'], 1); 801 } 802 break; 803 case 'infoboxtext': 804 if(typeof(pair[1]) == 'string') { 805 this.infoboxText = pair[1]; 806 } 807 else this.infoboxText = false; 808 break; 809 case 'showinfobox': 810 if(pair[1] == 'false' || pair[1] == false) { 811 this.showInfobox = false; 812 } 813 else if(pair[1] == 'true' || pair[1] == true) { 814 this.showInfobox = true; 815 } 816 break; 817 case 'visible': 818 if(pair[1] == 'false' || pair[1] == false) { 819 this.visProp['visible'] = false; 820 this.hideElement(); 821 } 822 else if(pair[1] == 'true' || pair[1] == true) { 823 this.visProp['visible'] = true; 824 this.showElement(); 825 } 826 break; 827 case 'dash': 828 this.setDash(pair[1]); 829 break; 830 case 'trace': 831 if(pair[1] == 'false' || pair[1] == false) { 832 this.traced = false; 833 } 834 else if(pair[1] == 'true' || pair[1] == true) { 835 this.traced = true; 836 } 837 break; 838 case 'style': 839 this.setStyle(1*pair[1]); 840 break; 841 case 'face': 842 if(this.elementClass == JXG.OBJECT_CLASS_POINT) 843 this.setFace(pair[1]); 844 break; 845 case 'size': 846 if(this.elementClass == JXG.OBJECT_CLASS_POINT) { 847 this.visProp['size'] = 1*pair[1]; 848 this.board.renderer.updatePoint(this); 849 } 850 break; 851 case 'fixed': 852 this.fixed = ((pair[1]=='false') || (pair[1]==false)) ? false : true; 853 break; 854 case 'frozen': 855 this.frozen = ((pair[1]=='false') || (pair[1]==false)) ? false : true; 856 break; 857 case 'shadow': 858 if(pair[1] == 'false' || pair[1] == false) { 859 this.visProp['shadow'] = false; 860 } 861 else if(pair[1] == 'true' || pair[1] == true) { 862 this.visProp['shadow'] = true; 863 } 864 this.board.renderer.setShadow(this); 865 break; 866 case 'gradient': 867 this.visProp['gradient'] = pair[1]; 868 this.board.renderer.setGradient(this); 869 break; 870 case 'gradientsecondcolor': 871 color = pair[1]; 872 if (color.length=='9' && color.substr(0,1)=='#') { 873 opacity = color.substr(7,2); 874 color = color.substr(0,7); 875 } 876 else { 877 opacity = 'FF'; 878 } 879 this.visProp['gradientSecondColor'] = color; 880 this.visProp['gradientSecondOpacity'] = parseInt(opacity.toUpperCase(),16)/255; 881 this.board.renderer.updateGradient(this); 882 break; 883 case 'gradientsecondopacity': 884 this.visProp['gradientSecondOpacity'] = pair[1]; 885 this.board.renderer.updateGradient(this); 886 break; 887 case 'draft': 888 if(pair[1] == 'false' || pair[1] == false) { 889 if(this.visProp['draft'] == true) { 890 this.visProp['draft'] = false; 891 this.board.renderer.removeDraft(this); 892 } 893 } 894 else if(pair[1] == 'true' || pair[1] == true) { 895 this.visProp['draft'] = true; 896 this.board.renderer.setDraft(this); 897 } 898 break; 899 case 'straightfirst': 900 if(pair[1] == 'false' || pair[1] == false) { 901 this.visProp['straightFirst'] = false; 902 } 903 else if(pair[1] == 'true' || pair[1] == true) { 904 this.visProp['straightFirst'] = true; 905 } 906 this.setStraight(this.visProp['straightFirst'], this.visProp['straightLast']); 907 break; 908 case 'straightlast': 909 if(pair[1] == 'false' || pair[1] == false) { 910 this.visProp['straightLast'] = false; 911 } 912 else if(pair[1] == 'true' || pair[1] == true) { 913 this.visProp['straightLast'] = true; 914 } 915 this.setStraight(this.visProp['straightFirst'], this.visProp['straightLast']); 916 break; 917 case 'firstarrow': 918 if(pair[1] == 'false' || pair[1] == false) { 919 this.visProp['firstArrow'] = false; 920 } 921 else if(pair[1] == 'true' || pair[1] == true) { 922 this.visProp['firstArrow'] = true; 923 } 924 this.setArrow(this.visProp['firstArrow'], this.visProp['lastArrow']); 925 break; 926 case 'lastarrow': 927 if(pair[1] == 'false' || pair[1] == false) { 928 this.visProp['lastArrow'] = false; 929 } 930 else if(pair[1] == 'true' || pair[1] == true) { 931 this.visProp['lastArrow'] = true; 932 } 933 this.setArrow(this.visProp['firstArrow'], this.visProp['lastArrow']); 934 break; 935 case 'curvetype': 936 this.curveType = pair[1]; 937 break; 938 case 'fontsize': 939 this.visProp['fontSize'] = pair[1]; 940 break; 941 case 'insertticks': 942 if(this.type == JXG.OBJECT_TYPE_TICKS) { 943 var old = this.insertTicks; 944 945 this.insertTicks = !(pair[1] == 'false' || pair[1] == false); 946 if(old != this.insertTicks) this.prepareUpdate().update().updateRenderer(); 947 } 948 break; 949 case 'drawlabels': 950 if(this.type == JXG.OBJECT_TYPE_TICKS) { 951 var old = this.drawLabels; 952 953 this.drawLabels = !(pair[1] == 'false' || pair[1] == false); 954 if(old != this.drawLabels) this.prepareUpdate().update().updateRenderer(); 955 } 956 break; 957 case 'drawzero': 958 if(this.type == JXG.OBJECT_TYPE_TICKS) { 959 var old = this.drawZero; 960 961 this.drawZero = !(pair[1] == 'false' || pair[1] == false); 962 if(old != this.drawZero) this.prepareUpdate().update().updateRenderer(); 963 } 964 break; 965 case 'minorticks': 966 if(this.type == JXG.OBJECT_TYPE_TICKS) { 967 var old = this.minorTicks; 968 if((pair[1] != null) && (pair[1] > 0)) 969 this.minorTicks = pair[1]; 970 if(old != this.minorTicks) this.prepareUpdate().update().updateRenderer(); 971 } 972 break; 973 case 'majortickheight': 974 if(this.type == JXG.OBJECT_TYPE_TICKS) { 975 var old = this.majorHeight; 976 if((pair[1] != null) && (pair[1] > 0)) 977 this.majorHeight = pair[1]; 978 if(old != this.majorHeight) this.prepareUpdate().update().updateRenderer(); 979 } 980 break; 981 case 'minortickheight': 982 if(this.type == JXG.OBJECT_TYPE_TICKS) { 983 var old = this.minorHeight; 984 if((pair[1] != null) && (pair[1] > 0)) 985 this.minorHeight = pair[1]; 986 if(old != this.minorHeight) this.prepareUpdate().update().updateRenderer(); 987 } 988 break; 989 case 'snapwidth': 990 if(this.type == JXG.OBJECT_TYPE_GLIDER) { 991 this.snapWidth = pair[1]; 992 } 993 break; 994 case 'withlabel': 995 if(!pair[1]) { 996 if (this.label!=null && this.hasLabel) { 997 this.label.content.hideElement(); 998 } 999 } 1000 else { 1001 if (this.label!=null && this.hasLabel) { 1002 if(this.visProp['visible']) { 1003 this.label.content.showElement(); 1004 } 1005 1006 } 1007 else { 1008 this.addLabelToElement(); 1009 if(!this.visProp['visible']) { 1010 this.label.content.hideElement(); 1011 } 1012 } 1013 } 1014 this.hasLabel = pair[1]; 1015 } 1016 } 1017 this.board.update(this); 1018 return this; 1019 }; 1020 1021 /** 1022 * Set the dash style of an object. See {@link #dash} for a list of available dash styles. 1023 * You should use {@link #setProperty} instead of this method. 1024 * @param {number} dash Indicates the new dash style 1025 * @private 1026 */ 1027 JXG.GeometryElement.prototype.setDash = function(dash) { 1028 this.visProp['dash'] = dash; 1029 this.board.renderer.setDashStyle(this,this.visProp); 1030 return this; 1031 }; 1032 1033 /** 1034 * Notify all child elements for updates. 1035 * @private 1036 */ 1037 JXG.GeometryElement.prototype.prepareUpdate = function() { 1038 this.needsUpdate = true; 1039 return this; // Im Moment steigen wir nicht rekursiv hinab 1040 /* End of function */ 1041 1042 /* 1043 var el; 1044 for(el in this.childElements) { 1045 // Wurde das Element vielleicht geloescht? 1046 if(JXG.exists(this.board.objects[el])) { 1047 // Nein, wurde es nicht, also updaten 1048 this.childElements[el].prepareUpdate(); 1049 } else { // es wurde geloescht, also aus dem Array entfernen 1050 delete(this.childElements[el]); 1051 } 1052 } 1053 */ 1054 }; 1055 1056 /** 1057 * Removes the element from the construction. 1058 */ 1059 JXG.GeometryElement.prototype.remove = function() { 1060 this.board.renderer.remove(this.board.renderer.getElementById(this.id)); 1061 1062 if (this.hasLabel) { 1063 this.board.renderer.remove(this.board.renderer.getElementById(this.label.content.id)); 1064 } 1065 return this; 1066 }; 1067 1068 /** 1069 * Returns the coords object where a text that is bound to the element shall be drawn. 1070 * Differs in some cases from the values that getLabelAnchor returns. 1071 * @type JXG.Coords 1072 * @return JXG.Coords Place where the text shall be drawn. 1073 * @see #getLabelAnchor 1074 * @private 1075 */ 1076 JXG.GeometryElement.prototype.getTextAnchor = function() { 1077 return new JXG.Coords(JXG.COORDS_BY_USER, [0,0], this.board); 1078 }; 1079 1080 /** 1081 * Returns the coords object where the label of the element shall be drawn. 1082 * Differs in some cases from the values that getTextAnchor returns. 1083 * @type JXG.Coords 1084 * @return JXG.Coords Place where the label of an element shall be drawn. 1085 * @see #getTextAnchor 1086 * @private 1087 */ 1088 JXG.GeometryElement.prototype.getLabelAnchor = function() { 1089 return new JXG.Coords(JXG.COORDS_BY_USER, [0,0], this.board); 1090 }; 1091 1092 /** 1093 * TODO 1094 * Was hat das hier verloren? Styles gibts doch nur fuer Punkte oder? 1095 * Sollte das dann nicht nur in Point.js zu finden sein? --michael 1096 * @private 1097 */ 1098 JXG.GeometryElement.prototype.setStyle = function(x) { 1099 return this; 1100 }; 1101 1102 /** 1103 * TODO 1104 * Was hat das hier verloren? "Straights" gibts doch nur fuer Lines oder? 1105 * Sollte das dann nicht nur in Line.js zu finden sein? --michael 1106 * @private 1107 */ 1108 JXG.GeometryElement.prototype.setStraight = function(x,y) { 1109 return this; 1110 }; 1111 1112 /** 1113 * Determines whether the arc has arrows at start or end of the arc. 1114 * @param {bool} firstArrow True if there is an arrow at the start of the arc, false otherwise. 1115 * @param {bool} lastArrow True if there is an arrow at the end of the arc, false otherwise. 1116 * Is stored at visProp['firstArrow'] and visProp['lastArrow'] 1117 */ 1118 JXG.GeometryElement.prototype.setArrow = function (firstArrow, lastArrow) { 1119 this.visProp['firstArrow'] = firstArrow; 1120 this.visProp['lastArrow'] = lastArrow; 1121 this.prepareUpdate().update(); 1122 return this; 1123 }; 1124 1125 /** 1126 * Creates a label element for this geometry element. 1127 * Doesn't add the label to the board, so it shouldn't be called itself. Use {@link #addLabelToElement} instead. 1128 * @param {boolean} withLabel true if a label shall be initialized, false otherwise. 1129 * @see #addLabelToElement 1130 * @private 1131 */ 1132 JXG.GeometryElement.prototype.createLabel = function(withLabel,coords) { 1133 // WTF?!? Eine Methode namens createLabel, die optional kein label erstellt? 1134 // TODO - Spaeter genauer ansehen, grad keine Zeit 1135 var isTmpId = false; 1136 if (!JXG.exists(coords)) { 1137 coords = [10,10]; 1138 } 1139 this.nameHTML = JXG.GeonextParser.replaceSup(JXG.GeonextParser.replaceSub(this.name)); 1140 this.label = {}; 1141 if (typeof withLabel=='undefined' || withLabel==true) { 1142 if (this.board.objects[this.id]==null) { 1143 this.board.objects[this.id] = this; 1144 isTmpId = true; 1145 } 1146 this.label.relativeCoords = coords; 1147 this.label.content = new JXG.Text(this.board, this.nameHTML, this.id, 1148 [this.label.relativeCoords[0],-this.label.relativeCoords[1]], this.id+"Label", "", null, true, this.board.options.text.defaultDisplay); 1149 if (isTmpId) delete(this.board.objects[this.id]); 1150 this.label.color = '#000000'; 1151 if(!this.visProp['visible']) { 1152 this.label.hiddenByParent = true; 1153 this.label.content.visProp['visible'] = false; 1154 } 1155 this.hasLabel = true; 1156 } 1157 return this; 1158 }; 1159 1160 /** 1161 * Adds a label to the element. 1162 */ 1163 JXG.GeometryElement.prototype.addLabelToElement = function() { 1164 this.createLabel(true); 1165 this.label.content.id = this.id+"Label"; 1166 this.board.setId(this.label.content, 'T'); 1167 this.board.renderer.drawText(this.label.content); 1168 if(!this.label.content.visProp['visible']) { 1169 this.board.renderer.hide(this.label.content); 1170 } 1171 return this; 1172 }; 1173 1174 /** 1175 * Highlights the element. 1176 */ 1177 JXG.GeometryElement.prototype.highlight = function() { 1178 this.board.renderer.highlight(this); 1179 return this; 1180 }; 1181 1182 /** 1183 * Uses the "normal" properties of the element. 1184 */ 1185 JXG.GeometryElement.prototype.noHighlight = function() { 1186 this.board.renderer.noHighlight(this); 1187 return this; 1188 }; 1189 1190 /** 1191 * Removes all objects generated by the trace function. 1192 */ 1193 JXG.GeometryElement.prototype.clearTrace = function() { 1194 var obj; 1195 for(obj in this.traces) { 1196 this.board.renderer.remove(this.traces[obj]); 1197 } 1198 this.numTraces = 0; 1199 return this; 1200 }; 1201 1202 /** 1203 * Copy element to background. Has to be implemented in the element itself. 1204 * @private 1205 */ 1206 JXG.GeometryElement.prototype.cloneToBackground = function(addToTrace) { 1207 return this; 1208 }; 1209 1210 // [c,b0,b1,a,k] 1211 /** 1212 * Normalize the element's standard form. 1213 * @private 1214 */ 1215 JXG.GeometryElement.prototype.normalize = function() { 1216 this.stdform = JXG.Math.normalize(this.stdform); 1217 return this; 1218 }; 1219 1220 /** 1221 * EXPERIMENTAL. Generate JSON object code of visProp and other properties. 1222 * @type string 1223 * @private 1224 * @return JSON string containing element's properties. 1225 */ 1226 JXG.GeometryElement.prototype.toJSON = function() { 1227 var json = '{"name":' + this.name; 1228 json += ', ' + '"id":' + this.id; 1229 1230 var vis = []; 1231 for (var key in this.visProp) { 1232 if (this.visProp[key]!=null) { 1233 vis.push('"' + key + '":' + this.visProp[key]); 1234 } 1235 } 1236 json += ', "visProp":{'+vis.toString()+'}'; 1237 json +='}'; 1238 1239 return json; 1240 }; 1241 1242 /** 1243 * Set the highlightStrokeColor of an element 1244 * @param {String} sColor String which determines the stroke color of an object when its highlighted. 1245 * @see JXG.GeometryElement#highlightStrokeColor 1246 */ 1247 JXG.GeometryElement.prototype.highlightStrokeColor = function(sColor) { 1248 this.setProperty({highlightStrokeColor:sColor}); 1249 }; 1250 1251 /** 1252 * Set the strokeColor of an element 1253 * @param {String} sColor String which determines the stroke color of an object. 1254 * @see JXG.GeometryElement#strokeColor 1255 */ 1256 JXG.GeometryElement.prototype.strokeColor = function(sColor) { 1257 this.setProperty({strokeColor:sColor}); 1258 }; 1259 1260 /** 1261 * Set the strokeWidth of an element 1262 * @param {Integer} width Integer which determines the stroke width of an outline. 1263 * @see JXG.GeometryElement#strokeWidth 1264 */ 1265 JXG.GeometryElement.prototype.strokeWidth = function(width) { 1266 this.setProperty({strokeWidth:width}); 1267 }; 1268 1269 1270 /** 1271 * Set the fillColor of an element 1272 * @param {String} fColor String which determines the fill color of an object. 1273 * @see JXG.GeometryElement#fillColod 1274 */ 1275 JXG.GeometryElement.prototype.fillColor = function(fColor) { 1276 this.setProperty({fillColor:fColor}); 1277 }; 1278 1279 /** 1280 * Set the highlightFillColor of an element 1281 * @param {String} fColor String which determines the fill color of an object when its highlighted. 1282 * @see JXG.GeometryElement#highlightFillColor 1283 */ 1284 JXG.GeometryElement.prototype.highlightFillColor = function(fColor) { 1285 this.setProperty({highlightFillColor:fColor}); 1286 }; 1287 1288 /** 1289 * Set the labelColor of an element 1290 * @param {String} lColor String which determines the text color of an object's label. 1291 * @see JXG.GeometryElement#labelColor 1292 */ 1293 JXG.GeometryElement.prototype.labelColor = function(lColor) { 1294 this.setProperty({labelColor:lColor}); 1295 }; 1296 1297 /** 1298 * Set the dash type of an element 1299 * @param {Int} d Integer which determines the way of dashing an element's outline. 1300 * @see JXG.GeometryElement#dash 1301 */ 1302 JXG.GeometryElement.prototype.dash = function(d) { 1303 this.setProperty({dash:d}); 1304 }; 1305 1306 /** 1307 * Set the visibility of an element 1308 * @param {Boolean} v Boolean which determines whether the element is drawn. 1309 * @see JXG.GeometryElement#visible 1310 */ 1311 JXG.GeometryElement.prototype.visible = function(v) { 1312 this.setProperty({visible:v}); 1313 }; 1314 1315 /** 1316 * Set the shadow of an element 1317 * @param {Boolean} v Boolean which determines whether the element has a shadow. 1318 * @see JXG.GeometryElement#shadow 1319 */ 1320 JXG.GeometryElement.prototype.shadow = function(s) { 1321 this.setProperty({shadow:s}); 1322 }; 1323 1324 1325 /** 1326 * Setting visPropOld is done in an none object oriented version 1327 * since otherwise there would be problems in cloneToBackground 1328 */ 1329 JXG.clearVisPropOld = function(el) { 1330 el.visPropOld = {}; 1331 el.visPropOld['strokeColor']= ''; 1332 el.visPropOld['strokeOpacity']= ''; 1333 el.visPropOld['strokeWidth']= ''; 1334 el.visPropOld['fillColor']= ''; 1335 el.visPropOld['fillOpacity']= ''; 1336 el.visPropOld['shadow']= false; 1337 el.visPropOld['firstArrow'] = false; 1338 el.visPropOld['lastArrow'] = false; 1339 }; 1340 // vim: et ts=4 1341