Displayable.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  1. import { __extends } from "tslib";
  2. import Element from '../Element.js';
  3. import BoundingRect from '../core/BoundingRect.js';
  4. import { keys, extend, createObject } from '../core/util.js';
  5. import { REDRAW_BIT, STYLE_CHANGED_BIT } from './constants.js';
  6. var STYLE_MAGIC_KEY = '__zr_style_' + Math.round((Math.random() * 10));
  7. export var DEFAULT_COMMON_STYLE = {
  8. shadowBlur: 0,
  9. shadowOffsetX: 0,
  10. shadowOffsetY: 0,
  11. shadowColor: '#000',
  12. opacity: 1,
  13. blend: 'source-over'
  14. };
  15. export var DEFAULT_COMMON_ANIMATION_PROPS = {
  16. style: {
  17. shadowBlur: true,
  18. shadowOffsetX: true,
  19. shadowOffsetY: true,
  20. shadowColor: true,
  21. opacity: true
  22. }
  23. };
  24. DEFAULT_COMMON_STYLE[STYLE_MAGIC_KEY] = true;
  25. var PRIMARY_STATES_KEYS = ['z', 'z2', 'invisible'];
  26. var PRIMARY_STATES_KEYS_IN_HOVER_LAYER = ['invisible'];
  27. var Displayable = (function (_super) {
  28. __extends(Displayable, _super);
  29. function Displayable(props) {
  30. return _super.call(this, props) || this;
  31. }
  32. Displayable.prototype._init = function (props) {
  33. var keysArr = keys(props);
  34. for (var i = 0; i < keysArr.length; i++) {
  35. var key = keysArr[i];
  36. if (key === 'style') {
  37. this.useStyle(props[key]);
  38. }
  39. else {
  40. _super.prototype.attrKV.call(this, key, props[key]);
  41. }
  42. }
  43. if (!this.style) {
  44. this.useStyle({});
  45. }
  46. };
  47. Displayable.prototype.beforeBrush = function () { };
  48. Displayable.prototype.afterBrush = function () { };
  49. Displayable.prototype.innerBeforeBrush = function () { };
  50. Displayable.prototype.innerAfterBrush = function () { };
  51. Displayable.prototype.shouldBePainted = function (viewWidth, viewHeight, considerClipPath, considerAncestors) {
  52. var m = this.transform;
  53. if (this.ignore
  54. || this.invisible
  55. || this.style.opacity === 0
  56. || (this.culling
  57. && isDisplayableCulled(this, viewWidth, viewHeight))
  58. || (m && !m[0] && !m[3])) {
  59. return false;
  60. }
  61. if (considerClipPath && this.__clipPaths) {
  62. for (var i = 0; i < this.__clipPaths.length; ++i) {
  63. if (this.__clipPaths[i].isZeroArea()) {
  64. return false;
  65. }
  66. }
  67. }
  68. if (considerAncestors && this.parent) {
  69. var parent_1 = this.parent;
  70. while (parent_1) {
  71. if (parent_1.ignore) {
  72. return false;
  73. }
  74. parent_1 = parent_1.parent;
  75. }
  76. }
  77. return true;
  78. };
  79. Displayable.prototype.contain = function (x, y) {
  80. return this.rectContain(x, y);
  81. };
  82. Displayable.prototype.traverse = function (cb, context) {
  83. cb.call(context, this);
  84. };
  85. Displayable.prototype.rectContain = function (x, y) {
  86. var coord = this.transformCoordToLocal(x, y);
  87. var rect = this.getBoundingRect();
  88. return rect.contain(coord[0], coord[1]);
  89. };
  90. Displayable.prototype.getPaintRect = function () {
  91. var rect = this._paintRect;
  92. if (!this._paintRect || this.__dirty) {
  93. var transform = this.transform;
  94. var elRect = this.getBoundingRect();
  95. var style = this.style;
  96. var shadowSize = style.shadowBlur || 0;
  97. var shadowOffsetX = style.shadowOffsetX || 0;
  98. var shadowOffsetY = style.shadowOffsetY || 0;
  99. rect = this._paintRect || (this._paintRect = new BoundingRect(0, 0, 0, 0));
  100. if (transform) {
  101. BoundingRect.applyTransform(rect, elRect, transform);
  102. }
  103. else {
  104. rect.copy(elRect);
  105. }
  106. if (shadowSize || shadowOffsetX || shadowOffsetY) {
  107. rect.width += shadowSize * 2 + Math.abs(shadowOffsetX);
  108. rect.height += shadowSize * 2 + Math.abs(shadowOffsetY);
  109. rect.x = Math.min(rect.x, rect.x + shadowOffsetX - shadowSize);
  110. rect.y = Math.min(rect.y, rect.y + shadowOffsetY - shadowSize);
  111. }
  112. var tolerance = this.dirtyRectTolerance;
  113. if (!rect.isZero()) {
  114. rect.x = Math.floor(rect.x - tolerance);
  115. rect.y = Math.floor(rect.y - tolerance);
  116. rect.width = Math.ceil(rect.width + 1 + tolerance * 2);
  117. rect.height = Math.ceil(rect.height + 1 + tolerance * 2);
  118. }
  119. }
  120. return rect;
  121. };
  122. Displayable.prototype.setPrevPaintRect = function (paintRect) {
  123. if (paintRect) {
  124. this._prevPaintRect = this._prevPaintRect || new BoundingRect(0, 0, 0, 0);
  125. this._prevPaintRect.copy(paintRect);
  126. }
  127. else {
  128. this._prevPaintRect = null;
  129. }
  130. };
  131. Displayable.prototype.getPrevPaintRect = function () {
  132. return this._prevPaintRect;
  133. };
  134. Displayable.prototype.animateStyle = function (loop) {
  135. return this.animate('style', loop);
  136. };
  137. Displayable.prototype.updateDuringAnimation = function (targetKey) {
  138. if (targetKey === 'style') {
  139. this.dirtyStyle();
  140. }
  141. else {
  142. this.markRedraw();
  143. }
  144. };
  145. Displayable.prototype.attrKV = function (key, value) {
  146. if (key !== 'style') {
  147. _super.prototype.attrKV.call(this, key, value);
  148. }
  149. else {
  150. if (!this.style) {
  151. this.useStyle(value);
  152. }
  153. else {
  154. this.setStyle(value);
  155. }
  156. }
  157. };
  158. Displayable.prototype.setStyle = function (keyOrObj, value) {
  159. if (typeof keyOrObj === 'string') {
  160. this.style[keyOrObj] = value;
  161. }
  162. else {
  163. extend(this.style, keyOrObj);
  164. }
  165. this.dirtyStyle();
  166. return this;
  167. };
  168. Displayable.prototype.dirtyStyle = function (notRedraw) {
  169. if (!notRedraw) {
  170. this.markRedraw();
  171. }
  172. this.__dirty |= STYLE_CHANGED_BIT;
  173. if (this._rect) {
  174. this._rect = null;
  175. }
  176. };
  177. Displayable.prototype.dirty = function () {
  178. this.dirtyStyle();
  179. };
  180. Displayable.prototype.styleChanged = function () {
  181. return !!(this.__dirty & STYLE_CHANGED_BIT);
  182. };
  183. Displayable.prototype.styleUpdated = function () {
  184. this.__dirty &= ~STYLE_CHANGED_BIT;
  185. };
  186. Displayable.prototype.createStyle = function (obj) {
  187. return createObject(DEFAULT_COMMON_STYLE, obj);
  188. };
  189. Displayable.prototype.useStyle = function (obj) {
  190. if (!obj[STYLE_MAGIC_KEY]) {
  191. obj = this.createStyle(obj);
  192. }
  193. if (this.__inHover) {
  194. this.__hoverStyle = obj;
  195. }
  196. else {
  197. this.style = obj;
  198. }
  199. this.dirtyStyle();
  200. };
  201. Displayable.prototype.isStyleObject = function (obj) {
  202. return obj[STYLE_MAGIC_KEY];
  203. };
  204. Displayable.prototype._innerSaveToNormal = function (toState) {
  205. _super.prototype._innerSaveToNormal.call(this, toState);
  206. var normalState = this._normalState;
  207. if (toState.style && !normalState.style) {
  208. normalState.style = this._mergeStyle(this.createStyle(), this.style);
  209. }
  210. this._savePrimaryToNormal(toState, normalState, PRIMARY_STATES_KEYS);
  211. };
  212. Displayable.prototype._applyStateObj = function (stateName, state, normalState, keepCurrentStates, transition, animationCfg) {
  213. _super.prototype._applyStateObj.call(this, stateName, state, normalState, keepCurrentStates, transition, animationCfg);
  214. var needsRestoreToNormal = !(state && keepCurrentStates);
  215. var targetStyle;
  216. if (state && state.style) {
  217. if (transition) {
  218. if (keepCurrentStates) {
  219. targetStyle = state.style;
  220. }
  221. else {
  222. targetStyle = this._mergeStyle(this.createStyle(), normalState.style);
  223. this._mergeStyle(targetStyle, state.style);
  224. }
  225. }
  226. else {
  227. targetStyle = this._mergeStyle(this.createStyle(), keepCurrentStates ? this.style : normalState.style);
  228. this._mergeStyle(targetStyle, state.style);
  229. }
  230. }
  231. else if (needsRestoreToNormal) {
  232. targetStyle = normalState.style;
  233. }
  234. if (targetStyle) {
  235. if (transition) {
  236. var sourceStyle = this.style;
  237. this.style = this.createStyle(needsRestoreToNormal ? {} : sourceStyle);
  238. if (needsRestoreToNormal) {
  239. var changedKeys = keys(sourceStyle);
  240. for (var i = 0; i < changedKeys.length; i++) {
  241. var key = changedKeys[i];
  242. if (key in targetStyle) {
  243. targetStyle[key] = targetStyle[key];
  244. this.style[key] = sourceStyle[key];
  245. }
  246. }
  247. }
  248. var targetKeys = keys(targetStyle);
  249. for (var i = 0; i < targetKeys.length; i++) {
  250. var key = targetKeys[i];
  251. this.style[key] = this.style[key];
  252. }
  253. this._transitionState(stateName, {
  254. style: targetStyle
  255. }, animationCfg, this.getAnimationStyleProps());
  256. }
  257. else {
  258. this.useStyle(targetStyle);
  259. }
  260. }
  261. var statesKeys = this.__inHover ? PRIMARY_STATES_KEYS_IN_HOVER_LAYER : PRIMARY_STATES_KEYS;
  262. for (var i = 0; i < statesKeys.length; i++) {
  263. var key = statesKeys[i];
  264. if (state && state[key] != null) {
  265. this[key] = state[key];
  266. }
  267. else if (needsRestoreToNormal) {
  268. if (normalState[key] != null) {
  269. this[key] = normalState[key];
  270. }
  271. }
  272. }
  273. };
  274. Displayable.prototype._mergeStates = function (states) {
  275. var mergedState = _super.prototype._mergeStates.call(this, states);
  276. var mergedStyle;
  277. for (var i = 0; i < states.length; i++) {
  278. var state = states[i];
  279. if (state.style) {
  280. mergedStyle = mergedStyle || {};
  281. this._mergeStyle(mergedStyle, state.style);
  282. }
  283. }
  284. if (mergedStyle) {
  285. mergedState.style = mergedStyle;
  286. }
  287. return mergedState;
  288. };
  289. Displayable.prototype._mergeStyle = function (targetStyle, sourceStyle) {
  290. extend(targetStyle, sourceStyle);
  291. return targetStyle;
  292. };
  293. Displayable.prototype.getAnimationStyleProps = function () {
  294. return DEFAULT_COMMON_ANIMATION_PROPS;
  295. };
  296. Displayable.initDefaultProps = (function () {
  297. var dispProto = Displayable.prototype;
  298. dispProto.type = 'displayable';
  299. dispProto.invisible = false;
  300. dispProto.z = 0;
  301. dispProto.z2 = 0;
  302. dispProto.zlevel = 0;
  303. dispProto.culling = false;
  304. dispProto.cursor = 'pointer';
  305. dispProto.rectHover = false;
  306. dispProto.incremental = false;
  307. dispProto._rect = null;
  308. dispProto.dirtyRectTolerance = 0;
  309. dispProto.__dirty = REDRAW_BIT | STYLE_CHANGED_BIT;
  310. })();
  311. return Displayable;
  312. }(Element));
  313. var tmpRect = new BoundingRect(0, 0, 0, 0);
  314. var viewRect = new BoundingRect(0, 0, 0, 0);
  315. function isDisplayableCulled(el, width, height) {
  316. tmpRect.copy(el.getBoundingRect());
  317. if (el.transform) {
  318. tmpRect.applyTransform(el.transform);
  319. }
  320. viewRect.width = width;
  321. viewRect.height = height;
  322. return !tmpRect.intersect(viewRect);
  323. }
  324. export default Displayable;