/src/path/Path.js

http://canviz.googlecode.com/ · JavaScript · 154 lines · 145 code · 3 blank · 6 comment · 45 complexity · dce21f9fc7c660b708d017207e604ec9 MD5 · raw file

  1. // Constructor
  2. function Path(segments, options) {
  3. if (!(this instanceof Path)) return new Path(segments, options);
  4. this.segments = segments || [];
  5. this.options = {};
  6. if (options) this.setOptions(options);
  7. }
  8. // Prototype
  9. Path.prototype = {
  10. constructor: Path,
  11. x_fill: false,
  12. x_stroke: true,
  13. x_strokeType: 'solid',
  14. x_dashLength: 6,
  15. x_dotSpacing: 4,
  16. setOptions: function (options) {
  17. var keys = objectKeys(options);
  18. var keysLength = keys.length;
  19. for (var i = 0; i < keysLength; ++i) {
  20. var key = keys[i];
  21. if ('x_' == key.substr(0, 2)) {
  22. this[key] = options[key];
  23. } else {
  24. this.options[key] = options[key];
  25. }
  26. }
  27. },
  28. setupSegments: function () {},
  29. // Based on Oliver Steele's bezier.js library.
  30. addBezier: function (pointsOrBezier) {
  31. this.segments.push(pointsOrBezier instanceof Array ? Bezier(pointsOrBezier) : pointsOrBezier);
  32. },
  33. offset: function (dx, dy) {
  34. if (0 == this.segments.length) this.setupSegments();
  35. var segmentsLength = this.segments.length;
  36. for (var i = 0; i < segmentsLength; ++i) {
  37. this.segments[i].offset(dx, dy);
  38. }
  39. },
  40. getBB: function () {
  41. if (0 == this.segments.length) this.setupSegments();
  42. var l, t, r, b, p = this.segments[0].points[0];
  43. l = r = p.x;
  44. t = b = p.y;
  45. var segmentsLength = this.segments.length;
  46. for (var i = 0; i < segmentsLength; ++i) {
  47. var points = this.segments[i].points;
  48. var pointsLength = points.length;
  49. for (var j = 0; j < pointsLength; ++j) {
  50. var point = this.segments[i].points[j];
  51. l = Math.min(l, point.x);
  52. t = Math.min(t, point.y);
  53. r = Math.max(r, point.x);
  54. b = Math.max(b, point.y);
  55. }
  56. }
  57. var rect = Rect(l, t, r, b);
  58. return (this.getBB = function () {return rect;})();
  59. },
  60. isPointInBB: function (x, y, tolerance) {
  61. if (typeof tolerance == 'undefined') tolerance = 0;
  62. var bb = this.getBB();
  63. if (0 < tolerance) {
  64. bb = Object.clone(bb);
  65. bb.inset(-tolerance, -tolerance);
  66. }
  67. return !(x < bb.l || x > bb.r || y < bb.t || y > bb.b);
  68. },
  69. isPointOnPath: function (x, y, tolerance) {
  70. if (typeof tolerance == 'undefined') tolerance = 0;
  71. if (!this.isPointInBB(x, y, tolerance)) return false;
  72. var segmentsLength = this.segments.length;
  73. for (var i = 0; i < segmentsLength; ++i) {
  74. if (this.segments[i].isPointOnBezier(x, y, tolerance)) {
  75. return true;
  76. }
  77. }
  78. return false;
  79. },
  80. isPointInPath: function (x, y) {
  81. return false;
  82. },
  83. // Based on Oliver Steele's bezier.js library.
  84. makePath: function (ctx) {
  85. if (0 == this.segments.length) this.setupSegments();
  86. var segmentsLength = this.segments.length;
  87. for (var i = 0; i < segmentsLength; ++i) {
  88. this.segments[i].makePath(ctx, 0 == i);
  89. }
  90. },
  91. makeDashedPath: function (ctx, dashLength, firstDistance, drawFirst) {
  92. if (0 == this.segments.length) this.setupSegments();
  93. var info = {
  94. drawFirst: (typeof drawFirst == 'undefined') || drawFirst,
  95. firstDistance: firstDistance || dashLength
  96. };
  97. var segmentsLength = this.segments.length;
  98. for (var i = 0; i < segmentsLength; ++i) {
  99. info = this.segments[i].makeDashedPath(ctx, dashLength, info.firstDistance, info.drawFirst);
  100. }
  101. },
  102. makeDottedPath: function (ctx, dotSpacing, firstDistance) {
  103. if (0 == this.segments.length) this.setupSegments();
  104. if (!firstDistance) firstDistance = dotSpacing;
  105. var segmentsLength = this.segments.length;
  106. for (var i = 0; i < segmentsLength; ++i) {
  107. firstDistance = this.segments[i].makeDottedPath(ctx, dotSpacing, firstDistance);
  108. }
  109. },
  110. draw: function (ctx) {
  111. ctx.save();
  112. var keys = objectKeys(this.options);
  113. var keysLength = keys.length;
  114. for (var i = 0; i < keysLength; ++i) {
  115. var key = keys[i];
  116. ctx[key] = this.options[key];
  117. }
  118. if (this.x_fill) {
  119. ctx.beginPath();
  120. this.makePath(ctx);
  121. ctx.fill();
  122. }
  123. if (this.x_stroke) {
  124. switch (this.x_strokeType) {
  125. case 'dashed':
  126. ctx.beginPath();
  127. this.makeDashedPath(ctx, this.x_dashLength);
  128. break;
  129. case 'dotted':
  130. if (ctx.lineWidth < 2) ctx.lineWidth = 2;
  131. ctx.beginPath();
  132. this.makeDottedPath(ctx, this.x_dotSpacing);
  133. break;
  134. case 'solid':
  135. default:
  136. if (!this.x_fill) {
  137. ctx.beginPath();
  138. this.makePath(ctx);
  139. }
  140. }
  141. ctx.stroke();
  142. }
  143. ctx.restore();
  144. }
  145. };
  146. // Exports
  147. module.exports = Path;
  148. // Dependencies
  149. var Bezier = require('./Bezier.js');
  150. var objectKeys = require('./objectKeys.js');
  151. var Rect = require('./Rect.js');