mxMarker.js 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. /**
  2. * Copyright (c) 2006-2015, JGraph Ltd
  3. * Copyright (c) 2006-2015, Gaudenz Alder
  4. */
  5. var mxMarker =
  6. {
  7. /**
  8. * Class: mxMarker
  9. *
  10. * A static class that implements all markers for SVG using a
  11. * registry. NOTE: The signatures in this class will change.
  12. *
  13. * Variable: markers
  14. *
  15. * Maps from markers names to functions to paint the markers.
  16. */
  17. markers: [],
  18. /**
  19. * Function: addMarker
  20. *
  21. * Adds a factory method that updates a given endpoint and returns a
  22. * function to paint the marker onto the given canvas.
  23. */
  24. addMarker: function(type, funct)
  25. {
  26. mxMarker.markers[type] = funct;
  27. },
  28. /**
  29. * Function: createMarker
  30. *
  31. * Returns a function to paint the given marker.
  32. */
  33. createMarker: function(canvas, shape, type, pe, unitX, unitY, size, source, sw, filled)
  34. {
  35. var funct = mxMarker.markers[type];
  36. return (funct != null) ? funct(canvas, shape, type, pe, unitX, unitY, size, source, sw, filled) : null;
  37. }
  38. };
  39. /**
  40. * Adds the classic and block marker factory method.
  41. */
  42. (function()
  43. {
  44. function createArrow(widthFactor)
  45. {
  46. widthFactor = (widthFactor != null) ? widthFactor : 2;
  47. return function(canvas, shape, type, pe, unitX, unitY, size, source, sw, filled)
  48. {
  49. // The angle of the forward facing arrow sides against the x axis is
  50. // 26.565 degrees, 1/sin(26.565) = 2.236 / 2 = 1.118 ( / 2 allows for
  51. // only half the strokewidth is processed ).
  52. var endOffsetX = unitX * sw * 1.118;
  53. var endOffsetY = unitY * sw * 1.118;
  54. unitX = unitX * (size + sw);
  55. unitY = unitY * (size + sw);
  56. var pt = pe.clone();
  57. pt.x -= endOffsetX;
  58. pt.y -= endOffsetY;
  59. var f = (type != mxConstants.ARROW_CLASSIC && type != mxConstants.ARROW_CLASSIC_THIN) ? 1 : 3 / 4;
  60. pe.x += -unitX * f - endOffsetX;
  61. pe.y += -unitY * f - endOffsetY;
  62. return function()
  63. {
  64. canvas.begin();
  65. canvas.moveTo(pt.x, pt.y);
  66. canvas.lineTo(pt.x - unitX - unitY / widthFactor, pt.y - unitY + unitX / widthFactor);
  67. if (type == mxConstants.ARROW_CLASSIC || type == mxConstants.ARROW_CLASSIC_THIN)
  68. {
  69. canvas.lineTo(pt.x - unitX * 3 / 4, pt.y - unitY * 3 / 4);
  70. }
  71. canvas.lineTo(pt.x + unitY / widthFactor - unitX, pt.y - unitY - unitX / widthFactor);
  72. canvas.close();
  73. if (filled)
  74. {
  75. canvas.fillAndStroke();
  76. }
  77. else
  78. {
  79. canvas.stroke();
  80. }
  81. };
  82. }
  83. };
  84. mxMarker.addMarker('classic', createArrow(2));
  85. mxMarker.addMarker('classicThin', createArrow(3));
  86. mxMarker.addMarker('block', createArrow(2));
  87. mxMarker.addMarker('blockThin', createArrow(3));
  88. function createOpenArrow(widthFactor)
  89. {
  90. widthFactor = (widthFactor != null) ? widthFactor : 2;
  91. return function(canvas, shape, type, pe, unitX, unitY, size, source, sw, filled)
  92. {
  93. // The angle of the forward facing arrow sides against the x axis is
  94. // 26.565 degrees, 1/sin(26.565) = 2.236 / 2 = 1.118 ( / 2 allows for
  95. // only half the strokewidth is processed ).
  96. var endOffsetX = unitX * sw * 1.118;
  97. var endOffsetY = unitY * sw * 1.118;
  98. unitX = unitX * (size + sw);
  99. unitY = unitY * (size + sw);
  100. var pt = pe.clone();
  101. pt.x -= endOffsetX;
  102. pt.y -= endOffsetY;
  103. pe.x += -endOffsetX * 2;
  104. pe.y += -endOffsetY * 2;
  105. return function()
  106. {
  107. canvas.begin();
  108. canvas.moveTo(pt.x - unitX - unitY / widthFactor, pt.y - unitY + unitX / widthFactor);
  109. canvas.lineTo(pt.x, pt.y);
  110. canvas.lineTo(pt.x + unitY / widthFactor - unitX, pt.y - unitY - unitX / widthFactor);
  111. canvas.stroke();
  112. };
  113. }
  114. };
  115. mxMarker.addMarker('open', createOpenArrow(2));
  116. mxMarker.addMarker('openThin', createOpenArrow(3));
  117. mxMarker.addMarker('oval', function(canvas, shape, type, pe, unitX, unitY, size, source, sw, filled)
  118. {
  119. var a = size / 2;
  120. var pt = pe.clone();
  121. pe.x -= unitX * a;
  122. pe.y -= unitY * a;
  123. return function()
  124. {
  125. canvas.ellipse(pt.x - a, pt.y - a, size, size);
  126. if (filled)
  127. {
  128. canvas.fillAndStroke();
  129. }
  130. else
  131. {
  132. canvas.stroke();
  133. }
  134. };
  135. });
  136. mxMarker.addMarker('baseDash', function(canvas, shape, type, pe, unitX, unitY, size, source, sw, filled)
  137. {
  138. var nx = unitX * (size + sw + 1);
  139. var ny = unitY * (size + sw + 1);
  140. return function()
  141. {
  142. canvas.begin();
  143. canvas.moveTo(pe.x - ny / 2, pe.y + nx / 2);
  144. canvas.lineTo(pe.x + ny / 2, pe.y - nx / 2);
  145. canvas.stroke();
  146. };
  147. });
  148. mxMarker.addMarker('doubleBlock', function(canvas, shape, type, pe, unitX, unitY, size, source, sw, filled)
  149. {
  150. var widthFactor = 2;
  151. var endOffsetX = unitX * sw * 1.118;
  152. var endOffsetY = unitY * sw * 1.118;
  153. unitX = unitX * (size + sw);
  154. unitY = unitY * (size + sw);
  155. var pt = pe.clone();
  156. pt.x -= endOffsetX;
  157. pt.y -= endOffsetY;
  158. var f = (type != mxConstants.ARROW_CLASSIC && type != mxConstants.ARROW_CLASSIC_THIN) ? 1 : 3 / 4;
  159. pe.x += -unitX * f * 2 - endOffsetX;
  160. pe.y += -unitY * f * 2 - endOffsetY;
  161. return function()
  162. {
  163. canvas.begin();
  164. canvas.moveTo(pt.x, pt.y);
  165. canvas.lineTo(pt.x - unitX - unitY / widthFactor, pt.y - unitY + unitX / widthFactor);
  166. canvas.lineTo(pt.x + unitY / widthFactor - unitX, pt.y - unitY - unitX / widthFactor);
  167. canvas.close();
  168. canvas.moveTo(pt.x - unitX, pt.y - unitY);
  169. canvas.lineTo(pt.x - 2 * unitX - 0.5 * unitY, pt.y + 0.5 * unitX - 2 * unitY);
  170. canvas.lineTo(pt.x - 2 * unitX + 0.5 * unitY, pt.y - 0.5 * unitX - 2 * unitY);
  171. canvas.close();
  172. if (filled)
  173. {
  174. canvas.fillAndStroke();
  175. }
  176. else
  177. {
  178. canvas.stroke();
  179. }
  180. };
  181. });
  182. function diamond(canvas, shape, type, pe, unitX, unitY, size, source, sw, filled)
  183. {
  184. // The angle of the forward facing arrow sides against the x axis is
  185. // 45 degrees, 1/sin(45) = 1.4142 / 2 = 0.7071 ( / 2 allows for
  186. // only half the strokewidth is processed ). Or 0.9862 for thin diamond.
  187. // Note these values and the tk variable below are dependent, update
  188. // both together (saves trig hard coding it).
  189. var swFactor = (type == mxConstants.ARROW_DIAMOND) ? 0.7071 : 0.9862;
  190. var endOffsetX = unitX * sw * swFactor;
  191. var endOffsetY = unitY * sw * swFactor;
  192. unitX = unitX * (size + sw);
  193. unitY = unitY * (size + sw);
  194. var pt = pe.clone();
  195. pt.x -= endOffsetX;
  196. pt.y -= endOffsetY;
  197. pe.x += -unitX - endOffsetX;
  198. pe.y += -unitY - endOffsetY;
  199. // thickness factor for diamond
  200. var tk = ((type == mxConstants.ARROW_DIAMOND) ? 2 : 3.4);
  201. return function()
  202. {
  203. canvas.begin();
  204. canvas.moveTo(pt.x, pt.y);
  205. canvas.lineTo(pt.x - unitX / 2 - unitY / tk, pt.y + unitX / tk - unitY / 2);
  206. canvas.lineTo(pt.x - unitX, pt.y - unitY);
  207. canvas.lineTo(pt.x - unitX / 2 + unitY / tk, pt.y - unitY / 2 - unitX / tk);
  208. canvas.close();
  209. if (filled)
  210. {
  211. canvas.fillAndStroke();
  212. }
  213. else
  214. {
  215. canvas.stroke();
  216. }
  217. };
  218. };
  219. mxMarker.addMarker('diamond', diamond);
  220. mxMarker.addMarker('diamondThin', diamond);
  221. mxMarker.addMarker('manyOptional', function(c, shape, type, pe, unitX, unitY, size, source, sw, filled)
  222. {
  223. var nx = unitX * (size + sw + 1);
  224. var ny = unitY * (size + sw + 1);
  225. var a = size / 2;
  226. var px = pe.x;
  227. var py = pe.y;
  228. pe.x -= 2 * nx - unitX * sw / 2;
  229. pe.y -= 2 * ny - unitY * sw / 2;
  230. return function()
  231. {
  232. c.begin();
  233. c.ellipse(px - 1.5 * nx - a, py - 1.5 * ny - a, 2 * a, 2 * a);
  234. filled ? c.fillAndStroke() : c.stroke();
  235. c.begin();
  236. c.moveTo(px, py);
  237. c.lineTo(px - nx, py - ny);
  238. c.moveTo(px + ny / 2, py - nx / 2);
  239. c.lineTo(px - nx, py - ny);
  240. c.lineTo(px - ny / 2, py + nx / 2);
  241. c.stroke();
  242. };
  243. });
  244. })();