| [ Index ] |
PHP Cross Reference of Moodle 310 |
[Summary view] [Print] [Text view]
1 // This file is part of Moodle - http://moodle.org/ 2 // 3 // Moodle is free software: you can redistribute it and/or modify 4 // it under the terms of the GNU General Public License as published by 5 // the Free Software Foundation, either version 3 of the License, or 6 // (at your option) any later version. 7 // 8 // Moodle is distributed in the hope that it will be useful, 9 // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 // GNU General Public License for more details. 12 // 13 // You should have received a copy of the GNU General Public License 14 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 15 16 /* eslint max-depth: ["error", 8] */ 17 18 /** 19 * Library of classes for handling simple shapes. 20 * 21 * These classes can represent shapes, let you alter them, can go to and from a string 22 * representation, and can give you an SVG representation. 23 * 24 * @module qtype_ddmarker/shapes 25 * @copyright 2018 The Open University 26 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 27 */ 28 29 define(function() { 30 31 "use strict"; 32 33 /** 34 * A point, with x and y coordinates. 35 * 36 * @param {int} x centre X. 37 * @param {int} y centre Y. 38 * @constructor 39 */ 40 function Point(x, y) { 41 this.x = x; 42 this.y = y; 43 } 44 45 /** 46 * Standard toString method. 47 * @returns {string} "x;y"; 48 */ 49 Point.prototype.toString = function() { 50 return this.x + ',' + this.y; 51 }; 52 53 /** 54 * Move a point 55 * @param {int} dx x offset 56 * @param {int} dy y offset 57 */ 58 Point.prototype.move = function(dx, dy) { 59 this.x += dx; 60 this.y += dy; 61 }; 62 63 /** 64 * Return a new point that is a certain position relative to this one. 65 * 66 * @param {(int|Point)} offsetX if a point, offset by this points coordinates, else and int x offset. 67 * @param {int} [offsetY] used if offsetX is an int, the corresponding y offset. 68 * @return {Point} the new point. 69 */ 70 Point.prototype.offset = function(offsetX, offsetY) { 71 if (offsetX instanceof Point) { 72 offsetY = offsetX.y; 73 offsetX = offsetX.x; 74 } 75 return new Point(this.x + offsetX, this.y + offsetY); 76 }; 77 78 /** 79 * Make a point from the string representation. 80 * 81 * @param {String} coordinates "x,y". 82 * @return {Point} the point. Throws an exception if input is not valid. 83 */ 84 Point.parse = function(coordinates) { 85 var bits = coordinates.split(','); 86 if (bits.length !== 2) { 87 throw new Error(coordinates + ' is not a valid point'); 88 } 89 return new Point(Math.round(bits[0]), Math.round(bits[1])); 90 }; 91 92 93 /** 94 * Shape constructor. Abstract class to represent the different types of drop zone shapes. 95 * 96 * @param {String} [label] name of this area. 97 * @param {int} [x] centre X. 98 * @param {int} [y] centre Y. 99 * @constructor 100 */ 101 function Shape(label, x, y) { 102 this.label = label; 103 this.centre = new Point(x || 0, y || 0); 104 } 105 106 /** 107 * Get the type of shape. 108 * 109 * @return {String} 'circle', 'rectangle' or 'polygon'; 110 */ 111 Shape.prototype.getType = function() { 112 throw new Error('Not implemented.'); 113 }; 114 115 /** 116 * Get the string representation of this shape. 117 * 118 * @return {String} coordinates as they need to be typed into the form. 119 */ 120 Shape.prototype.getCoordinates = function() { 121 throw new Error('Not implemented.'); 122 }; 123 124 /** 125 * Update the shape from the string representation. 126 * 127 * @param {String} coordinates in the form returned by getCoordinates. 128 * @param {number} ratio Ratio to scale. 129 * @return {boolean} true if the string could be parsed and the shape updated, else false. 130 */ 131 Shape.prototype.parse = function(coordinates, ratio) { 132 void (coordinates, ratio); 133 throw new Error('Not implemented.'); 134 }; 135 136 /** 137 * Move the entire shape by this offset. 138 * 139 * @param {int} dx x offset. 140 * @param {int} dy y offset. 141 * @param {int} maxX ensure that after editing, the shape lies between 0 and maxX on the x-axis. 142 * @param {int} maxY ensure that after editing, the shape lies between 0 and maxX on the y-axis. 143 */ 144 Shape.prototype.move = function(dx, dy, maxX, maxY) { 145 void (maxY); 146 }; 147 148 /** 149 * Move one of the edit handles by this offset. 150 * 151 * @param {int} handleIndex which handle was moved. 152 * @param {int} dx x offset. 153 * @param {int} dy y offset. 154 * @param {int} maxX ensure that after editing, the shape lies between 0 and maxX on the x-axis. 155 * @param {int} maxY ensure that after editing, the shape lies between 0 and maxX on the y-axis. 156 */ 157 Shape.prototype.edit = function(handleIndex, dx, dy, maxX, maxY) { 158 void (maxY); 159 }; 160 161 /** 162 * Update the properties of this shape after a sequence of edits. 163 * 164 * For example make sure the circle radius is positive, of the polygon centre is centred. 165 */ 166 Shape.prototype.normalizeShape = function() { 167 void (1); // To make CiBoT happy. 168 }; 169 170 /** 171 * Get the string representation of this shape. 172 * 173 * @param {SVGElement} svg the SVG graphic to add this shape to. 174 * @return {SVGElement} SVG representation of this shape. 175 */ 176 Shape.prototype.makeSvg = function(svg) { 177 void (svg); 178 throw new Error('Not implemented.'); 179 }; 180 181 /** 182 * Update the SVG representation of this shape. 183 * 184 * @param {SVGElement} svgEl the SVG representation of this shape. 185 */ 186 Shape.prototype.updateSvg = function(svgEl) { 187 void (svgEl); 188 }; 189 190 /** 191 * Make a circle similar to this shape. 192 * 193 * @return {Circle} a circle that is about the same size and position as this shape. 194 */ 195 Shape.prototype.makeSimilarCircle = function() { 196 throw new Error('Not implemented.'); 197 }; 198 199 /** 200 * Make a rectangle similar to this shape. 201 * 202 * @return {Rectangle} a rectangle that is about the same size and position as this shape. 203 */ 204 Shape.prototype.makeSimilarRectangle = function() { 205 throw new Error('Not implemented.'); 206 }; 207 208 /** 209 * Make a polygon similar to this shape. 210 * 211 * @return {Polygon} a polygon that is about the same size and position as this shape. 212 */ 213 Shape.prototype.makeSimilarPolygon = function() { 214 throw new Error('Not implemented.'); 215 }; 216 217 /** 218 * Get the handles that should be offered to edit this shape, or null if not appropriate. 219 * 220 * @return {Object[]} with properties moveHandle {Point} and editHandles {Point[]} 221 */ 222 Shape.prototype.getHandlePositions = function() { 223 return null; 224 }; 225 226 227 /** 228 * A shape that is a circle. 229 * 230 * @param {String} label name of this area. 231 * @param {int} [x] centre X. 232 * @param {int} [y] centre Y. 233 * @param {int} [radius] radius. 234 * @constructor 235 */ 236 function Circle(label, x, y, radius) { 237 x = x || 15; 238 y = y || 15; 239 Shape.call(this, label, x, y); 240 this.radius = radius || 15; 241 } 242 Circle.prototype = new Shape(); 243 244 Circle.prototype.getType = function() { 245 return 'circle'; 246 }; 247 248 Circle.prototype.getCoordinates = function() { 249 return this.centre + ';' + Math.abs(this.radius); 250 }; 251 252 Circle.prototype.makeSvg = function(svg) { 253 var svgEl = createSvgShapeGroup(svg, 'circle'); 254 this.updateSvg(svgEl); 255 return svgEl; 256 }; 257 258 Circle.prototype.updateSvg = function(svgEl) { 259 svgEl.childNodes[0].setAttribute('cx', this.centre.x); 260 svgEl.childNodes[0].setAttribute('cy', this.centre.y); 261 svgEl.childNodes[0].setAttribute('r', Math.abs(this.radius)); 262 svgEl.childNodes[1].setAttribute('x', this.centre.x); 263 svgEl.childNodes[1].setAttribute('y', this.centre.y + 15); 264 svgEl.childNodes[1].textContent = this.label; 265 }; 266 267 Circle.prototype.parse = function(coordinates, ratio) { 268 if (!coordinates.match(/^\d+(\.\d+)?,\d+(\.\d+)?;\d+(\.\d+)?$/)) { 269 return false; 270 } 271 272 var bits = coordinates.split(';'); 273 this.centre = Point.parse(bits[0]); 274 this.centre.x = this.centre.x * parseFloat(ratio); 275 this.centre.y = this.centre.y * parseFloat(ratio); 276 this.radius = Math.round(bits[1]) * parseFloat(ratio); 277 return true; 278 }; 279 280 Circle.prototype.move = function(dx, dy, maxX, maxY) { 281 this.centre.move(dx, dy); 282 if (this.centre.x < this.radius) { 283 this.centre.x = this.radius; 284 } 285 if (this.centre.x > maxX - this.radius) { 286 this.centre.x = maxX - this.radius; 287 } 288 if (this.centre.y < this.radius) { 289 this.centre.y = this.radius; 290 } 291 if (this.centre.y > maxY - this.radius) { 292 this.centre.y = maxY - this.radius; 293 } 294 }; 295 296 Circle.prototype.edit = function(handleIndex, dx, dy, maxX, maxY) { 297 this.radius += dx; 298 var limit = Math.min(this.centre.x, this.centre.y, maxX - this.centre.x, maxY - this.centre.y); 299 if (this.radius > limit) { 300 this.radius = limit; 301 } 302 if (this.radius < -limit) { 303 this.radius = -limit; 304 } 305 }; 306 307 /** 308 * Update the properties of this shape after a sequence of edits. 309 * 310 * For example make sure the circle radius is positive, of the polygon centre is centred. 311 */ 312 Circle.prototype.normalizeShape = function() { 313 this.radius = Math.abs(this.radius); 314 }; 315 316 Circle.prototype.makeSimilarRectangle = function() { 317 return new Rectangle(this.label, 318 this.centre.x - this.radius, this.centre.y - this.radius, 319 this.radius * 2, this.radius * 2); 320 }; 321 322 Circle.prototype.makeSimilarPolygon = function() { 323 // We make a similar square, so if you go to and from Rectangle afterwards, it is loss-less. 324 return new Polygon(this.label, [ 325 this.centre.offset(-this.radius, -this.radius), this.centre.offset(-this.radius, this.radius), 326 this.centre.offset(this.radius, this.radius), this.centre.offset(this.radius, -this.radius)]); 327 }; 328 329 Circle.prototype.getHandlePositions = function() { 330 return { 331 moveHandle: this.centre, 332 editHandles: [this.centre.offset(this.radius, 0)] 333 }; 334 }; 335 336 337 /** 338 * A shape that is a rectangle. 339 * 340 * @param {String} label name of this area. 341 * @param {int} [x] top left X. 342 * @param {int} [y] top left Y. 343 * @param {int} [width] width. 344 * @param {int} [height] height. 345 * @constructor 346 */ 347 function Rectangle(label, x, y, width, height) { 348 Shape.call(this, label, x, y); 349 this.width = width || 30; 350 this.height = height || 30; 351 } 352 Rectangle.prototype = new Shape(); 353 354 Rectangle.prototype.getType = function() { 355 return 'rectangle'; 356 }; 357 358 Rectangle.prototype.getCoordinates = function() { 359 return this.centre + ';' + this.width + ',' + this.height; 360 }; 361 362 Rectangle.prototype.makeSvg = function(svg) { 363 var svgEl = createSvgShapeGroup(svg, 'rect'); 364 this.updateSvg(svgEl); 365 return svgEl; 366 }; 367 368 Rectangle.prototype.updateSvg = function(svgEl) { 369 if (this.width >= 0) { 370 svgEl.childNodes[0].setAttribute('x', this.centre.x); 371 svgEl.childNodes[0].setAttribute('width', this.width); 372 } else { 373 svgEl.childNodes[0].setAttribute('x', this.centre.x + this.width); 374 svgEl.childNodes[0].setAttribute('width', -this.width); 375 } 376 if (this.height >= 0) { 377 svgEl.childNodes[0].setAttribute('y', this.centre.y); 378 svgEl.childNodes[0].setAttribute('height', this.height); 379 } else { 380 svgEl.childNodes[0].setAttribute('y', this.centre.y + this.height); 381 svgEl.childNodes[0].setAttribute('height', -this.height); 382 } 383 384 svgEl.childNodes[1].setAttribute('x', this.centre.x + this.width / 2); 385 svgEl.childNodes[1].setAttribute('y', this.centre.y + this.height / 2 + 15); 386 svgEl.childNodes[1].textContent = this.label; 387 }; 388 389 Rectangle.prototype.parse = function(coordinates, ratio) { 390 if (!coordinates.match(/^\d+(\.\d+)?,\d+(\.\d+)?;\d+(\.\d+)?,\d+(\.\d+)?$/)) { 391 return false; 392 } 393 394 var bits = coordinates.split(';'); 395 this.centre = Point.parse(bits[0]); 396 this.centre.x = this.centre.x * parseFloat(ratio); 397 this.centre.y = this.centre.y * parseFloat(ratio); 398 var size = Point.parse(bits[1]); 399 this.width = size.x * parseFloat(ratio); 400 this.height = size.y * parseFloat(ratio); 401 return true; 402 }; 403 404 Rectangle.prototype.move = function(dx, dy, maxX, maxY) { 405 this.centre.move(dx, dy); 406 if (this.centre.x < 0) { 407 this.centre.x = 0; 408 } 409 if (this.centre.x > maxX - this.width) { 410 this.centre.x = maxX - this.width; 411 } 412 if (this.centre.y < 0) { 413 this.centre.y = 0; 414 } 415 if (this.centre.y > maxY - this.height) { 416 this.centre.y = maxY - this.height; 417 } 418 }; 419 420 Rectangle.prototype.edit = function(handleIndex, dx, dy, maxX, maxY) { 421 this.width += dx; 422 this.height += dy; 423 if (this.width < -this.centre.x) { 424 this.width = -this.centre.x; 425 } 426 if (this.width > maxX - this.centre.x) { 427 this.width = maxX - this.centre.x; 428 } 429 if (this.height < -this.centre.y) { 430 this.height = -this.centre.y; 431 } 432 if (this.height > maxY - this.centre.y) { 433 this.height = maxY - this.centre.y; 434 } 435 }; 436 437 /** 438 * Update the properties of this shape after a sequence of edits. 439 * 440 * For example make sure the circle radius is positive, of the polygon centre is centred. 441 */ 442 Rectangle.prototype.normalizeShape = function() { 443 if (this.width < 0) { 444 this.centre.x += this.width; 445 this.width = -this.width; 446 } 447 if (this.height < 0) { 448 this.centre.y += this.height; 449 this.height = -this.height; 450 } 451 }; 452 453 Rectangle.prototype.makeSimilarCircle = function() { 454 return new Circle(this.label, 455 Math.round(this.centre.x + this.width / 2), 456 Math.round(this.centre.y + this.height / 2), 457 Math.round((this.width + this.height) / 4)); 458 }; 459 460 Rectangle.prototype.makeSimilarPolygon = function() { 461 return new Polygon(this.label, [ 462 this.centre, this.centre.offset(0, this.height), 463 this.centre.offset(this.width, this.height), this.centre.offset(this.width, 0)]); 464 }; 465 466 Rectangle.prototype.getHandlePositions = function() { 467 return { 468 moveHandle: this.centre.offset(this.width / 2, this.height / 2), 469 editHandles: [this.centre.offset(this.width, this.height)] 470 }; 471 }; 472 473 474 /** 475 * A shape that is a polygon. 476 * 477 * @param {String} label name of this area. 478 * @param {Point[]} [points] position of the vertices relative to (centreX, centreY). 479 * each object in the array should have two 480 * @constructor 481 */ 482 function Polygon(label, points) { 483 Shape.call(this, label, 0, 0); 484 this.points = points ? points.slice() : [new Point(10, 10), new Point(40, 10), new Point(10, 40)]; 485 this.normalizeShape(); 486 this.ratio = 1; 487 } 488 Polygon.prototype = new Shape(); 489 490 Polygon.prototype.getType = function() { 491 return 'polygon'; 492 }; 493 494 Polygon.prototype.getCoordinates = function() { 495 var coordinates = ''; 496 for (var i = 0; i < this.points.length; i++) { 497 coordinates += this.centre.offset(this.points[i]) + ';'; 498 } 499 return coordinates.slice(0, coordinates.length - 1); // Strip off the last ';'. 500 }; 501 502 Polygon.prototype.makeSvg = function(svg) { 503 var svgEl = createSvgShapeGroup(svg, 'polygon'); 504 this.updateSvg(svgEl); 505 return svgEl; 506 }; 507 508 Polygon.prototype.updateSvg = function(svgEl) { 509 svgEl.childNodes[0].setAttribute('points', this.getCoordinates().replace(/[,;]/g, ' ')); 510 svgEl.childNodes[0].setAttribute('transform', 'scale(' + parseFloat(this.ratio) + ')'); 511 svgEl.childNodes[1].setAttribute('x', this.centre.x); 512 svgEl.childNodes[1].setAttribute('y', this.centre.y + 15); 513 svgEl.childNodes[1].textContent = this.label; 514 }; 515 516 Polygon.prototype.parse = function(coordinates, ratio) { 517 if (!coordinates.match(/^\d+(\.\d+)?,\d+(\.\d+)?(?:;\d+(\.\d+)?,\d+(\.\d+)?)*$/)) { 518 return false; 519 } 520 521 var bits = coordinates.split(';'); 522 var points = []; 523 for (var i = 0; i < bits.length; i++) { 524 points.push(Point.parse(bits[i])); 525 } 526 527 this.points = points; 528 this.centre.x = 0; 529 this.centre.y = 0; 530 this.ratio = ratio; 531 this.normalizeShape(); 532 533 return true; 534 }; 535 536 Polygon.prototype.move = function(dx, dy, maxX, maxY) { 537 this.centre.move(dx, dy); 538 var bbXMin = maxX, 539 bbXMax = 0, 540 bbYMin = maxY, 541 bbYMax = 0; 542 // Computer centre. 543 for (var i = 0; i < this.points.length; i++) { 544 bbXMin = Math.min(bbXMin, this.points[i].x); 545 bbXMax = Math.max(bbXMax, this.points[i].x); 546 bbYMin = Math.min(bbYMin, this.points[i].y); 547 bbYMax = Math.max(bbYMax, this.points[i].y); 548 } 549 if (this.centre.x < -bbXMin) { 550 this.centre.x = -bbXMin; 551 } 552 if (this.centre.x > maxX - bbXMax) { 553 this.centre.x = maxX - bbXMax; 554 } 555 if (this.centre.y < -bbYMin) { 556 this.centre.y = -bbYMin; 557 } 558 if (this.centre.y > maxY - bbYMax) { 559 this.centre.y = maxY - bbYMax; 560 } 561 }; 562 563 Polygon.prototype.edit = function(handleIndex, dx, dy, maxX, maxY) { 564 this.points[handleIndex].move(dx, dy); 565 if (this.points[handleIndex].x < -this.centre.x) { 566 this.points[handleIndex].x = -this.centre.x; 567 } 568 if (this.points[handleIndex].x > maxX - this.centre.x) { 569 this.points[handleIndex].x = maxX - this.centre.x; 570 } 571 if (this.points[handleIndex].y < -this.centre.y) { 572 this.points[handleIndex].y = -this.centre.y; 573 } 574 if (this.points[handleIndex].y > maxY - this.centre.y) { 575 this.points[handleIndex].y = maxY - this.centre.y; 576 } 577 }; 578 579 /** 580 * Add a new point after the given point, with the same co-ordinates. 581 * 582 * This does not automatically normalise. 583 * 584 * @param {int} pointIndex the index of the vertex after which to insert this new one. 585 */ 586 Polygon.prototype.addNewPointAfter = function(pointIndex) { 587 this.points.splice(pointIndex, 0, 588 new Point(this.points[pointIndex].x, this.points[pointIndex].y)); 589 }; 590 591 Polygon.prototype.normalizeShape = function() { 592 var i, 593 x = 0, 594 y = 0; 595 596 if (this.points.length === 0) { 597 return; 598 } 599 600 // Computer centre. 601 for (i = 0; i < this.points.length; i++) { 602 x += this.points[i].x; 603 y += this.points[i].y; 604 } 605 x = Math.round(x / this.points.length); 606 y = Math.round(y / this.points.length); 607 608 if (x === 0 && y === 0) { 609 return; 610 } 611 612 for (i = 0; i < this.points.length; i++) { 613 this.points[i].move(-x, -y); 614 } 615 this.centre.move(x, y); 616 }; 617 618 Polygon.prototype.makeSimilarCircle = function() { 619 return this.makeSimilarRectangle().makeSimilarCircle(); 620 }; 621 622 Polygon.prototype.makeSimilarRectangle = function() { 623 var p, 624 minX = 0, 625 maxX = 0, 626 minY = 0, 627 maxY = 0; 628 for (var i = 0; i < this.points.length; i++) { 629 p = this.points[i]; 630 minX = Math.min(minX, p.x); 631 maxX = Math.max(maxX, p.x); 632 minY = Math.min(minY, p.y); 633 maxY = Math.max(maxY, p.y); 634 } 635 return new Rectangle(this.label, 636 this.centre.x + minX, this.centre.y + minY, 637 Math.max(maxX - minX, 10), Math.max(maxY - minY, 10)); 638 }; 639 640 Polygon.prototype.getHandlePositions = function() { 641 var editHandles = []; 642 for (var i = 0; i < this.points.length; i++) { 643 editHandles.push(this.points[i].offset(this.centre.x, this.centre.y)); 644 } 645 646 this.centre.x = this.centre.x * parseFloat(this.ratio); 647 this.centre.y = this.centre.y * parseFloat(this.ratio); 648 649 return { 650 moveHandle: this.centre, 651 editHandles: editHandles 652 }; 653 }; 654 655 656 /** 657 * Not a shape (null object pattern). 658 * 659 * @param {String} label name of this area. 660 * @constructor 661 */ 662 function NullShape(label) { 663 Shape.call(this, label); 664 } 665 NullShape.prototype = new Shape(); 666 667 NullShape.prototype.getType = function() { 668 return 'null'; 669 }; 670 671 NullShape.prototype.getCoordinates = function() { 672 return ''; 673 }; 674 675 NullShape.prototype.makeSvg = function(svg) { 676 void (svg); 677 return null; 678 }; 679 680 NullShape.prototype.updateSvg = function(svgEl) { 681 void (svgEl); 682 }; 683 684 NullShape.prototype.parse = function(coordinates) { 685 void (coordinates); 686 return false; 687 }; 688 689 NullShape.prototype.makeSimilarCircle = function() { 690 return new Circle(this.label); 691 }; 692 693 NullShape.prototype.makeSimilarRectangle = function() { 694 return new Rectangle(this.label); 695 }; 696 697 NullShape.prototype.makeSimilarPolygon = function() { 698 return new Polygon(this.label); 699 }; 700 701 702 /** 703 * Make a new SVG DOM element as a child of svg. 704 * 705 * @param {SVGElement} svg the parent node. 706 * @param {String} tagName the tag name. 707 * @return {SVGElement} the newly created node. 708 */ 709 function createSvgElement(svg, tagName) { 710 var svgEl = svg.ownerDocument.createElementNS('http://www.w3.org/2000/svg', tagName); 711 svg.appendChild(svgEl); 712 return svgEl; 713 } 714 715 /** 716 * Make a group SVG DOM elements containing a shape of the given type as first child, 717 * and a text label as the second child. 718 * 719 * @param {SVGElement} svg the parent node. 720 * @param {String} tagName the tag name. 721 * @return {SVGElement} the newly created g element. 722 */ 723 function createSvgShapeGroup(svg, tagName) { 724 var svgEl = createSvgElement(svg, 'g'); 725 createSvgElement(svgEl, tagName).setAttribute('class', 'shape'); 726 createSvgElement(svgEl, 'text').setAttribute('class', 'shapeLabel'); 727 return svgEl; 728 } 729 730 /** 731 * @alias module:qtype_ddmarker/shapes 732 */ 733 return { 734 /** 735 * A point, with x and y coordinates. 736 * 737 * @param {int} x centre X. 738 * @param {int} y centre Y. 739 * @constructor 740 */ 741 Point: Point, 742 743 /** 744 * A point, with x and y coordinates. 745 * 746 * @param {int} x centre X. 747 * @param {int} y centre Y. 748 * @constructor 749 */ 750 Shape: Shape, 751 752 /** 753 * A shape that is a circle. 754 * 755 * @param {String} label name of this area. 756 * @param {int} [x] centre X. 757 * @param {int} [y] centre Y. 758 * @param {int} [radius] radius. 759 * @constructor 760 */ 761 Circle: Circle, 762 763 /** 764 * A shape that is a rectangle. 765 * 766 * @param {String} label name of this area. 767 * @param {int} [x] top left X. 768 * @param {int} [y] top left Y. 769 * @param {int} [width] width. 770 * @param {int} [height] height. 771 * @constructor 772 */ 773 Rectangle: Rectangle, 774 775 /** 776 * A shape that is a polygon. 777 * 778 * @param {String} label name of this area. 779 * @param {Point[]} [points] position of the vertices relative to (centreX, centreY). 780 * each object in the array should have two 781 * @constructor 782 */ 783 Polygon: Polygon, 784 785 /** 786 * Not a shape (null object pattern). 787 * 788 * @param {String} label name of this area. 789 * @constructor 790 */ 791 NullShape: NullShape, 792 793 /** 794 * Make a new SVG DOM element as a child of svg. 795 * 796 * @param {SVGElement} svg the parent node. 797 * @param {String} tagName the tag name. 798 * @return {SVGElement} the newly created node. 799 */ 800 createSvgElement: createSvgElement, 801 802 /** 803 * Make a shape of the given type. 804 * 805 * @param {String} shapeType 806 * @param {String} label 807 * @return {Shape} the requested shape. 808 */ 809 make: function(shapeType, label) { 810 switch (shapeType) { 811 case 'circle': 812 return new Circle(label); 813 case 'rectangle': 814 return new Rectangle(label); 815 case 'polygon': 816 return new Polygon(label); 817 default: 818 return new NullShape(label); 819 } 820 }, 821 822 /** 823 * Make a shape of the given type that is similar to the shape of the original type. 824 * 825 * @param {String} shapeType the new type of shape to make 826 * @param {Shape} shape the shape to copy 827 * @return {Shape} the similar shape of a different type. 828 */ 829 getSimilar: function(shapeType, shape) { 830 if (shapeType === shape.getType()) { 831 return shape; 832 } 833 switch (shapeType) { 834 case 'circle': 835 return shape.makeSimilarCircle(); 836 case 'rectangle': 837 return shape.makeSimilarRectangle(); 838 case 'polygon': 839 return shape.makeSimilarPolygon(); 840 default: 841 return new NullShape(shape.label); 842 } 843 } 844 }; 845 });
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated: Wed Jan 22 11:59:49 2025 | Cross-referenced by PHPXref 0.7.1 |