symbol.js 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374
  1. /*
  2. * Licensed to the Apache Software Foundation (ASF) under one
  3. * or more contributor license agreements. See the NOTICE file
  4. * distributed with this work for additional information
  5. * regarding copyright ownership. The ASF licenses this file
  6. * to you under the Apache License, Version 2.0 (the
  7. * "License"); you may not use this file except in compliance
  8. * with the License. You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing,
  13. * software distributed under the License is distributed on an
  14. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  15. * KIND, either express or implied. See the License for the
  16. * specific language governing permissions and limitations
  17. * under the License.
  18. */
  19. // Symbol factory
  20. import * as zrUtil from 'zrender/src/core/util';
  21. import * as graphic from './graphic';
  22. import BoundingRect from 'zrender/src/core/BoundingRect';
  23. import {calculateTextPosition} from 'zrender/src/contain/text';
  24. /**
  25. * Triangle shape
  26. * @inner
  27. */
  28. var Triangle = graphic.extendShape({
  29. type: 'triangle',
  30. shape: {
  31. cx: 0,
  32. cy: 0,
  33. width: 0,
  34. height: 0
  35. },
  36. buildPath: function (path, shape) {
  37. var cx = shape.cx;
  38. var cy = shape.cy;
  39. var width = shape.width / 2;
  40. var height = shape.height / 2;
  41. path.moveTo(cx, cy - height);
  42. path.lineTo(cx + width, cy + height);
  43. path.lineTo(cx - width, cy + height);
  44. path.closePath();
  45. }
  46. });
  47. /**
  48. * Diamond shape
  49. * @inner
  50. */
  51. var Diamond = graphic.extendShape({
  52. type: 'diamond',
  53. shape: {
  54. cx: 0,
  55. cy: 0,
  56. width: 0,
  57. height: 0
  58. },
  59. buildPath: function (path, shape) {
  60. var cx = shape.cx;
  61. var cy = shape.cy;
  62. var width = shape.width / 2;
  63. var height = shape.height / 2;
  64. path.moveTo(cx, cy - height);
  65. path.lineTo(cx + width, cy);
  66. path.lineTo(cx, cy + height);
  67. path.lineTo(cx - width, cy);
  68. path.closePath();
  69. }
  70. });
  71. /**
  72. * Pin shape
  73. * @inner
  74. */
  75. var Pin = graphic.extendShape({
  76. type: 'pin',
  77. shape: {
  78. // x, y on the cusp
  79. x: 0,
  80. y: 0,
  81. width: 0,
  82. height: 0
  83. },
  84. buildPath: function (path, shape) {
  85. var x = shape.x;
  86. var y = shape.y;
  87. var w = shape.width / 5 * 3;
  88. // Height must be larger than width
  89. var h = Math.max(w, shape.height);
  90. var r = w / 2;
  91. // Dist on y with tangent point and circle center
  92. var dy = r * r / (h - r);
  93. var cy = y - h + r + dy;
  94. var angle = Math.asin(dy / r);
  95. // Dist on x with tangent point and circle center
  96. var dx = Math.cos(angle) * r;
  97. var tanX = Math.sin(angle);
  98. var tanY = Math.cos(angle);
  99. var cpLen = r * 0.6;
  100. var cpLen2 = r * 0.7;
  101. path.moveTo(x - dx, cy + dy);
  102. path.arc(
  103. x, cy, r,
  104. Math.PI - angle,
  105. Math.PI * 2 + angle
  106. );
  107. path.bezierCurveTo(
  108. x + dx - tanX * cpLen, cy + dy + tanY * cpLen,
  109. x, y - cpLen2,
  110. x, y
  111. );
  112. path.bezierCurveTo(
  113. x, y - cpLen2,
  114. x - dx + tanX * cpLen, cy + dy + tanY * cpLen,
  115. x - dx, cy + dy
  116. );
  117. path.closePath();
  118. }
  119. });
  120. /**
  121. * Arrow shape
  122. * @inner
  123. */
  124. var Arrow = graphic.extendShape({
  125. type: 'arrow',
  126. shape: {
  127. x: 0,
  128. y: 0,
  129. width: 0,
  130. height: 0
  131. },
  132. buildPath: function (ctx, shape) {
  133. var height = shape.height;
  134. var width = shape.width;
  135. var x = shape.x;
  136. var y = shape.y;
  137. var dx = width / 3 * 2;
  138. ctx.moveTo(x, y);
  139. ctx.lineTo(x + dx, y + height);
  140. ctx.lineTo(x, y + height / 4 * 3);
  141. ctx.lineTo(x - dx, y + height);
  142. ctx.lineTo(x, y);
  143. ctx.closePath();
  144. }
  145. });
  146. /**
  147. * Map of path contructors
  148. * @type {Object.<string, module:zrender/graphic/Path>}
  149. */
  150. var symbolCtors = {
  151. line: graphic.Line,
  152. rect: graphic.Rect,
  153. roundRect: graphic.Rect,
  154. square: graphic.Rect,
  155. circle: graphic.Circle,
  156. diamond: Diamond,
  157. pin: Pin,
  158. arrow: Arrow,
  159. triangle: Triangle
  160. };
  161. var symbolShapeMakers = {
  162. line: function (x, y, w, h, shape) {
  163. // FIXME
  164. shape.x1 = x;
  165. shape.y1 = y + h / 2;
  166. shape.x2 = x + w;
  167. shape.y2 = y + h / 2;
  168. },
  169. rect: function (x, y, w, h, shape) {
  170. shape.x = x;
  171. shape.y = y;
  172. shape.width = w;
  173. shape.height = h;
  174. },
  175. roundRect: function (x, y, w, h, shape) {
  176. shape.x = x;
  177. shape.y = y;
  178. shape.width = w;
  179. shape.height = h;
  180. shape.r = Math.min(w, h) / 4;
  181. },
  182. square: function (x, y, w, h, shape) {
  183. var size = Math.min(w, h);
  184. shape.x = x;
  185. shape.y = y;
  186. shape.width = size;
  187. shape.height = size;
  188. },
  189. circle: function (x, y, w, h, shape) {
  190. // Put circle in the center of square
  191. shape.cx = x + w / 2;
  192. shape.cy = y + h / 2;
  193. shape.r = Math.min(w, h) / 2;
  194. },
  195. diamond: function (x, y, w, h, shape) {
  196. shape.cx = x + w / 2;
  197. shape.cy = y + h / 2;
  198. shape.width = w;
  199. shape.height = h;
  200. },
  201. pin: function (x, y, w, h, shape) {
  202. shape.x = x + w / 2;
  203. shape.y = y + h / 2;
  204. shape.width = w;
  205. shape.height = h;
  206. },
  207. arrow: function (x, y, w, h, shape) {
  208. shape.x = x + w / 2;
  209. shape.y = y + h / 2;
  210. shape.width = w;
  211. shape.height = h;
  212. },
  213. triangle: function (x, y, w, h, shape) {
  214. shape.cx = x + w / 2;
  215. shape.cy = y + h / 2;
  216. shape.width = w;
  217. shape.height = h;
  218. }
  219. };
  220. var symbolBuildProxies = {};
  221. zrUtil.each(symbolCtors, function (Ctor, name) {
  222. symbolBuildProxies[name] = new Ctor();
  223. });
  224. var SymbolClz = graphic.extendShape({
  225. type: 'symbol',
  226. shape: {
  227. symbolType: '',
  228. x: 0,
  229. y: 0,
  230. width: 0,
  231. height: 0
  232. },
  233. calculateTextPosition: function (out, style, rect) {
  234. var res = calculateTextPosition(out, style, rect);
  235. var shape = this.shape;
  236. if (shape && shape.symbolType === 'pin' && style.textPosition === 'inside') {
  237. res.y = rect.y + rect.height * 0.4;
  238. }
  239. return res;
  240. },
  241. buildPath: function (ctx, shape, inBundle) {
  242. var symbolType = shape.symbolType;
  243. if (symbolType !== 'none') {
  244. var proxySymbol = symbolBuildProxies[symbolType];
  245. if (!proxySymbol) {
  246. // Default rect
  247. symbolType = 'rect';
  248. proxySymbol = symbolBuildProxies[symbolType];
  249. }
  250. symbolShapeMakers[symbolType](
  251. shape.x, shape.y, shape.width, shape.height, proxySymbol.shape
  252. );
  253. proxySymbol.buildPath(ctx, proxySymbol.shape, inBundle);
  254. }
  255. }
  256. });
  257. // Provide setColor helper method to avoid determine if set the fill or stroke outside
  258. function symbolPathSetColor(color, innerColor) {
  259. if (this.type !== 'image') {
  260. var symbolStyle = this.style;
  261. var symbolShape = this.shape;
  262. if (symbolShape && symbolShape.symbolType === 'line') {
  263. symbolStyle.stroke = color;
  264. }
  265. else if (this.__isEmptyBrush) {
  266. symbolStyle.stroke = color;
  267. symbolStyle.fill = innerColor || '#fff';
  268. }
  269. else {
  270. // FIXME 判断图形默认是填充还是描边,使用 onlyStroke ?
  271. symbolStyle.fill && (symbolStyle.fill = color);
  272. symbolStyle.stroke && (symbolStyle.stroke = color);
  273. }
  274. this.dirty(false);
  275. }
  276. }
  277. /**
  278. * Create a symbol element with given symbol configuration: shape, x, y, width, height, color
  279. * @param {string} symbolType
  280. * @param {number} x
  281. * @param {number} y
  282. * @param {number} w
  283. * @param {number} h
  284. * @param {string} color
  285. * @param {boolean} [keepAspect=false] whether to keep the ratio of w/h,
  286. * for path and image only.
  287. */
  288. export function createSymbol(symbolType, x, y, w, h, color, keepAspect) {
  289. // TODO Support image object, DynamicImage.
  290. var isEmpty = symbolType.indexOf('empty') === 0;
  291. if (isEmpty) {
  292. symbolType = symbolType.substr(5, 1).toLowerCase() + symbolType.substr(6);
  293. }
  294. var symbolPath;
  295. if (symbolType.indexOf('image://') === 0) {
  296. symbolPath = graphic.makeImage(
  297. symbolType.slice(8),
  298. new BoundingRect(x, y, w, h),
  299. keepAspect ? 'center' : 'cover'
  300. );
  301. }
  302. else if (symbolType.indexOf('path://') === 0) {
  303. symbolPath = graphic.makePath(
  304. symbolType.slice(7),
  305. {},
  306. new BoundingRect(x, y, w, h),
  307. keepAspect ? 'center' : 'cover'
  308. );
  309. }
  310. else {
  311. symbolPath = new SymbolClz({
  312. shape: {
  313. symbolType: symbolType,
  314. x: x,
  315. y: y,
  316. width: w,
  317. height: h
  318. }
  319. });
  320. }
  321. symbolPath.__isEmptyBrush = isEmpty;
  322. symbolPath.setColor = symbolPathSetColor;
  323. symbolPath.setColor(color);
  324. return symbolPath;
  325. }