1 /*! 2 * 3 * RaphaëlTools : Raphaël extension (button, sliders, misc..) 4 * version 0.5.1 (2011-10-06) 5 * 6 * Copyright (C) 2011 Jan Stransky 7 * 8 * Czech Technical University, Faculty of Civil Engineering, 9 * Department of Structural Mechanics, 166 29 Prague, Czech Republic 10 * 11 * 12 * This program is free software: you can redistribute it and/or modify 13 * it under the terms of the GNU 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 * This program 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 General Public License for more details. 21 * 22 * You should have received a copy of the GNU General Public License 23 * along with this program. If not, see <http://www.gnu.org/licenses/>. 24 */ 25 26 /** 27 * @fileOverview <a href="http://raphaeljs.com/">Raphaël</a> (svg javascript library) extension by various functions and "classes" (slider, button, etc.). Requires <a href="http://raphaeljs.com/">raphael.js</a> loaded before loading this file. For more information see <a href="http://mech.fsv.cvut.cz/~stransky/software/raphaeltools/">project homepage</a>. 28 <br /><br/>RaphaëlTools is a free software distributed under <a href='http://www.gnu.org/licenses/gpl.html'>GNU GPL license</a>. 29 * @author <a href="http://mech.fsv.cvut.cz/~stransky/">Jan Stránský</a> 30 * @version Version 0.5.1 (2011-10-06) 31 */ 32 33 /** Generic function used for draging ojects. For each dragable object should be defined function dragUpdate(dx,dz): e.g. moving only in x direction etc. 34 * @param {float} dx x increment of dragging 35 * @param {float} dz z increment of dragging 36 * @example 37 * a = new Arrow(100,59,199,30) // equivalent to a = Arrow.create(100,59,199,30); 38 * a.dragUpdate = function(dx,dz) { a.translate(dx,dz); } 39 * a.drag(move,init,reset) // make an object draggable using a.dragUpdate() function when moving*/ 40 function dragMove(dx,dz) { 41 this.dragUpdate(dx - (this.deltax || 0), dz - (this.deltaz || 0)); 42 this.deltax = dx; 43 this.deltaz = dz; 44 } 45 46 /** Generic function used for draging ojects, see {@link dragMove}*/ 47 function dragInit() { this.deltax = this.deltaz = 0; } 48 49 /** Generic function used for draging ojects, see {@link dragMove}*/ 50 function dragReset() { this.dragReset(); } 51 52 53 /* *********************************************************** 54 * other generic functions 55 ************************************************************/ 56 /** Raphael function loaded from <a href="http://raphaeljs.com">raphael.js file</a> 57 * @class*/ 58 Raphael = Raphael; 59 60 /** Raphael.el element of {@link Raphael} 61 * @memberOf Raphael# 62 */ 63 Raphael.el = Raphael.el; 64 65 /**#@+ 66 * @function 67 * @memberOf Raphael# 68 */ 69 // color setting 70 /** Sets fill color of receiver to red*/ Raphael.el.fillRed = function() { this.attr({"fill":"#f00"}); } 71 /** Sets fill color of receiver to green*/ Raphael.el.fillGreen = function() { this.attr({"fill":"#0f0"}); } 72 /** Sets fill color of receiver to blue*/ Raphael.el.fillBlue = function() { this.attr({"fill":"#00f"}); } 73 /** Sets fill color of receiver to yellow*/ Raphael.el.fillYellow = function() { this.attr({"fill":"#ff0"}); } 74 /** Sets fill color of receiver to cyan*/ Raphael.el.fillCyan = function() { this.attr({"fill":"#0ff"}); } 75 /** Sets fill color of receiver to magenta*/ Raphael.el.fillMagenta = function() { this.attr({"fill":"#f0f"}); } 76 /** Sets fill color of receiver to orange*/ Raphael.el.fillOrange = function() { this.attr({"fill":"#f50"}); } 77 /** Sets fill color of receiver to black*/ Raphael.el.fillBlack = function() { this.attr({"fill":"#000"}); } 78 /** Sets fill color of receiver to white*/ Raphael.el.fillWhite = function() { this.attr({"fill":"#fff"}); } 79 /** Sets fill color of receiver to gray*/ Raphael.el.fillGray = function() { this.attr({"fill":"#777"}); } 80 /** Sets stroke color of receiver to red*/ Raphael.el.strokeRed = function() { this.attr({"stroke":"#f00"}); } 81 /** Sets stroke color of receiver to green*/ Raphael.el.strokeGreen = function() { this.attr({"stroke":"#0f0"}); } 82 /** Sets stroke color of receiver to blue*/ Raphael.el.strokeBlue = function() { this.attr({"stroke":"#00f"}); } 83 /** Sets stroke color of receiver to yellow*/ Raphael.el.strokeYellow = function() { this.attr({"stroke":"#ff0"}); } 84 /** Sets stroke color of receiver to cyan*/ Raphael.el.strokeCyan = function() { this.attr({"stroke":"#0ff"}); } 85 /** Sets stroke color of receiver to magenta*/ Raphael.el.strokeMagenta = function() { this.attr({"stroke":"#f0f"}); } 86 /** Sets stroke color of receiver to orange*/ Raphael.el.strokeOrange = function() { this.attr({"stroke":"#f50"}); } 87 /** Sets stroke color of receiver to black*/ Raphael.el.strokeBlack = function() { this.attr({"stroke":"#000"}); } 88 /** Sets stroke color of receiver to white*/ Raphael.el.strokeWhite = function() { this.attr({"stroke":"#fff"}); } 89 /** Sets stroke color of receiver to gray*/ Raphael.el.strokeGray = function() { this.attr({"stroke":"#777"}); } 90 /** Sets fill and stroke color of receiver to red*/ Raphael.el.red = function() { this.fillRed(); this.strokeRed(); } 91 /** Sets fill and stroke color of receiver to green*/ Raphael.el.green = function() { this.fillGreen(); this.strokeGreen(); } 92 /** Sets fill and stroke color of receiver to blue*/ Raphael.el.blue = function() { this.fillBlue(); this.strokeBlue(); } 93 /** Sets fill and stroke color of receiver to yellow*/ Raphael.el.yellow = function() { this.fillYellow(); this.strokeYellow(); } 94 /** Sets fill and stroke color of receiver to cyan*/ Raphael.el.cyan = function() { this.fillCyan(); this.strokeCyan(); } 95 /** Sets fill and stroke color of receiver to magenta*/ Raphael.el.magenta = function() { this.fillMagenta(); this.strokeMagenta(); } 96 /** Sets fill and stroke color of receiver to orange*/ Raphael.el.orange = function() { this.fillOrange(); this.strokeOrange(); } 97 /** Sets fill and stroke color of receiver to black*/ Raphael.el.black = function() { this.fillBlack(); this.strokeBlack(); } 98 /** Sets fill and stroke color of receiver to white*/ Raphael.el.white = function() { this.fillWhite(); this.strokeWhite(); } 99 /** Sets fill and stroke color of receiver to gray*/ Raphael.el.gray = function() { this.fillGreen(); this.strokeGray(); } 100 /** Set width of receiver 101 * @param w new width*/ 102 Raphael.el.setWidth = function(w) { this.attr({"stroke-width":w}); } 103 /**#@-*/ 104 105 /** Returns [x,z] components of transformated vector 106 * @param {float} x x component of original vector 107 * @param {float} z z component of original vector 108 * @param {float} sin sin of angle of rotation 109 * @param {float} cos cos of angle of rotation 110 * @returns {[float,float]} coordinates of transformated vector*/ 111 vecTrans = function(x,z,sin,cos) { return [x*cos-z*sin,x*sin+z*cos]; } 112 113 114 115 /** 2d xz plane point implementation 116 * @class represents points in 2d zx plane 117 * @param {float} x x coordinate of point 118 * @param {float} z z coordinate of point 119 * @property {float} x x coordinate 120 * @property {float} z z coordinate 121 * @property {[Points2d]} copies array of copies of itself 122 * @property {[[float,float]]} copiesShifts horizontal and verical shifts of copies from receiver*/ 123 Point2d = function(x,z) { 124 this.x = x || 0; 125 this.z = z || 0; 126 this.copies = []; 127 this.copiesShifts = [] 128 129 /** String representation 130 * @returns {String} string representation*/ 131 this.toString = function() { 132 return "Point2d ( "+this.x+","+this.z+" )"; 133 } 134 135 /** Copy receiver to given positions 136 * @param {[[float,float]]} shifts vertical and horizontal shifts of copied points 137 * @example n = Point2d(100,150); 138 * shifts=[[100,200],[200,200],[100,300],[200,300]]*/ 139 this.copy = function(shifts) { 140 for (var i=0; i<shifts.length; i++) { 141 this.copiesShifts.push(shifts[i]); 142 this.copies.push(new Point2d(this.x+shifts[i][0],this.z+shifts[i][1])); 143 } 144 } 145 146 /** Sets new position to receiver 147 * @param {float} x x coordinate of new position 148 * @param {float} z z coordinate of new position*/ 149 this.setXZ = function(x,z) { 150 this.x=x; this.z=z; this.up(); 151 } 152 153 /** Set new x coordinate to receiver 154 * @param x x coordinate of new position*/ 155 this.setX = function(x) { 156 this.x=x; this.up(); 157 } 158 159 /** Set new z coordinate to receiver 160 * @param z z coordinate of new position*/ 161 this.setZ = function(z) { 162 this.z=z; this.up(); 163 } 164 165 /** Change position of receiver by given values 166 * @param {float} dx length of translation in x direction 167 * @param {float} dz length of translation in z direction*/ 168 this.translate = function(dx,dz) { 169 this.x+=dx; this.z+=dz; this.up(); 170 } 171 172 /** Change horizontal position of receiver by given values 173 * @param {float} dx length of translation in x direction*/ 174 this.translateX = function(dx) { 175 this.x+=dx; this.up(); 176 } 177 178 /** Change vertical position of receiver by given values 179 * @param {float} dz length of translation in x direction*/ 180 this.translateZ = function(dz) { 181 this.z+=dz; this.up(); 182 } 183 184 /** Update receiver (change positions of stored copies so as stored shifts between receiver and its copies remain constant*/ 185 this.up = function() { 186 for (var i=0; i<this.copies.length; i++) { this.copies[i].setXZ(this.x+this.copiesShifts[i][0],this.z+this.copiesShifts[i][1]); this.copies[i].up(); } 187 } 188 } 189 /** Creates new Point2d object, for parameters meaning see {@link Point2d} 190 * @returns {Point2d} new Point2d object*/ 191 Point2d.create = function(x,z) { 192 return new Point2d(x,z); 193 } 194 195 196 197 198 /** 3d point implementation 199 * @class represents points in 3d space 200 * @param {float} xr x coordinate of point in real space 201 * @param {float} yr y coordinate of point in real space 202 * @param {float} zr z coordinate of point in real space 203 * @property {float} xr x coordinate of point in real space 204 * @property {float} yr y coordinate of point in real space 205 * @property {float} zr z coordinate of point in real space 206 * @property {float} x x coordinate of point in screen projection 207 * @property {float} y y coordinate of point in screen projection (can be used for visibility issues) 208 * @property {float} z z coordinate of point in screen projection 209 * @property {[3x(3 or 4) floats]} p projection matrix 210 * @property {[Points]} copies array of copies of itself 211 * @property {[[float,float]]} copiesShifts horizontal and verical shifts of copies from receiver*/ 212 Point3d = function(xr,yr,zr,projection) { 213 this.xr = xr || 0; 214 this.yr = yr || 0; 215 this.zr = zr || 0; 216 this.copies = []; 217 this.copiesShifts = [] 218 this.p = projection==undefined? [[1,0,0],[0,1,0],[0,0,1]] : projection; 219 this.x = this.p[0][0]*this.xr + this.p[0][1]*this.yr + this.p[0][2]*this.zr + (this.p[0][3] || 0); 220 this.y = this.p[1][0]*this.xr + this.p[1][1]*this.yr + this.p[1][2]*this.zr + (this.p[1][3] || 0); 221 this.z = this.p[2][0]*this.xr + this.p[2][1]*this.yr + this.p[2][2]*this.zr + (this.p[2][3] || 0); 222 223 /** String representation 224 * @returns {String} string representation*/ 225 this.toString = function() { 226 return "Point3d ( "+this.xr+","+this.yr+","+this.zr+" )"; 227 } 228 229 /** Copy receiver to given positions 230 * @param {[[float,float,float]]} shifts vertical and horizontal shifts of copied points 231 * @example n = Point3d(100,150,250); 232 * shifts=[[100,200,300],[200,200,500],[100,300,100],[200,300,340]]*/ 233 this.copy = function(shifts) { 234 for (var i=0; i<shifts.length; i++) { 235 this.copiesShifts.push(shifts[i]); 236 this.copies.push(new Point3d(this.xr+shifts[i][0],this.yr+shifts[i][1],this.zr+shifts[i][2])); 237 } 238 } 239 240 /** Sets new position to receiver 241 * @param {float} xr xr coordinate of new position (in real space) 242 * @param {float} yr yr coordinate of new position (in real space) 243 * @param {float} zr zr coordinate of new position (in real space)*/ 244 this.setXYZ = function(xr,yr,zr) { 245 this.xr=xr; this.yr=yr; this.zr=zr; this.up(); 246 } 247 248 /** Set new x coordinate to receiver 249 * @param x x coordinate of new position (in real space)*/ 250 this.setX = function(xr) { 251 this.xr=xr; this.up(); 252 } 253 254 /** Set new y coordinate to receiver 255 * @param y y coordinate of new position (in real space)*/ 256 this.setY = function(yr) { 257 this.yr=yr; this.up(); 258 } 259 260 /** Set new z coordinate to receiver 261 * @param z z coordinate of new position (in real space)*/ 262 this.setZ = function(zr) { 263 this.zr=zr; this.up(); 264 } 265 266 /** Change position of receiver by given values 267 * @param {float} dx length of translation in x direction (in real space) 268 * @param {float} dy length of translation in y direction (in real space) 269 * @param {float} dz length of translation in z direction (in real space)*/ 270 this.translate = function(dx,dy,dz) { 271 this.xr+=dx; this.zr+=dz; this.yr+=dy; this.up(); 272 } 273 274 /** Change horizontal position of receiver by given values 275 * @param {float} dx length of translation in x direction (in real space)*/ 276 this.translateX = function(dx) { 277 this.xr+=dx; this.up(); 278 } 279 280 /** Change horizontal position of receiver by given values 281 * @param {float} dy length of translation in y direction (in real space)*/ 282 this.translateY = function(dy) { 283 this.yr+=dy; this.up(); 284 } 285 286 /** Change vertical position of receiver by given values 287 * @param {float} dz length of translation in x direction (in real space)*/ 288 this.translateZ = function(dz) { 289 this.zr+=dz; this.up(); 290 } 291 292 /** Sets projection matrix 293 * @param {[2x(3 or 4) floats]} p new projection matrix*/ 294 this.setProjection = function(p) { this.p = p; this.up() } 295 296 /** project receiver to xz screen coordinates accordind to this.p*/ 297 this.project = function() { 298 this.x = this.p[0][0]*this.xr + this.p[0][1]*this.yr + this.p[0][2]*this.zr + (this.p[0][3] || 0); 299 this.y = this.p[1][0]*this.xr + this.p[1][1]*this.yr + this.p[1][2]*this.zr + (this.p[1][3] || 0); 300 this.z = this.p[2][0]*this.xr + this.p[2][1]*this.yr + this.p[2][2]*this.zr + (this.p[2][3] || 0); 301 } 302 303 this.rotX = function(a) { 304 c = Math.cos(a); 305 s = Math.sin(a); 306 var p = this.p; 307 var p10 = p[1][0], p11 = p[1][1], p12 = p[1][2]; 308 var p20 = p[2][0], p21 = p[2][1], p22 = p[2][2]; 309 p[1][0] = p10*c - p20*s; 310 p[2][0] = p10*s + p20*c; 311 p[1][1] = p11*c - p21*s; 312 p[2][1] = p11*s + p21*c; 313 p[1][2] = p12*c - p22*s; 314 p[2][2] = p12*s + p22*c; 315 this.up(); 316 } 317 318 this.rotY = function(a) { 319 c = Math.cos(a); 320 s = Math.sin(a); 321 var p = this.p; 322 var p00 = p[0][0], p01 = p[0][1], p02 = p[0][2]; 323 var p20 = p[2][0], p21 = p[2][1], p22 = p[2][2]; 324 var p = this.p; 325 p[0][0] = p00*c - p20*s; 326 p[2][0] = p00*s + p20*c; 327 p[0][1] = p01*c - p21*s; 328 p[2][1] = p01*s + p21*c; 329 p[0][2] = p02*c - p22*s; 330 p[2][2] = p02*s + p22*c; 331 this.up(); 332 } 333 334 this.rotZ = function(a) { 335 c = Math.cos(a); 336 s = Math.sin(a); 337 var p = this.p; 338 var p00 = p[0][0], p01 = p[0][1], p02 = p[0][2]; 339 var p10 = p[1][0], p11 = p[1][1], p12 = p[1][2]; 340 p[0][0] = p00*c - p10*s; 341 p[1][0] = p00*s + p10*c; 342 p[0][1] = p01*c - p11*s; 343 p[1][1] = p01*s + p11*c; 344 p[0][2] = p02*c - p12*s; 345 p[1][2] = p02*s + p12*c; 346 this.up(); 347 } 348 349 /** Update receiver (change positions of stored copies so as stored shifts between receiver and its copies remain constant*/ 350 this.up = function() { 351 this.project(); 352 for (var i=0; i<this.copies.length; i++) { this.copies[i].setXYZ(this.xr+this.copiesShifts[i][0],this.yr+this.copiesShifts[i][1],this.zr+this.copiesShifts[i][2]); this.copies[i].up(); } 353 } 354 355 this.up(); 356 } 357 /** Creates new Point3d object, for parameters meaning see {@link Point3d} 358 * @returns {Point3d} new Point3d object*/ 359 Point3d.create = function(x,y,z,projection) { 360 return new Point3d(x,y,z,projection); 361 } 362 363 364 365 /** Line given by ax+bz+c=0 clipped in bounding rectangle 366 * @class represents line given by equation clipped in bounding rectangle 367 * @param {Raphael} raphael raphael instance 368 * @param {float} a a in ax+bz+c=0 369 * @param {float} b b in ax+bz+c=0 370 * @param {float} c c in ax+bz+c=0 371 * @param {Point} lt left top corner of bounding rectangle 372 * @param {Point} rb right bottom corner of bounding rectangle (lt.x<rb.x && tl.z<rb.z) 373 * @property {Raphael} raphael Raphael instance 374 * @property {float} a a in ax+bz+c=0 375 * @property {float} b b in ax+bz+c=0 376 * @property {float} c c in ax+bz+c=0 377 * @property {Point} lt left top corner of bounding rectangle 378 * @property {Point} rb right bottom corner of bounding rectangle (lt.x<rb.x && tl.z<rb.z) 379 * @property {Point} point1 1st point of intersection of line with bounding rectangle 380 * @property {Point} point2 2nd point of intersection of line with bounding rectangle 381 * @property {Line} line Line object (see {@link Line})*/ 382 LineBR = function(raphael,a,b,c,lt,rb) { 383 this.raphael = raphael; 384 this.a = a==undefined? 1. : a; 385 this.b = b==undefined? 1. : b; 386 this.c = c==undefined? 1. : c; 387 this.lt = lt || new Point2d(); 388 this.rb = rb || new Point2d(); 389 this.point1 = new Point2d(); 390 this.point2 = new Point2d(); 391 this.line = new Line(this.raphael,this.point1,this.point2); 392 393 /** Sets new a of ax+bz+c=0 394 *@param {float} a new a in ax+bz+c=0*/ 395 this.setA = function(a) { this.a = a; this.up(); } 396 397 /** Sets new a of ax+bz+c=0 398 *@param {float} a new a in ax+bz+c=0*/ 399 this.setB = function(b) { this.b = b; this.up(); } 400 401 /** Sets new a of ax+bz+c=0 402 *@param {float} a new a in ax+bz+c=0*/ 403 this.setC = function(c) { this.c = c; this.up(); } 404 405 /** Sets new a of ax+bz+c=0 406 *@param {float} a new a in ax+bz+c=0*/ 407 this.setABC = function(a,b,c) { this.a = a; this.b = b; this.c = c; this.up(); } 408 409 /** Hide the line*/ 410 this.hide = function() { this.point1.setXZ(-100,-100); this.point2.setXZ(-100,-100); } 411 412 /** Finds sections of given line with given bounding rectangle and sets to this.points*/ 413 this.findSections = function() { 414 var x1,z1,x2,z2; 415 var a = this.a; var b = this.b; var c = this.c; 416 var p1 = this.point1; var p2 = this.point2; 417 var lt = this.lt; var rb = this.rb; 418 var zmin = lt.z; var zmax = rb.z; 419 var xmin = lt.x; var xmax = rb.x; 420 if (a == 0.) { 421 if (-c/b > zmin && -c/b < zmax) { 422 p1.setXZ(xmin,-c/b); 423 p2.setXZ(xmax,-c/b); 424 } 425 else { this.hide(); } 426 return; 427 } 428 if (b == 0.) { 429 if (-c/a > xmin && -c/a < xmax) { 430 p1.setXZ(-c/a,zmin); 431 p2.setXZ(-c/a,zmax); 432 } 433 else { this.hide(); } 434 return; 435 } 436 x1 = xmin; 437 x2 = xmax; 438 z1 = -(a*x1+c)/b; 439 z2 = -(a*x2+c)/b; 440 if (z1<zmin && z2<zmin) { this.hide(); return; } 441 if (z1>zmax && z2>zmax) { this.hide(); return; } 442 if ((z1>zmin && z1<zmax) && (z2>zmin && z2<zmax)) { p1.setXZ(x1,z1); p2.setXZ(x2,z2); return; } 443 if ((z1<zmin && z2>zmax) || (z1>zmax && z2<zmin)) { 444 p1.setXZ(-(b*zmin+c)/a,zmin); 445 p2.setXZ(-(b*zmax+c)/a,zmax); 446 return; 447 } 448 if (z1 < zmax && z1 > zmin) { 449 p1.setXZ(x1,z1); 450 if (z2 < zmin) { p2.setXZ(-(b*zmin+c)/a,zmin); } 451 else { p2.setXZ(-(b*zmax+c)/a,zmax); } 452 } 453 else { 454 p2.setXZ(x2,z2); 455 if (z1 < zmin) { p1.setXZ(-(b*zmin+c)/a,zmin); } 456 else { p1.setXZ(-(b*zmax+c)/a,zmax); } 457 } 458 } 459 460 /** Update receiver*/ 461 this.up = function() { this.findSections(); this.line.up(); } 462 463 this.up(); 464 } 465 /** Creates new LineBR object, for parameters meaning see {@link LineBR} 466 * @returns {LineBR} new LineBR object*/ 467 LineBR.create = function(raphael,a,b,c,lt,rb) { 468 return new LineBR(raphael,a,b,c,lt,rb); 469 } 470 471 472 473 474 475 /** Line 476 * @class represents line connecting two points 477 * @param {Raphael} raphael raphael instance 478 * @param {Point} point1 1st Point2d 479 * @param {Point} point2 2nd Point2d 480 * @property {Raphael} raphael Raphael instance 481 * @property {Point} point1 first point of line 482 * @property {Point} point2 second point of line 483 * @property {[Lines]} copies array of copies of receiver 484 * @property {[[Points],[Points]]} copiesPoints array of points of copies of receiver 485 * @property {Raphael.el} obj pointer to actual raphael object*/ 486 Line = function(raphael,point1,point2) { 487 this.raphael = raphael; 488 this.point1 = point1; 489 this.point2 = point2; 490 this.copies = []; 491 this.copiesPoints = [[],[]]; 492 this.obj = null; 493 494 /** Sets svg path of receiver*/ 495 this.setPathList = function() { this.pathList = [["M",this.point1.x,this.point1.z],["L",this.point2.x,this.point2.z]]; } 496 // Create a raphael object and assign it to this.obj 497 this.makeObj = function() { this.obj = this.raphael.path(this.pathList); } 498 this.setPathList(); 499 this.makeObj(); 500 // Set this.pathList to this.obj raphael object 501 this.attrObjPath = function() { this.obj.attr({"path":this.pathList}); } 502 /** Update receiver (set this.pathList for given internal variables - x,z,angle... - as well as its copies)*/ 503 this.up = function() { 504 this.setPathList(); this.attrObjPath(); 505 for (var c=0; c<this.copies.length; c++) { this.copies[c].up(); } 506 } 507 /** Copy receiver 508 * @param {[[Points],[Points]]} points points of to be copied lines*/ 509 this.copy = function(points) { // points=[[point1,point2,point3],[point4,point5,point6]] wll make lines 14,25,36 510 for (var n=0; n<points[0].length; n++) { 511 this.copiesPoints[0].push(points[0][n]); 512 this.copiesPoints[1].push(points[1][n]); 513 this.copies.push(this.makeCopy(points[0][n],points[1][n])); 514 } 515 this.up(); 516 } 517 /** Returns copy of receiver 518 * @returns {Line} copy of receiver*/ 519 this.makeCopy = function(point1,point2) { 520 var ret = new Line(this.raphael,point1,point2); 521 ret.obj.remove(); 522 ret.obj = this.obj.clone(); 523 return ret; 524 } 525 } 526 /** Creates new Line object, for parameters meaning see {@link Line} 527 * @returns {Line} new Line object*/ 528 Line.create = function(raphael,point1,point2) { 529 return new Line(raphael,point1,point2); 530 } 531 532 533 534 /** Path (for easier modifying) 535 * @class represents svg path 536 * @param {Raphael} raphael raphael instance 537 * @param {Array} pathList path list for raphael path 538 * @property {Raphael} raphael raphael instance 539 * @property {Array} pathList svg array (list) of the object 540 * @property {Raphael.el} obj actual raphael object*/ 541 Path = function(raphael,pathList) { 542 this.pathList = pathList==undefined? [] : pathList; 543 this.raphael = raphael; 544 this.obj = this.raphael.path(this.pathList); 545 // methods 546 // Set this.pathList to this.obj raphael object 547 this.attrObjPath = function() { this.obj.attr({"path":this.pathList}); } 548 549 /** Sets one specific value in this.pathList (this.pathList[i][j] = val) 550 * @param {int} i first index 551 * @param {int} j second index 552 * @param {float|string} val value to be set*/ 553 this.setItem = function(i,j,val) { this.pathList[i][j] = val; this.attrObjPath(); } 554 555 /** Increment one specific value in this.pathList (this.pathList[i][j] = val) 556 * @param {int} i first index 557 * @param {int} j second index 558 * @param {float} val value of incerementation*/ 559 this.iaddItem = function(i,j,val) { this.pathList[i][j] += val; this.attrObjPath(); } 560 561 /** Sets new svg line path to receiver 562 * @param {Array} newPathList newpath list*/ 563 this.setNewPath = function(newPathList) { this.pathList = newPathList; this.attrObjPath(); } 564 } 565 /** Creates new Path object, for parameters meaning see {@link Path} 566 * @returns {Path} new Path object*/ 567 Path.create = function(pathList) { 568 return new Path(pathList); 569 } 570 571 572 573 /** Circle (for easier modifying) 574 * @class represents circle 575 * @param {Raphael} raphael raphael instance 576 * @param {float} [cx=0.] x coordinate of circle center 577 * @param {float} [cz=0.] z coordinate of circle center 578 * @param {float} [r=10.] circle radius 579 * @property {Raphael} raphael raphael instance 580 * @property {float} x x coordinate of circle center 581 * @property {float} z z coordinate of circle center 582 * @property {float} r radius of the circle 583 * @property {Raphael.circle} obj actual raphael object 584 * @property {[Circles]} copies array of copies of receiver 585 * @property {[[float,float]]} copiesShifts array of shifts of copies of receiver*/ 586 Circle = function(raphael,x,z,r) { 587 this.raphael = raphael; 588 this.x = x==undefined? 0. : x; 589 this.z = z==undefined? 0. : z; 590 this.r = r==undefined? 0. : r; 591 this.copies = []; 592 this.copiesShifts = []; 593 this.obj = this.raphael.circle(this.x,this.z,this.r); 594 595 /** Sets radius of receiver 596 * @param {float} r new radius*/ 597 this.setR = function(r) { this.r = r; this.obj.attr({"r":r}); this.up(); } 598 599 /** Sets x coordinate of receiver 600 * @param {float} x new x coordinate*/ 601 this.setX = function(x) { this.x = x; this.obj.attr({"cx":x}); this.up(); } 602 603 /** Sets z coordinate of receiver 604 * @param {float} z new z coordinate*/ 605 this.setZ = function(z) { this.z = z; this.obj.attr({"cy":z}); this.up(); } 606 607 /** Sets new coordinates of receiver 608 * @param {float} x new x coordinate 609 * @param {float} z new z coordinate*/ 610 this.setXZ = function(x,z) { this.x = x; this.z = z; this.obj.attr({"cx":x,"cy":z}); } 611 612 /** Translate along x axis of receiver 613 * @param {float} dx x distance of translation*/ 614 this.translateX = function(dx) { this.x += dx; this.obj.attr({"cx":this.x}); } 615 616 /** Translate along z axis of receiver 617 * @param {float} dz z distance of translation*/ 618 this.translateZ = function(dz) { this.z += dz; this.obj.attr({"cy":this.z}); } 619 620 /** Translate receiver 621 * @param {float} dx x distance of translation 622 * @param {float} dz z distance of translation*/ 623 this.translate = function(dx,dz) { this.x += dx; this.z += dz; this.obj.attr({"cx":this.x,"cy":this.z}); } 624 625 /** Copy of receiver 626 * @param {[[float,float]]} shifts shifts of copies*/ 627 this.copy = function(shifts) { for (var i=0; i<shifts.length; i++) { this.copiesShifts.push(shifts[i]); this.copies.push(this.makeCopy()); this.up()} } 628 this.makeCopy = function() { 629 var ret = new Circle(this.raphael,this.x,this.z,this.r) 630 ret.obj.remove(); 631 ret.obj = this.obj.clone(); 632 return ret; 633 } 634 635 /** Update*/ 636 this.up = function() { 637 for (var c=0; c<this.copies.length; c++) { 638 this.copies[c].setXZ(this.x+this.copiesShifts[c][0],this.z+this.copiesShifts[c][1]); 639 this.copies[c].setR(this.r); 640 } 641 } 642 } 643 /** Creates new Circle object, for parameters meaning see {@link Circle} 644 * @returns {Circle} new Circle object*/ 645 Circle.create = function(raphael,x,z,r) { 646 return new Circle(raphael,x,z,r); 647 } 648 649 650 651 652 /** Ellipse 653 * @class represents ellipse 654 * @param {Raphael} raphael raphael instance 655 * @param {float} [cx=0.] x coordinate of circle center 656 * @param {float} [cz=0.] z coordinate of circle center 657 * @param {float} [a=10.] x semiaxis 658 * @param {float} [b=10.] z semiaxis 659 * @param {float} [angle=0.] rotation 660 * @param {int} [nSeg=0.] number of segments 661 * @property {Raphael} raphael raphael instance 662 * @property {float} cx x coordinate of circle center 663 * @property {float} cz z coordinate of circle center 664 * @property {float} a x semiaxis 665 * @property {float} b z semiaxis 666 * @property {float} angle rotation 667 * @property {int} nSeg number of segments*/ 668 Ellipse = function(raphael,cx,cz,a,b,angle,nSeg) { 669 this.raphael = raphael; 670 this.cx = cx==undefined? 0. : cx; 671 this.cz = cz==undefined? 0. : cz; 672 this.a = a==undefined? 10. : a; 673 this.b = b==undefined? 10. : b; 674 this.angle = angle==undefined? 0. : angle; 675 this.nSeg = nSeg==undefined? 32 : nSeg; 676 this.pathList = []; 677 this.obj = this.raphael.path([]); 678 679 /** Sets a (x semiaxis) of receiver 680 * @param {float} r new radius*/ 681 this.setA = function(a) { this.a = a; this.up(); } 682 683 /** Sets b (z semiaxis) of receiver 684 * @param {float} r new radius*/ 685 this.setB = function(b) { this.b = b; this.up(); } 686 687 /** Sets a (x semiaxis) and b (z semiaxis) of receiver 688 * @param {float} a new a (x semiaxis) 689 * @param {float} b new b (x semiaxis)*/ 690 this.setAB = function(a,b) { this.a = a; this.b = b; this.up(); } 691 692 /** Sets x coordinate of center of receiver 693 * @param {float} cx new x coordinate*/ 694 this.setX = function(cx) { this.cx = cx; this.up(); } 695 696 /** Sets z coordinate of center of receiver 697 * @param {float} cz new z coordinate*/ 698 this.setZ = function(cz) { this.cz = cz; this.up(); } 699 700 /** Sets new coordinates of receiver 701 * @param {float} cx new x coordinate 702 * @param {float} cz new z coordinate*/ 703 this.setXZ = function(cx,cz) { this.cx = cx; this.cz = cz; this.up(); } 704 705 /** Sets new coordinates of receiver and new semiaxes 706 * @param {float} cx new x coordinate 707 * @param {float} cz new z coordinate 708 * @param {float} a new a (x semiaxis) 709 * @param {float} b new b (x semiaxis) 710 * @param {float} angle new angle*/ 711 this.setAll = function(cx,cz,a,b,angle) { this.cx = cx; this.cz = cz; this.a = a; this.b = b; this.angle = angle; this.up(); } 712 713 /** Sets rotation of receiver 714 * @param {float} cz new z coordinate*/ 715 this.setAngle = function(angle) { this.angle = angle; this.up(); } 716 717 /** Translate along x axis of receiver 718 * @param {float} dx x distance of translation*/ 719 this.translateX = function(dx) { this.cx += dx; this.up(); } 720 721 /** Translate along z axis of receiver 722 * @param {float} dz z distance of translation*/ 723 this.translateZ = function(dz) { this.cz += dz; this.up(); } 724 725 /** Translate receiver 726 * @param {float} dx x distance of translation 727 * @param {float} dz z distance of translation*/ 728 this.translate = function(dx,dz) { this.cx += dx; this.cz += dz; this.up(); } 729 730 /** Sets svg path of receiver*/ 731 this.setPathList = function() { 732 this.pathList = []; 733 var c = Math.cos(this.angle); 734 var s = Math.sin(this.angle); 735 var t,xl,zl; 736 for (var i=0; i<this.nSeg; i++) { 737 t = i*2*Math.PI/this.nSeg; 738 xl = this.a*Math.cos(t); 739 zl = this.b*Math.sin(t); 740 if (i==0) { this.pathList[0] = ["M",this.cx+c*xl+s*zl,this.cz-s*xl+c*zl]; } 741 else { this.pathList[i] = ["L",this.cx+c*xl+s*zl,this.cz-s*xl+c*zl]; } 742 } 743 this.pathList.push(["Z"]); 744 this.obj.attr({"path":this.pathList}); 745 } 746 747 /** Update*/ 748 this.up = function() { 749 this.setPathList(); 750 } 751 752 this.up(); 753 } 754 /** Creates new Ellipse object, for parameters meaning see {@link Ellipse} 755 * @returns {Circle} new Ellipse object*/ 756 Ellipse.create = function(raphael,cx,cz,a,b,angle,nSeg) { 757 return new Ellipse(raphael,cx,cz,a,b,angle,nSeg); 758 } 759 760 761 762 763 /** Slider 764 * @class abstract class epresenting generic slider 765 * @param {Raphael} raphael raphael instance 766 * @param {Object} params parameters,see below 767 * @param {float} [params.x=100.] x coordinate of left/upper end 768 * @param {float} [params.z=100.] z coordinate of left/upper end 769 * @param {float} [params.length=100.] length of slider [pixels] 770 * @param {float} [params.rcirc=5.] radius of slider's circle 771 * @param {float} [params.val1=0.] value when the slider is at the very beginning 772 * @param {float} [params.val2=1.] value when the slider is at the very end 773 * @param {float} [params.initVal=(val1+val2)/2] initial value 774 * @param {float} [params.gap=3.] gap between end of the slider's line and the slider's circle when the circle is at extreme position 775 * @property {Raphael} raphael raphael instance 776 * @property {float} x x coordinate of left/upper end 777 * @property {float} z z coordinate of left/upper end 778 * @property {float} len len of slider [pixels] 779 * @property {float} rcirc radius of slider's circle 780 * @property {float} val1 value when the slider is at the very beginning 781 * @property {float} val2 value when the slider is at the very end 782 * @property {float} initVal initial value 783 * @property {float} gap gap between end of the slider's line and the slider's circle when the circle is at extreme position 784 * @property {float} lenVals length span of getable values 785 * @property {Raphael.el} line line 786 * @property {Circle} circ Circle*/ 787 Slider = function(raphael,params) { 788 this.constructorSlider = function(raphael,params) { 789 this.raphael = raphael; 790 this.x = params.x==undefined? 100. : params.x; 791 this.z = params.z==undefined? 100. : params.z; 792 this.len = params.length==undefined? 100. : params.length; 793 this.rcirc = params.rcirc==undefined? 5. : params.rcirc; 794 this.gap = params.gap==undefined? 3. : params.gap; 795 this.start = this.gap+this.rcirc; 796 this.stop = this.len - this.start; 797 this.val1 = params.val1==undefined? 0. : params.val1; 798 this.val2 = params.val2==undefined? 1. : params.val2; 799 this.initVal = params.initVal==undefined? .5*(this.val1+this.val2) : params.initVal; 800 this.lenVals = this.len - 2*this.start; 801 this.line = this.raphael.rect(this.x,this.z-2,this.len,4).attr({"fill":"#bbb"}); 802 this.circ = new Circle(this.raphael,this.x,this.z,this.rcirc); 803 this.circ.obj.attr({"cursor":"move","fill":"#f00"}) 804 this.circ.obj.slider = this; 805 this.circ.obj.circ = this.circ; 806 } 807 } 808 809 810 /** Horizontal slider 811 * @class represents horizontal slider 812 * @param {Raphael} raphael raphael instance 813 * @param {Object} params parameters, see below 814 * @param {float} [params.x=100.] x coordinate of left/upper end 815 * @param {float} [params.z=100.] z coordinate of left/upper end 816 * @param {float} [params.length=100.] length of slider [pixels] 817 * @param {float} [params.rcirc=5.] radius of slider's circle 818 * @param {float} [params.val1=0.] value when the slider is at the very beginning 819 * @param {float} [params.val2=1.] value when the slider is at the very end 820 * @param {float} [params.initVal=(val1+val2)/2] initial value 821 * @param {float} [params.gap=3.] gap between end of the slider's line and the slider's circle when the circle is at extreme position 822 * @property {Raphael} raphael raphael instance 823 * @property {float} x x coordinate of left/upper end 824 * @property {float} z z coordinate of left/upper end 825 * @property {float} len len of slider [pixels] 826 * @property {float} rcirc radius of slider's circle 827 * @property {float} val1 value when the slider is at the very beginning 828 * @property {float} val2 value when the slider is at the very end 829 * @property {float} initVal initial value 830 * @property {float} gap gap between end of the slider's line and the slider's circle when the circle is at extreme position 831 * @property {float} lenVals length span of getable values 832 * @property {Raphael.el} line line 833 * @property {Circle} circ circle*/ 834 HorizontalSlider = function(raphael,params) { 835 this.inheritFrom = Slider; this.inheritFrom(); 836 837 /** Constructor, see {@link HorizontalSlider} for parameters description*/ 838 this.constructorHorizontalSlider = function(raphael,params) { 839 this.constructorSlider(raphael,params); 840 var initPos; 841 if (this.lenVals<0) { 842 initPos = this.len*.5; 843 this.lenVals = 1.; 844 } 845 else { 846 initPos = this.start+this.lenVals/(this.val2-this.val1)*(this.initVal-this.val1); 847 if (initPos < this.start) { initPos = this.start; } 848 if (initPos > this.stop) { initPos = this.stop; } 849 } 850 this.circ.setXZ(this.x+initPos,this.z); 851 this.circ.obj.dragReset = function() { this.slider.pos = this.circ.x; }; 852 this.circ.obj.dragReset(); 853 this.circ.obj.dragUpdate = function(dx,dz) { 854 this.slider.pos += dx; 855 if (this.slider.pos >= this.slider.x+this.slider.start && this.slider.pos <= this.slider.x+this.slider.len-this.slider.start) { 856 this.circ.setX(this.slider.pos); 857 this.slider.onmove(); 858 } 859 } 860 /**@ignore*/ 861 this.circ.obj.drag(dragMove,dragInit,dragReset); 862 } 863 864 /** Get current value from receiver 865 * @returns {float} current value*/ 866 this.getVal = function() { 867 var dx = this.circ.x-this.x-this.start; 868 return this.val1+dx*(this.val2-this.val1)/this.lenVals; 869 } 870 871 /** Set value to receiver 872 * @param {float} new value*/ 873 this.setVal = function(newVal) { 874 var newPos; 875 if (this.lenVals<0) { 876 newPos = this.len*.5; 877 this.lenVals = 1.; 878 } 879 else { 880 newPos = this.start+this.lenVals/(this.val2-this.val1)*(newVal-this.val1); 881 if (newPos < this.start) { newPos = this.start; } 882 if (newPos > this.stop) { newPos = this.stop; } 883 } 884 this.circ.setXZ(this.x+newPos,this.z); 885 this.circ.obj.dragReset(); 886 } 887 888 /** What to do when moving. Initially empty function, overwrite it by desired actions*/ 889 this.onmove = function() {} 890 891 this.constructorHorizontalSlider(raphael,params); 892 } 893 /** Creates new HorizontalSlider object, for parameters meaning see {@link HorizontalSlider} 894 * @returns {HorizontalSlider} new HorizontalSlider object*/ 895 HorizontalSlider.create = function(raphael,params) { 896 return new HorizontalSlider(raphael,params); 897 } 898 899 900 901 /** Button 902 * @class represents button 903 * @param {Raphael} raphael raphael instance 904 * @param {Object} params parameters, see below 905 * @param {string} [params.str="str"] displayed string of button 906 * @param {float} [params.x=100.] x coordinate of left upper end 907 * @param {float} [params.z=100.] z coordinate of left upper end 908 * @param {float} [params.width=100.] length of slider [pixels] 909 * @param {float} [params.height=30.] length of slider [pixels] 910 * @param {float} [params.fontSize=20.] font size of button str 911 * @param {float} [params.rCorner=4.] radius of button corners camber 912 * @param {color} [params.bgColor="#bbb"] background color of button 913 * @param {color} [params.bgColorWhenClicked="#aaa"] background color of button when clicked 914 * @property {Raphael} raphael raphael instance 915 * @property {float} x x coordinate of left upper end 916 * @property {float} z z coordinate of left upper end 917 * @property {float} width length of slider [pixels] 918 * @property {float} height length of slider [pixels] 919 * @property {float} fontSize font size of button text 920 * @property {color} bgColor background color of button 921 * @property {color} bgColorWhenClicked background color of button when clicked 922 * @property {Raphael.rect} rect rectangle of receiver 923 * @property {Raphael.text} text object of receiver*/ 924 Button = function(raphael,params) { 925 this.constructorButton = function(raphael,params) { 926 this.raphael = raphael; 927 var str = params.str==undefined? 'str' : params.str; 928 this.x = params.x==undefined? 100. : params.x; 929 this.z = params.z==undefined? 100. : params.z; 930 this.width = params.width==undefined? 100. : params.width; 931 this.height = params.height==undefined? 30. : params.height; 932 var fontSize = params.fontSize==undefined? 20. : params.fontSize; 933 this.bgColor = params.bgColor==undefined? "#bbb" : params.bgColor; 934 this.bgColorWhenClicked = params.bgColorWhenClicked==undefined? "#aaa" : params.bgColorWhenClicked; 935 var rCorner = params.rCorner==undefined? 4. : params.rCorner; 936 this.rect = this.raphael.rect(this.x,this.z,this.width,this.height,rCorner).attr({"fill":this.bgColor,"cursor":"pointer"}) 937 this.rect.button = this; 938 this.text = this.raphael.text(this.x+.5*this.width,this.z+.5*this.height,str).attr({"font-size":fontSize,"cursor":"pointer"}) 939 this.text.button = this; 940 941 /** What to do when clicked. Initially empty function, overwrite it by desired actions*/ 942 this.onclick = function() {} 943 944 this.doThisWhenClicked = function() { 945 this.text.attr({"x":this.x+.5*this.width+2}) 946 this.rect.attr({"fill":this.bgColorWhenClicked}) 947 this.onclick(); 948 } 949 this.doThisWhenUnclicked = function() { 950 this.text.attr({"x":this.x+.5*this.width}) 951 this.rect.attr({"fill":this.bgColor}) 952 } 953 this.rect.mousedown(function(event) {this.button.doThisWhenClicked();}) 954 this.rect.mouseup(function(event) {this.button.doThisWhenUnclicked();}) 955 this.text.mousedown(function(event) {this.button.doThisWhenClicked();}) 956 this.text.mouseup(function(event) {this.button.doThisWhenUnclicked();}) 957 this.rect.mouseout(function(event) {this.button.doThisWhenUnclicked();}) 958 this.text.mouseout(function(event) {this.button.doThisWhenUnclicked();}) 959 } 960 961 this.constructorButton(raphael,params); 962 } 963 /** Creates new Button object, for parameters meaning see {@link Button} 964 * @returns {Button} new Button object*/ 965 Button.create = function(raphael,params) { 966 return new Button(raphael,params); 967 } 968 969 970 971 972 /** Text in rectangular frame 973 * @class represents text in rectangular frame 974 * @param {Raphael} raphael rapheal instance 975 * @param {Object} params parameters, see below 976 * @param {float} [params.x=100.] x coordinate of left lower corner [pixel] 977 * @param {float} [params.z=100.] z coordinate of left lower corner [pixel] 978 * @param {float} [params.width=100.] width [pixel] 979 * @param {float} [params.height=100.] height [pixel] 980 * @param {string} [params.str="string"] string to be shown 981 * @param {float} [params.fontSize=20.] font size 982 * @property {float} x x coordinate of top left corner 983 * @property {float} z z coordinate of top left corner 984 * @property {float} width width of rectangle 985 * @property {float} height height of rectangle 986 * @property {string} str text to display 987 * @property {float} fontSize font size 988 * @property {Raphael.text} text raphael text object 989 * @property {Raphael.rect} rect raphael rect object*/ 990 TextRect = function(raphael,params) { 991 992 /** Constructor, see {@link TextRect} for parameters description*/ 993 this.constructorTextRect = function(raphael,params) { 994 this.x = params.x==undefined? 100. : params.x; 995 this.z = params.z==undefined? 100. : params.z; 996 this.width = params.width==undefined? 100. : params.width; 997 this.height = params.height==undefined? 100. : params.height; 998 this.str = params.str==undefined? "string" : params.str; 999 this.fontSize = params.fontSize==undefined? 20 : params.fontSize; 1000 this.rect = raphael.rect(this.x,this.z-this.height,this.width,this.height); 1001 this.text = raphael.text(this.x+.5*this.width,this.z-.5*this.height,this.str).attr({"font-size":this.fontSize}); 1002 } 1003 1004 /** Update receiver (set this.pathList for given internal variables)*/ 1005 this.up = function() { 1006 this.rect.attr({"x":this.x,"y":(this.z-this.height)}); 1007 this.text.attr({"x":(this.x+.5*this.width),"y":(this.z-.5*this.height),"text":this.str,"font-size":this.fontSize}); 1008 } 1009 1010 /** Sets new x position of receiver (this.x = x) 1011 * @param {float} x new x coordinate [pixel]*/ 1012 this.setX = function(x) { this.x = x; this.up(); } 1013 1014 /** Sets new z position of receiver (this.z = z) 1015 * @param {float} z new z coordinate [pixel]*/ 1016 this.setZ = function(z) { this.z = z; this.up(); } 1017 1018 /** Sets new x and z position of receiver (this.x = x; this.z = z) 1019 * @param {float} x new x coordinate [pixel] 1020 * @param {float} z new z coordinate [pixel]*/ 1021 this.setXZ = function(x,z) { this.x = x; this.z = z; this.up(); } 1022 1023 /** Sets new text of receiver 1024 * @param {string} str new string*/ 1025 this.setStr = function(str) { this.str = str; this.up(); } 1026 1027 this.constructorTextRect(raphael,params); 1028 } 1029 /** Creates new TextRect object, for parameters meaning see {@link TextRect} 1030 * @returns {TextRect} new TextRect object*/ 1031 TextRect.create = function(raphael,params) { 1032 return new TextRect(raphael,params); 1033 } 1034 1035 1036 1037 1038 1039