Style.js 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447
  1. var STYLE_COMMON_PROPS = [['shadowBlur', 0], ['shadowOffsetX', 0], ['shadowOffsetY', 0], ['shadowColor', '#000'], ['lineCap', 'butt'], ['lineJoin', 'miter'], ['miterLimit', 10]]; // var SHADOW_PROPS = STYLE_COMMON_PROPS.slice(0, 4);
  2. // var LINE_PROPS = STYLE_COMMON_PROPS.slice(4);
  3. var Style = function (opts, host) {
  4. this.extendFrom(opts, false);
  5. this.host = host;
  6. };
  7. function createLinearGradient(ctx, obj, rect) {
  8. var x = obj.x == null ? 0 : obj.x;
  9. var x2 = obj.x2 == null ? 1 : obj.x2;
  10. var y = obj.y == null ? 0 : obj.y;
  11. var y2 = obj.y2 == null ? 0 : obj.y2;
  12. if (!obj.global) {
  13. x = x * rect.width + rect.x;
  14. x2 = x2 * rect.width + rect.x;
  15. y = y * rect.height + rect.y;
  16. y2 = y2 * rect.height + rect.y;
  17. }
  18. var canvasGradient = ctx.createLinearGradient(x, y, x2, y2);
  19. return canvasGradient;
  20. }
  21. function createRadialGradient(ctx, obj, rect) {
  22. var width = rect.width;
  23. var height = rect.height;
  24. var min = Math.min(width, height);
  25. var x = obj.x == null ? 0.5 : obj.x;
  26. var y = obj.y == null ? 0.5 : obj.y;
  27. var r = obj.r == null ? 0.5 : obj.r;
  28. if (!obj.global) {
  29. x = x * width + rect.x;
  30. y = y * height + rect.y;
  31. r = r * min;
  32. }
  33. var canvasGradient = ctx.createRadialGradient(x, y, 0, x, y, r);
  34. return canvasGradient;
  35. }
  36. Style.prototype = {
  37. constructor: Style,
  38. /**
  39. * @type {module:zrender/graphic/Displayable}
  40. */
  41. host: null,
  42. /**
  43. * @type {string}
  44. */
  45. fill: '#000',
  46. /**
  47. * @type {string}
  48. */
  49. stroke: null,
  50. /**
  51. * @type {number}
  52. */
  53. opacity: 1,
  54. /**
  55. * @type {Array.<number>}
  56. */
  57. lineDash: null,
  58. /**
  59. * @type {number}
  60. */
  61. lineDashOffset: 0,
  62. /**
  63. * @type {number}
  64. */
  65. shadowBlur: 0,
  66. /**
  67. * @type {number}
  68. */
  69. shadowOffsetX: 0,
  70. /**
  71. * @type {number}
  72. */
  73. shadowOffsetY: 0,
  74. /**
  75. * @type {number}
  76. */
  77. lineWidth: 1,
  78. /**
  79. * If stroke ignore scale
  80. * @type {Boolean}
  81. */
  82. strokeNoScale: false,
  83. // Bounding rect text configuration
  84. // Not affected by element transform
  85. /**
  86. * @type {string}
  87. */
  88. text: null,
  89. /**
  90. * If `fontSize` or `fontFamily` exists, `font` will be reset by
  91. * `fontSize`, `fontStyle`, `fontWeight`, `fontFamily`.
  92. * So do not visit it directly in upper application (like echarts),
  93. * but use `contain/text#makeFont` instead.
  94. * @type {string}
  95. */
  96. font: null,
  97. /**
  98. * The same as font. Use font please.
  99. * @deprecated
  100. * @type {string}
  101. */
  102. textFont: null,
  103. /**
  104. * It helps merging respectively, rather than parsing an entire font string.
  105. * @type {string}
  106. */
  107. fontStyle: null,
  108. /**
  109. * It helps merging respectively, rather than parsing an entire font string.
  110. * @type {string}
  111. */
  112. fontWeight: null,
  113. /**
  114. * It helps merging respectively, rather than parsing an entire font string.
  115. * Should be 12 but not '12px'.
  116. * @type {number}
  117. */
  118. fontSize: null,
  119. /**
  120. * It helps merging respectively, rather than parsing an entire font string.
  121. * @type {string}
  122. */
  123. fontFamily: null,
  124. /**
  125. * Reserved for special functinality, like 'hr'.
  126. * @type {string}
  127. */
  128. textTag: null,
  129. /**
  130. * @type {string}
  131. */
  132. textFill: '#000',
  133. /**
  134. * @type {string}
  135. */
  136. textStroke: null,
  137. /**
  138. * @type {number}
  139. */
  140. textWidth: null,
  141. /**
  142. * Only for textBackground.
  143. * @type {number}
  144. */
  145. textHeight: null,
  146. /**
  147. * textStroke may be set as some color as a default
  148. * value in upper applicaion, where the default value
  149. * of textStrokeWidth should be 0 to make sure that
  150. * user can choose to do not use text stroke.
  151. * @type {number}
  152. */
  153. textStrokeWidth: 0,
  154. /**
  155. * @type {number}
  156. */
  157. textLineHeight: null,
  158. /**
  159. * 'inside', 'left', 'right', 'top', 'bottom'
  160. * [x, y]
  161. * Based on x, y of rect.
  162. * @type {string|Array.<number>}
  163. * @default 'inside'
  164. */
  165. textPosition: 'inside',
  166. /**
  167. * If not specified, use the boundingRect of a `displayable`.
  168. * @type {Object}
  169. */
  170. textRect: null,
  171. /**
  172. * [x, y]
  173. * @type {Array.<number>}
  174. */
  175. textOffset: null,
  176. /**
  177. * @type {string}
  178. */
  179. textAlign: null,
  180. /**
  181. * @type {string}
  182. */
  183. textVerticalAlign: null,
  184. /**
  185. * @type {number}
  186. */
  187. textDistance: 5,
  188. /**
  189. * @type {string}
  190. */
  191. textShadowColor: 'transparent',
  192. /**
  193. * @type {number}
  194. */
  195. textShadowBlur: 0,
  196. /**
  197. * @type {number}
  198. */
  199. textShadowOffsetX: 0,
  200. /**
  201. * @type {number}
  202. */
  203. textShadowOffsetY: 0,
  204. /**
  205. * @type {string}
  206. */
  207. textBoxShadowColor: 'transparent',
  208. /**
  209. * @type {number}
  210. */
  211. textBoxShadowBlur: 0,
  212. /**
  213. * @type {number}
  214. */
  215. textBoxShadowOffsetX: 0,
  216. /**
  217. * @type {number}
  218. */
  219. textBoxShadowOffsetY: 0,
  220. /**
  221. * Whether transform text.
  222. * Only useful in Path and Image element
  223. * @type {boolean}
  224. */
  225. transformText: false,
  226. /**
  227. * Text rotate around position of Path or Image
  228. * Only useful in Path and Image element and transformText is false.
  229. */
  230. textRotation: 0,
  231. /**
  232. * Text origin of text rotation, like [10, 40].
  233. * Based on x, y of rect.
  234. * Useful in label rotation of circular symbol.
  235. * By default, this origin is textPosition.
  236. * Can be 'center'.
  237. * @type {string|Array.<number>}
  238. */
  239. textOrigin: null,
  240. /**
  241. * @type {string}
  242. */
  243. textBackgroundColor: null,
  244. /**
  245. * @type {string}
  246. */
  247. textBorderColor: null,
  248. /**
  249. * @type {number}
  250. */
  251. textBorderWidth: 0,
  252. /**
  253. * @type {number}
  254. */
  255. textBorderRadius: 0,
  256. /**
  257. * Can be `2` or `[2, 4]` or `[2, 3, 4, 5]`
  258. * @type {number|Array.<number>}
  259. */
  260. textPadding: null,
  261. /**
  262. * Text styles for rich text.
  263. * @type {Object}
  264. */
  265. rich: null,
  266. /**
  267. * {outerWidth, outerHeight, ellipsis, placeholder}
  268. * @type {Object}
  269. */
  270. truncate: null,
  271. /**
  272. * https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/globalCompositeOperation
  273. * @type {string}
  274. */
  275. blend: null,
  276. /**
  277. * @param {CanvasRenderingContext2D} ctx
  278. */
  279. bind: function (ctx, el, prevEl) {
  280. var style = this;
  281. var prevStyle = prevEl && prevEl.style;
  282. var firstDraw = !prevStyle;
  283. for (var i = 0; i < STYLE_COMMON_PROPS.length; i++) {
  284. var prop = STYLE_COMMON_PROPS[i];
  285. var styleName = prop[0];
  286. if (firstDraw || style[styleName] !== prevStyle[styleName]) {
  287. // FIXME Invalid property value will cause style leak from previous element.
  288. ctx[styleName] = style[styleName] || prop[1];
  289. }
  290. }
  291. if (firstDraw || style.fill !== prevStyle.fill) {
  292. ctx.fillStyle = style.fill;
  293. }
  294. if (firstDraw || style.stroke !== prevStyle.stroke) {
  295. ctx.strokeStyle = style.stroke;
  296. }
  297. if (firstDraw || style.opacity !== prevStyle.opacity) {
  298. ctx.globalAlpha = style.opacity == null ? 1 : style.opacity;
  299. }
  300. if (firstDraw || style.blend !== prevStyle.blend) {
  301. ctx.globalCompositeOperation = style.blend || 'source-over';
  302. }
  303. if (this.hasStroke()) {
  304. var lineWidth = style.lineWidth;
  305. ctx.lineWidth = lineWidth / (this.strokeNoScale && el && el.getLineScale ? el.getLineScale() : 1);
  306. }
  307. },
  308. hasFill: function () {
  309. var fill = this.fill;
  310. return fill != null && fill !== 'none';
  311. },
  312. hasStroke: function () {
  313. var stroke = this.stroke;
  314. return stroke != null && stroke !== 'none' && this.lineWidth > 0;
  315. },
  316. /**
  317. * Extend from other style
  318. * @param {zrender/graphic/Style} otherStyle
  319. * @param {boolean} overwrite true: overwrirte any way.
  320. * false: overwrite only when !target.hasOwnProperty
  321. * others: overwrite when property is not null/undefined.
  322. */
  323. extendFrom: function (otherStyle, overwrite) {
  324. if (otherStyle) {
  325. for (var name in otherStyle) {
  326. if (otherStyle.hasOwnProperty(name) && (overwrite === true || (overwrite === false ? !this.hasOwnProperty(name) : otherStyle[name] != null))) {
  327. this[name] = otherStyle[name];
  328. }
  329. }
  330. }
  331. },
  332. /**
  333. * Batch setting style with a given object
  334. * @param {Object|string} obj
  335. * @param {*} [obj]
  336. */
  337. set: function (obj, value) {
  338. if (typeof obj === 'string') {
  339. this[obj] = value;
  340. } else {
  341. this.extendFrom(obj, true);
  342. }
  343. },
  344. /**
  345. * Clone
  346. * @return {zrender/graphic/Style} [description]
  347. */
  348. clone: function () {
  349. var newStyle = new this.constructor();
  350. newStyle.extendFrom(this, true);
  351. return newStyle;
  352. },
  353. getGradient: function (ctx, obj, rect) {
  354. var method = obj.type === 'radial' ? createRadialGradient : createLinearGradient;
  355. var canvasGradient = method(ctx, obj, rect);
  356. var colorStops = obj.colorStops;
  357. for (var i = 0; i < colorStops.length; i++) {
  358. canvasGradient.addColorStop(colorStops[i].offset, colorStops[i].color);
  359. }
  360. return canvasGradient;
  361. }
  362. };
  363. var styleProto = Style.prototype;
  364. for (var i = 0; i < STYLE_COMMON_PROPS.length; i++) {
  365. var prop = STYLE_COMMON_PROPS[i];
  366. if (!(prop[0] in styleProto)) {
  367. styleProto[prop[0]] = prop[1];
  368. }
  369. } // Provide for others
  370. Style.getGradient = styleProto.getGradient;
  371. var _default = Style;
  372. module.exports = _default;