mxGeometry.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417
  1. /**
  2. * Copyright (c) 2006-2015, JGraph Ltd
  3. * Copyright (c) 2006-2015, Gaudenz Alder
  4. */
  5. /**
  6. * Class: mxGeometry
  7. *
  8. * Extends <mxRectangle> to represent the geometry of a cell.
  9. *
  10. * For vertices, the geometry consists of the x- and y-location, and the width
  11. * and height. For edges, the geometry consists of the optional terminal- and
  12. * control points. The terminal points are only required if an edge is
  13. * unconnected, and are stored in the <sourcePoint> and <targetPoint>
  14. * variables, respectively.
  15. *
  16. * Example:
  17. *
  18. * If an edge is unconnected, that is, it has no source or target terminal,
  19. * then a geometry with terminal points for a new edge can be defined as
  20. * follows.
  21. *
  22. * (code)
  23. * geometry.setTerminalPoint(new mxPoint(x1, y1), true);
  24. * geometry.points = [new mxPoint(x2, y2)];
  25. * geometry.setTerminalPoint(new mxPoint(x3, y3), false);
  26. * (end)
  27. *
  28. * Control points are used regardless of the connected state of an edge and may
  29. * be ignored or interpreted differently depending on the edge's <mxEdgeStyle>.
  30. *
  31. * To disable automatic reset of control points after a cell has been moved or
  32. * resized, the the <mxGraph.resizeEdgesOnMove> and
  33. * <mxGraph.resetEdgesOnResize> may be used.
  34. *
  35. * Edge Labels:
  36. *
  37. * Using the x- and y-coordinates of a cell's geometry, it is possible to
  38. * position the label on edges on a specific location on the actual edge shape
  39. * as it appears on the screen. The x-coordinate of an edge's geometry is used
  40. * to describe the distance from the center of the edge from -1 to 1 with 0
  41. * being the center of the edge and the default value. The y-coordinate of an
  42. * edge's geometry is used to describe the absolute, orthogonal distance in
  43. * pixels from that point. In addition, the <mxGeometry.offset> is used as an
  44. * absolute offset vector from the resulting point.
  45. *
  46. * This coordinate system is applied if <relative> is true, otherwise the
  47. * offset defines the absolute vector from the edge's center point to the
  48. * label and the values for <x> and <y> are ignored.
  49. *
  50. * The width and height parameter for edge geometries can be used to set the
  51. * label width and height (eg. for word wrapping).
  52. *
  53. * Ports:
  54. *
  55. * The term "port" refers to a relatively positioned, connectable child cell,
  56. * which is used to specify the connection between the parent and another cell
  57. * in the graph. Ports are typically modeled as vertices with relative
  58. * geometries.
  59. *
  60. * Offsets:
  61. *
  62. * The <offset> field is interpreted in 3 different ways, depending on the cell
  63. * and the geometry. For edges, the offset defines the absolute offset for the
  64. * edge label. For relative geometries, the offset defines the absolute offset
  65. * for the origin (top, left corner) of the vertex, otherwise the offset
  66. * defines the absolute offset for the label inside the vertex or group.
  67. *
  68. * Constructor: mxGeometry
  69. *
  70. * Constructs a new object to describe the size and location of a vertex or
  71. * the control points of an edge.
  72. */
  73. function mxGeometry(x, y, width, height)
  74. {
  75. mxRectangle.call(this, x, y, width, height);
  76. };
  77. /**
  78. * Extends mxRectangle.
  79. */
  80. mxGeometry.prototype = new mxRectangle();
  81. mxGeometry.prototype.constructor = mxGeometry;
  82. /**
  83. * Variable: TRANSLATE_CONTROL_POINTS
  84. *
  85. * Global switch to translate the points in translate. Default is true.
  86. */
  87. mxGeometry.prototype.TRANSLATE_CONTROL_POINTS = true;
  88. /**
  89. * Variable: alternateBounds
  90. *
  91. * Stores alternate values for x, y, width and height in a rectangle. See
  92. * <swap> to exchange the values. Default is null.
  93. */
  94. mxGeometry.prototype.alternateBounds = null;
  95. /**
  96. * Variable: sourcePoint
  97. *
  98. * Defines the source <mxPoint> of the edge. This is used if the
  99. * corresponding edge does not have a source vertex. Otherwise it is
  100. * ignored. Default is null.
  101. */
  102. mxGeometry.prototype.sourcePoint = null;
  103. /**
  104. * Variable: targetPoint
  105. *
  106. * Defines the target <mxPoint> of the edge. This is used if the
  107. * corresponding edge does not have a target vertex. Otherwise it is
  108. * ignored. Default is null.
  109. */
  110. mxGeometry.prototype.targetPoint = null;
  111. /**
  112. * Variable: points
  113. *
  114. * Array of <mxPoints> which specifies the control points along the edge.
  115. * These points are the intermediate points on the edge, for the endpoints
  116. * use <targetPoint> and <sourcePoint> or set the terminals of the edge to
  117. * a non-null value. Default is null.
  118. */
  119. mxGeometry.prototype.points = null;
  120. /**
  121. * Variable: offset
  122. *
  123. * For edges, this holds the offset (in pixels) from the position defined
  124. * by <x> and <y> on the edge. For relative geometries (for vertices), this
  125. * defines the absolute offset from the point defined by the relative
  126. * coordinates. For absolute geometries (for vertices), this defines the
  127. * offset for the label. Default is null.
  128. */
  129. mxGeometry.prototype.offset = null;
  130. /**
  131. * Variable: relative
  132. *
  133. * Specifies if the coordinates in the geometry are to be interpreted as
  134. * relative coordinates. For edges, this is used to define the location of
  135. * the edge label relative to the edge as rendered on the display. For
  136. * vertices, this specifies the relative location inside the bounds of the
  137. * parent cell.
  138. *
  139. * If this is false, then the coordinates are relative to the origin of the
  140. * parent cell or, for edges, the edge label position is relative to the
  141. * center of the edge as rendered on screen.
  142. *
  143. * Default is false.
  144. */
  145. mxGeometry.prototype.relative = false;
  146. /**
  147. * Function: swap
  148. *
  149. * Swaps the x, y, width and height with the values stored in
  150. * <alternateBounds> and puts the previous values into <alternateBounds> as
  151. * a rectangle. This operation is carried-out in-place, that is, using the
  152. * existing geometry instance. If this operation is called during a graph
  153. * model transactional change, then the geometry should be cloned before
  154. * calling this method and setting the geometry of the cell using
  155. * <mxGraphModel.setGeometry>.
  156. */
  157. mxGeometry.prototype.swap = function()
  158. {
  159. if (this.alternateBounds != null)
  160. {
  161. var old = new mxRectangle(
  162. this.x, this.y, this.width, this.height);
  163. this.x = this.alternateBounds.x;
  164. this.y = this.alternateBounds.y;
  165. this.width = this.alternateBounds.width;
  166. this.height = this.alternateBounds.height;
  167. this.alternateBounds = old;
  168. }
  169. };
  170. /**
  171. * Function: getTerminalPoint
  172. *
  173. * Returns the <mxPoint> representing the source or target point of this
  174. * edge. This is only used if the edge has no source or target vertex.
  175. *
  176. * Parameters:
  177. *
  178. * isSource - Boolean that specifies if the source or target point
  179. * should be returned.
  180. */
  181. mxGeometry.prototype.getTerminalPoint = function(isSource)
  182. {
  183. return (isSource) ? this.sourcePoint : this.targetPoint;
  184. };
  185. /**
  186. * Function: setTerminalPoint
  187. *
  188. * Sets the <sourcePoint> or <targetPoint> to the given <mxPoint> and
  189. * returns the new point.
  190. *
  191. * Parameters:
  192. *
  193. * point - Point to be used as the new source or target point.
  194. * isSource - Boolean that specifies if the source or target point
  195. * should be set.
  196. */
  197. mxGeometry.prototype.setTerminalPoint = function(point, isSource)
  198. {
  199. if (isSource)
  200. {
  201. this.sourcePoint = point;
  202. }
  203. else
  204. {
  205. this.targetPoint = point;
  206. }
  207. return point;
  208. };
  209. /**
  210. * Function: rotate
  211. *
  212. * Rotates the geometry by the given angle around the given center. That is,
  213. * <x> and <y> of the geometry, the <sourcePoint>, <targetPoint> and all
  214. * <points> are translated by the given amount. <x> and <y> are only
  215. * translated if <relative> is false.
  216. *
  217. * Parameters:
  218. *
  219. * angle - Number that specifies the rotation angle in degrees.
  220. * cx - <mxPoint> that specifies the center of the rotation.
  221. */
  222. mxGeometry.prototype.rotate = function(angle, cx)
  223. {
  224. var rad = mxUtils.toRadians(angle);
  225. var cos = Math.cos(rad);
  226. var sin = Math.sin(rad);
  227. // Rotates the geometry
  228. if (!this.relative)
  229. {
  230. var ct = new mxPoint(this.getCenterX(), this.getCenterY());
  231. var pt = mxUtils.getRotatedPoint(ct, cos, sin, cx);
  232. this.x = Math.round(pt.x - this.width / 2);
  233. this.y = Math.round(pt.y - this.height / 2);
  234. }
  235. // Rotates the source point
  236. if (this.sourcePoint != null)
  237. {
  238. var pt = mxUtils.getRotatedPoint(this.sourcePoint, cos, sin, cx);
  239. this.sourcePoint.x = Math.round(pt.x);
  240. this.sourcePoint.y = Math.round(pt.y);
  241. }
  242. // Translates the target point
  243. if (this.targetPoint != null)
  244. {
  245. var pt = mxUtils.getRotatedPoint(this.targetPoint, cos, sin, cx);
  246. this.targetPoint.x = Math.round(pt.x);
  247. this.targetPoint.y = Math.round(pt.y);
  248. }
  249. // Translate the control points
  250. if (this.points != null)
  251. {
  252. for (var i = 0; i < this.points.length; i++)
  253. {
  254. if (this.points[i] != null)
  255. {
  256. var pt = mxUtils.getRotatedPoint(this.points[i], cos, sin, cx);
  257. this.points[i].x = Math.round(pt.x);
  258. this.points[i].y = Math.round(pt.y);
  259. }
  260. }
  261. }
  262. };
  263. /**
  264. * Function: translate
  265. *
  266. * Translates the geometry by the specified amount. That is, <x> and <y> of the
  267. * geometry, the <sourcePoint>, <targetPoint> and all <points> are translated
  268. * by the given amount. <x> and <y> are only translated if <relative> is false.
  269. * If <TRANSLATE_CONTROL_POINTS> is false, then <points> are not modified by
  270. * this function.
  271. *
  272. * Parameters:
  273. *
  274. * dx - Number that specifies the x-coordinate of the translation.
  275. * dy - Number that specifies the y-coordinate of the translation.
  276. */
  277. mxGeometry.prototype.translate = function(dx, dy)
  278. {
  279. dx = parseFloat(dx);
  280. dy = parseFloat(dy);
  281. // Translates the geometry
  282. if (!this.relative)
  283. {
  284. this.x = parseFloat(this.x) + dx;
  285. this.y = parseFloat(this.y) + dy;
  286. }
  287. // Translates the source point
  288. if (this.sourcePoint != null)
  289. {
  290. this.sourcePoint.x = parseFloat(this.sourcePoint.x) + dx;
  291. this.sourcePoint.y = parseFloat(this.sourcePoint.y) + dy;
  292. }
  293. // Translates the target point
  294. if (this.targetPoint != null)
  295. {
  296. this.targetPoint.x = parseFloat(this.targetPoint.x) + dx;
  297. this.targetPoint.y = parseFloat(this.targetPoint.y) + dy;
  298. }
  299. // Translate the control points
  300. if (this.TRANSLATE_CONTROL_POINTS && this.points != null)
  301. {
  302. for (var i = 0; i < this.points.length; i++)
  303. {
  304. if (this.points[i] != null)
  305. {
  306. this.points[i].x = parseFloat(this.points[i].x) + dx;
  307. this.points[i].y = parseFloat(this.points[i].y) + dy;
  308. }
  309. }
  310. }
  311. };
  312. /**
  313. * Function: scale
  314. *
  315. * Scales the geometry by the given amount. That is, <x> and <y> of the
  316. * geometry, the <sourcePoint>, <targetPoint> and all <points> are scaled
  317. * by the given amount. <x>, <y>, <width> and <height> are only scaled if
  318. * <relative> is false. If <fixedAspect> is true, then the smaller value
  319. * is used to scale the width and the height.
  320. *
  321. * Parameters:
  322. *
  323. * sx - Number that specifies the horizontal scale factor.
  324. * sy - Number that specifies the vertical scale factor.
  325. * fixedAspect - Optional boolean to keep the aspect ratio fixed.
  326. */
  327. mxGeometry.prototype.scale = function(sx, sy, fixedAspect)
  328. {
  329. sx = parseFloat(sx);
  330. sy = parseFloat(sy);
  331. // Translates the source point
  332. if (this.sourcePoint != null)
  333. {
  334. this.sourcePoint.x = parseFloat(this.sourcePoint.x) * sx;
  335. this.sourcePoint.y = parseFloat(this.sourcePoint.y) * sy;
  336. }
  337. // Translates the target point
  338. if (this.targetPoint != null)
  339. {
  340. this.targetPoint.x = parseFloat(this.targetPoint.x) * sx;
  341. this.targetPoint.y = parseFloat(this.targetPoint.y) * sy;
  342. }
  343. // Translate the control points
  344. if (this.points != null)
  345. {
  346. for (var i = 0; i < this.points.length; i++)
  347. {
  348. if (this.points[i] != null)
  349. {
  350. this.points[i].x = parseFloat(this.points[i].x) * sx;
  351. this.points[i].y = parseFloat(this.points[i].y) * sy;
  352. }
  353. }
  354. }
  355. // Translates the geometry
  356. if (!this.relative)
  357. {
  358. this.x = parseFloat(this.x) * sx;
  359. this.y = parseFloat(this.y) * sy;
  360. if (fixedAspect)
  361. {
  362. sy = sx = Math.min(sx, sy);
  363. }
  364. this.width = parseFloat(this.width) * sx;
  365. this.height = parseFloat(this.height) * sy;
  366. }
  367. };
  368. /**
  369. * Function: equals
  370. *
  371. * Returns true if the given object equals this geometry.
  372. */
  373. mxGeometry.prototype.equals = function(obj)
  374. {
  375. return mxRectangle.prototype.equals.apply(this, arguments) &&
  376. this.relative == obj.relative &&
  377. ((this.sourcePoint == null && obj.sourcePoint == null) || (this.sourcePoint != null && this.sourcePoint.equals(obj.sourcePoint))) &&
  378. ((this.targetPoint == null && obj.targetPoint == null) || (this.targetPoint != null && this.targetPoint.equals(obj.targetPoint))) &&
  379. ((this.points == null && obj.points == null) || (this.points != null && mxUtils.equalPoints(this.points, obj.points))) &&
  380. ((this.alternateBounds == null && obj.alternateBounds == null) || (this.alternateBounds != null && this.alternateBounds.equals(obj.alternateBounds))) &&
  381. ((this.offset == null && obj.offset == null) || (this.offset != null && this.offset.equals(obj.offset)));
  382. };
  383. __mxOutput.mxGeometry = typeof mxGeometry !== 'undefined' ? mxGeometry : undefined;