symbol.js 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. var zrUtil = require("zrender/lib/core/util");
  2. var graphic = require("./graphic");
  3. var BoundingRect = require("zrender/lib/core/BoundingRect");
  4. // Symbol factory
  5. /**
  6. * Triangle shape
  7. * @inner
  8. */
  9. var Triangle = graphic.extendShape({
  10. type: 'triangle',
  11. shape: {
  12. cx: 0,
  13. cy: 0,
  14. width: 0,
  15. height: 0
  16. },
  17. buildPath: function (path, shape) {
  18. var cx = shape.cx;
  19. var cy = shape.cy;
  20. var width = shape.width / 2;
  21. var height = shape.height / 2;
  22. path.moveTo(cx, cy - height);
  23. path.lineTo(cx + width, cy + height);
  24. path.lineTo(cx - width, cy + height);
  25. path.closePath();
  26. }
  27. });
  28. /**
  29. * Diamond shape
  30. * @inner
  31. */
  32. var Diamond = graphic.extendShape({
  33. type: 'diamond',
  34. shape: {
  35. cx: 0,
  36. cy: 0,
  37. width: 0,
  38. height: 0
  39. },
  40. buildPath: function (path, shape) {
  41. var cx = shape.cx;
  42. var cy = shape.cy;
  43. var width = shape.width / 2;
  44. var height = shape.height / 2;
  45. path.moveTo(cx, cy - height);
  46. path.lineTo(cx + width, cy);
  47. path.lineTo(cx, cy + height);
  48. path.lineTo(cx - width, cy);
  49. path.closePath();
  50. }
  51. });
  52. /**
  53. * Pin shape
  54. * @inner
  55. */
  56. var Pin = graphic.extendShape({
  57. type: 'pin',
  58. shape: {
  59. // x, y on the cusp
  60. x: 0,
  61. y: 0,
  62. width: 0,
  63. height: 0
  64. },
  65. buildPath: function (path, shape) {
  66. var x = shape.x;
  67. var y = shape.y;
  68. var w = shape.width / 5 * 3; // Height must be larger than width
  69. var h = Math.max(w, shape.height);
  70. var r = w / 2; // Dist on y with tangent point and circle center
  71. var dy = r * r / (h - r);
  72. var cy = y - h + r + dy;
  73. var angle = Math.asin(dy / r); // Dist on x with tangent point and circle center
  74. var dx = Math.cos(angle) * r;
  75. var tanX = Math.sin(angle);
  76. var tanY = Math.cos(angle);
  77. var cpLen = r * 0.6;
  78. var cpLen2 = r * 0.7;
  79. path.moveTo(x - dx, cy + dy);
  80. path.arc(x, cy, r, Math.PI - angle, Math.PI * 2 + angle);
  81. path.bezierCurveTo(x + dx - tanX * cpLen, cy + dy + tanY * cpLen, x, y - cpLen2, x, y);
  82. path.bezierCurveTo(x, y - cpLen2, x - dx + tanX * cpLen, cy + dy + tanY * cpLen, x - dx, cy + dy);
  83. path.closePath();
  84. }
  85. });
  86. /**
  87. * Arrow shape
  88. * @inner
  89. */
  90. var Arrow = graphic.extendShape({
  91. type: 'arrow',
  92. shape: {
  93. x: 0,
  94. y: 0,
  95. width: 0,
  96. height: 0
  97. },
  98. buildPath: function (ctx, shape) {
  99. var height = shape.height;
  100. var width = shape.width;
  101. var x = shape.x;
  102. var y = shape.y;
  103. var dx = width / 3 * 2;
  104. ctx.moveTo(x, y);
  105. ctx.lineTo(x + dx, y + height);
  106. ctx.lineTo(x, y + height / 4 * 3);
  107. ctx.lineTo(x - dx, y + height);
  108. ctx.lineTo(x, y);
  109. ctx.closePath();
  110. }
  111. });
  112. /**
  113. * Map of path contructors
  114. * @type {Object.<string, module:zrender/graphic/Path>}
  115. */
  116. var symbolCtors = {
  117. line: graphic.Line,
  118. rect: graphic.Rect,
  119. roundRect: graphic.Rect,
  120. square: graphic.Rect,
  121. circle: graphic.Circle,
  122. diamond: Diamond,
  123. pin: Pin,
  124. arrow: Arrow,
  125. triangle: Triangle
  126. };
  127. var symbolShapeMakers = {
  128. line: function (x, y, w, h, shape) {
  129. // FIXME
  130. shape.x1 = x;
  131. shape.y1 = y + h / 2;
  132. shape.x2 = x + w;
  133. shape.y2 = y + h / 2;
  134. },
  135. rect: function (x, y, w, h, shape) {
  136. shape.x = x;
  137. shape.y = y;
  138. shape.width = w;
  139. shape.height = h;
  140. },
  141. roundRect: function (x, y, w, h, shape) {
  142. shape.x = x;
  143. shape.y = y;
  144. shape.width = w;
  145. shape.height = h;
  146. shape.r = Math.min(w, h) / 4;
  147. },
  148. square: function (x, y, w, h, shape) {
  149. var size = Math.min(w, h);
  150. shape.x = x;
  151. shape.y = y;
  152. shape.width = size;
  153. shape.height = size;
  154. },
  155. circle: function (x, y, w, h, shape) {
  156. // Put circle in the center of square
  157. shape.cx = x + w / 2;
  158. shape.cy = y + h / 2;
  159. shape.r = Math.min(w, h) / 2;
  160. },
  161. diamond: function (x, y, w, h, shape) {
  162. shape.cx = x + w / 2;
  163. shape.cy = y + h / 2;
  164. shape.width = w;
  165. shape.height = h;
  166. },
  167. pin: function (x, y, w, h, shape) {
  168. shape.x = x + w / 2;
  169. shape.y = y + h / 2;
  170. shape.width = w;
  171. shape.height = h;
  172. },
  173. arrow: function (x, y, w, h, shape) {
  174. shape.x = x + w / 2;
  175. shape.y = y + h / 2;
  176. shape.width = w;
  177. shape.height = h;
  178. },
  179. triangle: function (x, y, w, h, shape) {
  180. shape.cx = x + w / 2;
  181. shape.cy = y + h / 2;
  182. shape.width = w;
  183. shape.height = h;
  184. }
  185. };
  186. var symbolBuildProxies = {};
  187. zrUtil.each(symbolCtors, function (Ctor, name) {
  188. symbolBuildProxies[name] = new Ctor();
  189. });
  190. var SymbolClz = graphic.extendShape({
  191. type: 'symbol',
  192. shape: {
  193. symbolType: '',
  194. x: 0,
  195. y: 0,
  196. width: 0,
  197. height: 0
  198. },
  199. beforeBrush: function () {
  200. var style = this.style;
  201. var shape = this.shape; // FIXME
  202. if (shape.symbolType === 'pin' && style.textPosition === 'inside') {
  203. style.textPosition = ['50%', '40%'];
  204. style.textAlign = 'center';
  205. style.textVerticalAlign = 'middle';
  206. }
  207. },
  208. buildPath: function (ctx, shape, inBundle) {
  209. var symbolType = shape.symbolType;
  210. var proxySymbol = symbolBuildProxies[symbolType];
  211. if (shape.symbolType !== 'none') {
  212. if (!proxySymbol) {
  213. // Default rect
  214. symbolType = 'rect';
  215. proxySymbol = symbolBuildProxies[symbolType];
  216. }
  217. symbolShapeMakers[symbolType](shape.x, shape.y, shape.width, shape.height, proxySymbol.shape);
  218. proxySymbol.buildPath(ctx, proxySymbol.shape, inBundle);
  219. }
  220. }
  221. }); // Provide setColor helper method to avoid determine if set the fill or stroke outside
  222. function symbolPathSetColor(color, innerColor) {
  223. if (this.type !== 'image') {
  224. var symbolStyle = this.style;
  225. var symbolShape = this.shape;
  226. if (symbolShape && symbolShape.symbolType === 'line') {
  227. symbolStyle.stroke = color;
  228. } else if (this.__isEmptyBrush) {
  229. symbolStyle.stroke = color;
  230. symbolStyle.fill = innerColor || '#fff';
  231. } else {
  232. // FIXME 判断图形默认是填充还是描边,使用 onlyStroke ?
  233. symbolStyle.fill && (symbolStyle.fill = color);
  234. symbolStyle.stroke && (symbolStyle.stroke = color);
  235. }
  236. this.dirty(false);
  237. }
  238. }
  239. /**
  240. * Create a symbol element with given symbol configuration: shape, x, y, width, height, color
  241. * @param {string} symbolType
  242. * @param {number} x
  243. * @param {number} y
  244. * @param {number} w
  245. * @param {number} h
  246. * @param {string} color
  247. * @param {boolean} [keepAspect=false] whether to keep the ratio of w/h,
  248. * for path and image only.
  249. */
  250. function createSymbol(symbolType, x, y, w, h, color, keepAspect) {
  251. // TODO Support image object, DynamicImage.
  252. var isEmpty = symbolType.indexOf('empty') === 0;
  253. if (isEmpty) {
  254. symbolType = symbolType.substr(5, 1).toLowerCase() + symbolType.substr(6);
  255. }
  256. var symbolPath;
  257. if (symbolType.indexOf('image://') === 0) {
  258. symbolPath = graphic.makeImage(symbolType.slice(8), new BoundingRect(x, y, w, h), keepAspect ? 'center' : 'cover');
  259. } else if (symbolType.indexOf('path://') === 0) {
  260. symbolPath = graphic.makePath(symbolType.slice(7), {}, new BoundingRect(x, y, w, h), keepAspect ? 'center' : 'cover');
  261. } else {
  262. symbolPath = new SymbolClz({
  263. shape: {
  264. symbolType: symbolType,
  265. x: x,
  266. y: y,
  267. width: w,
  268. height: h
  269. }
  270. });
  271. }
  272. symbolPath.__isEmptyBrush = isEmpty;
  273. symbolPath.setColor = symbolPathSetColor;
  274. symbolPath.setColor(color);
  275. return symbolPath;
  276. }
  277. exports.createSymbol = createSymbol;