Element.js 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008
  1. import Transformable from './core/Transformable';
  2. import Animator, { cloneValue } from './animation/Animator';
  3. import BoundingRect from './core/BoundingRect';
  4. import Eventful from './core/Eventful';
  5. import { calculateTextPosition, parsePercent } from './contain/text';
  6. import { guid, isObject, keys, extend, indexOf, logError, mixin, isArrayLike, isTypedArray } from './core/util';
  7. import { LIGHT_LABEL_COLOR, DARK_LABEL_COLOR } from './config';
  8. import { parse, stringify } from './tool/color';
  9. import env from './core/env';
  10. import { REDRAW_BIT } from './graphic/constants';
  11. export var PRESERVED_NORMAL_STATE = '__zr_normal__';
  12. var PRIMARY_STATES_KEYS = ['x', 'y', 'scaleX', 'scaleY', 'originX', 'originY', 'rotation', 'ignore'];
  13. var DEFAULT_ANIMATABLE_MAP = {
  14. x: true,
  15. y: true,
  16. scaleX: true,
  17. scaleY: true,
  18. originX: true,
  19. originY: true,
  20. rotation: true,
  21. ignore: false
  22. };
  23. var tmpTextPosCalcRes = {};
  24. var tmpBoundingRect = new BoundingRect(0, 0, 0, 0);
  25. var Element = (function () {
  26. function Element(props) {
  27. this.id = guid();
  28. this.animators = [];
  29. this.currentStates = [];
  30. this.states = {};
  31. this._init(props);
  32. }
  33. Element.prototype._init = function (props) {
  34. this.attr(props);
  35. };
  36. Element.prototype.drift = function (dx, dy, e) {
  37. switch (this.draggable) {
  38. case 'horizontal':
  39. dy = 0;
  40. break;
  41. case 'vertical':
  42. dx = 0;
  43. break;
  44. }
  45. var m = this.transform;
  46. if (!m) {
  47. m = this.transform = [1, 0, 0, 1, 0, 0];
  48. }
  49. m[4] += dx;
  50. m[5] += dy;
  51. this.decomposeTransform();
  52. this.markRedraw();
  53. };
  54. Element.prototype.beforeUpdate = function () { };
  55. Element.prototype.afterUpdate = function () { };
  56. Element.prototype.update = function () {
  57. this.updateTransform();
  58. if (this.__dirty) {
  59. this.updateInnerText();
  60. }
  61. };
  62. Element.prototype.updateInnerText = function (forceUpdate) {
  63. var textEl = this._textContent;
  64. if (textEl && (!textEl.ignore || forceUpdate)) {
  65. if (!this.textConfig) {
  66. this.textConfig = {};
  67. }
  68. var textConfig = this.textConfig;
  69. var isLocal = textConfig.local;
  70. var innerTransformable = textEl.innerTransformable;
  71. var textAlign = void 0;
  72. var textVerticalAlign = void 0;
  73. var textStyleChanged = false;
  74. innerTransformable.parent = isLocal ? this : null;
  75. var innerOrigin = false;
  76. innerTransformable.copyTransform(textEl);
  77. if (textConfig.position != null) {
  78. var layoutRect = tmpBoundingRect;
  79. if (textConfig.layoutRect) {
  80. layoutRect.copy(textConfig.layoutRect);
  81. }
  82. else {
  83. layoutRect.copy(this.getBoundingRect());
  84. }
  85. if (!isLocal) {
  86. layoutRect.applyTransform(this.transform);
  87. }
  88. if (this.calculateTextPosition) {
  89. this.calculateTextPosition(tmpTextPosCalcRes, textConfig, layoutRect);
  90. }
  91. else {
  92. calculateTextPosition(tmpTextPosCalcRes, textConfig, layoutRect);
  93. }
  94. innerTransformable.x = tmpTextPosCalcRes.x;
  95. innerTransformable.y = tmpTextPosCalcRes.y;
  96. textAlign = tmpTextPosCalcRes.align;
  97. textVerticalAlign = tmpTextPosCalcRes.verticalAlign;
  98. var textOrigin = textConfig.origin;
  99. if (textOrigin && textConfig.rotation != null) {
  100. var relOriginX = void 0;
  101. var relOriginY = void 0;
  102. if (textOrigin === 'center') {
  103. relOriginX = layoutRect.width * 0.5;
  104. relOriginY = layoutRect.height * 0.5;
  105. }
  106. else {
  107. relOriginX = parsePercent(textOrigin[0], layoutRect.width);
  108. relOriginY = parsePercent(textOrigin[1], layoutRect.height);
  109. }
  110. innerOrigin = true;
  111. innerTransformable.originX = -innerTransformable.x + relOriginX + (isLocal ? 0 : layoutRect.x);
  112. innerTransformable.originY = -innerTransformable.y + relOriginY + (isLocal ? 0 : layoutRect.y);
  113. }
  114. }
  115. if (textConfig.rotation != null) {
  116. innerTransformable.rotation = textConfig.rotation;
  117. }
  118. var textOffset = textConfig.offset;
  119. if (textOffset) {
  120. innerTransformable.x += textOffset[0];
  121. innerTransformable.y += textOffset[1];
  122. if (!innerOrigin) {
  123. innerTransformable.originX = -textOffset[0];
  124. innerTransformable.originY = -textOffset[1];
  125. }
  126. }
  127. var isInside = textConfig.inside == null
  128. ? (typeof textConfig.position === 'string' && textConfig.position.indexOf('inside') >= 0)
  129. : textConfig.inside;
  130. var innerTextDefaultStyle = this._innerTextDefaultStyle || (this._innerTextDefaultStyle = {});
  131. var textFill = void 0;
  132. var textStroke = void 0;
  133. var autoStroke = void 0;
  134. if (isInside && this.canBeInsideText()) {
  135. textFill = textConfig.insideFill;
  136. textStroke = textConfig.insideStroke;
  137. if (textFill == null || textFill === 'auto') {
  138. textFill = this.getInsideTextFill();
  139. }
  140. if (textStroke == null || textStroke === 'auto') {
  141. textStroke = this.getInsideTextStroke(textFill);
  142. autoStroke = true;
  143. }
  144. }
  145. else {
  146. textFill = textConfig.outsideFill;
  147. textStroke = textConfig.outsideStroke;
  148. if (textFill == null || textFill === 'auto') {
  149. textFill = this.getOutsideFill();
  150. }
  151. if (textStroke == null || textStroke === 'auto') {
  152. textStroke = this.getOutsideStroke(textFill);
  153. autoStroke = true;
  154. }
  155. }
  156. textFill = textFill || '#000';
  157. if (textFill !== innerTextDefaultStyle.fill
  158. || textStroke !== innerTextDefaultStyle.stroke
  159. || autoStroke !== innerTextDefaultStyle.autoStroke
  160. || textAlign !== innerTextDefaultStyle.align
  161. || textVerticalAlign !== innerTextDefaultStyle.verticalAlign) {
  162. textStyleChanged = true;
  163. innerTextDefaultStyle.fill = textFill;
  164. innerTextDefaultStyle.stroke = textStroke;
  165. innerTextDefaultStyle.autoStroke = autoStroke;
  166. innerTextDefaultStyle.align = textAlign;
  167. innerTextDefaultStyle.verticalAlign = textVerticalAlign;
  168. textEl.setDefaultTextStyle(innerTextDefaultStyle);
  169. }
  170. textEl.__dirty |= REDRAW_BIT;
  171. if (textStyleChanged) {
  172. textEl.dirtyStyle(true);
  173. }
  174. }
  175. };
  176. Element.prototype.canBeInsideText = function () {
  177. return true;
  178. };
  179. Element.prototype.getInsideTextFill = function () {
  180. return '#fff';
  181. };
  182. Element.prototype.getInsideTextStroke = function (textFill) {
  183. return '#000';
  184. };
  185. Element.prototype.getOutsideFill = function () {
  186. return this.__zr && this.__zr.isDarkMode() ? LIGHT_LABEL_COLOR : DARK_LABEL_COLOR;
  187. };
  188. Element.prototype.getOutsideStroke = function (textFill) {
  189. var backgroundColor = this.__zr && this.__zr.getBackgroundColor();
  190. var colorArr = typeof backgroundColor === 'string' && parse(backgroundColor);
  191. if (!colorArr) {
  192. colorArr = [255, 255, 255, 1];
  193. }
  194. var alpha = colorArr[3];
  195. var isDark = this.__zr.isDarkMode();
  196. for (var i = 0; i < 3; i++) {
  197. colorArr[i] = colorArr[i] * alpha + (isDark ? 0 : 255) * (1 - alpha);
  198. }
  199. colorArr[3] = 1;
  200. return stringify(colorArr, 'rgba');
  201. };
  202. Element.prototype.traverse = function (cb, context) { };
  203. Element.prototype.attrKV = function (key, value) {
  204. if (key === 'textConfig') {
  205. this.setTextConfig(value);
  206. }
  207. else if (key === 'textContent') {
  208. this.setTextContent(value);
  209. }
  210. else if (key === 'clipPath') {
  211. this.setClipPath(value);
  212. }
  213. else if (key === 'extra') {
  214. this.extra = this.extra || {};
  215. extend(this.extra, value);
  216. }
  217. else {
  218. this[key] = value;
  219. }
  220. };
  221. Element.prototype.hide = function () {
  222. this.ignore = true;
  223. this.markRedraw();
  224. };
  225. Element.prototype.show = function () {
  226. this.ignore = false;
  227. this.markRedraw();
  228. };
  229. Element.prototype.attr = function (keyOrObj, value) {
  230. if (typeof keyOrObj === 'string') {
  231. this.attrKV(keyOrObj, value);
  232. }
  233. else if (isObject(keyOrObj)) {
  234. var obj = keyOrObj;
  235. var keysArr = keys(obj);
  236. for (var i = 0; i < keysArr.length; i++) {
  237. var key = keysArr[i];
  238. this.attrKV(key, keyOrObj[key]);
  239. }
  240. }
  241. this.markRedraw();
  242. return this;
  243. };
  244. Element.prototype.saveCurrentToNormalState = function (toState) {
  245. this._innerSaveToNormal(toState);
  246. var normalState = this._normalState;
  247. for (var i = 0; i < this.animators.length; i++) {
  248. var animator = this.animators[i];
  249. var fromStateTransition = animator.__fromStateTransition;
  250. if (fromStateTransition && fromStateTransition !== PRESERVED_NORMAL_STATE) {
  251. continue;
  252. }
  253. var targetName = animator.targetName;
  254. var target = targetName
  255. ? normalState[targetName] : normalState;
  256. animator.saveFinalToTarget(target);
  257. }
  258. };
  259. Element.prototype._innerSaveToNormal = function (toState) {
  260. var normalState = this._normalState;
  261. if (!normalState) {
  262. normalState = this._normalState = {};
  263. }
  264. if (toState.textConfig && !normalState.textConfig) {
  265. normalState.textConfig = this.textConfig;
  266. }
  267. this._savePrimaryToNormal(toState, normalState, PRIMARY_STATES_KEYS);
  268. };
  269. Element.prototype._savePrimaryToNormal = function (toState, normalState, primaryKeys) {
  270. for (var i = 0; i < primaryKeys.length; i++) {
  271. var key = primaryKeys[i];
  272. if (toState[key] != null && !(key in normalState)) {
  273. normalState[key] = this[key];
  274. }
  275. }
  276. };
  277. Element.prototype.hasState = function () {
  278. return this.currentStates.length > 0;
  279. };
  280. Element.prototype.getState = function (name) {
  281. return this.states[name];
  282. };
  283. Element.prototype.ensureState = function (name) {
  284. var states = this.states;
  285. if (!states[name]) {
  286. states[name] = {};
  287. }
  288. return states[name];
  289. };
  290. Element.prototype.clearStates = function (noAnimation) {
  291. this.useState(PRESERVED_NORMAL_STATE, false, noAnimation);
  292. };
  293. Element.prototype.useState = function (stateName, keepCurrentStates, noAnimation, forceUseHoverLayer) {
  294. var toNormalState = stateName === PRESERVED_NORMAL_STATE;
  295. var hasStates = this.hasState();
  296. if (!hasStates && toNormalState) {
  297. return;
  298. }
  299. var currentStates = this.currentStates;
  300. var animationCfg = this.stateTransition;
  301. if (indexOf(currentStates, stateName) >= 0 && (keepCurrentStates || currentStates.length === 1)) {
  302. return;
  303. }
  304. var state;
  305. if (this.stateProxy && !toNormalState) {
  306. state = this.stateProxy(stateName);
  307. }
  308. if (!state) {
  309. state = (this.states && this.states[stateName]);
  310. }
  311. if (!state && !toNormalState) {
  312. logError("State " + stateName + " not exists.");
  313. return;
  314. }
  315. if (!toNormalState) {
  316. this.saveCurrentToNormalState(state);
  317. }
  318. var useHoverLayer = !!((state && state.hoverLayer) || forceUseHoverLayer);
  319. if (useHoverLayer) {
  320. this._toggleHoverLayerFlag(true);
  321. }
  322. this._applyStateObj(stateName, state, this._normalState, keepCurrentStates, !noAnimation && !this.__inHover && animationCfg && animationCfg.duration > 0, animationCfg);
  323. var textContent = this._textContent;
  324. var textGuide = this._textGuide;
  325. if (textContent) {
  326. textContent.useState(stateName, keepCurrentStates, noAnimation, useHoverLayer);
  327. }
  328. if (textGuide) {
  329. textGuide.useState(stateName, keepCurrentStates, noAnimation, useHoverLayer);
  330. }
  331. if (toNormalState) {
  332. this.currentStates = [];
  333. this._normalState = {};
  334. }
  335. else {
  336. if (!keepCurrentStates) {
  337. this.currentStates = [stateName];
  338. }
  339. else {
  340. this.currentStates.push(stateName);
  341. }
  342. }
  343. this._updateAnimationTargets();
  344. this.markRedraw();
  345. if (!useHoverLayer && this.__inHover) {
  346. this._toggleHoverLayerFlag(false);
  347. this.__dirty &= ~REDRAW_BIT;
  348. }
  349. return state;
  350. };
  351. Element.prototype.useStates = function (states, noAnimation, forceUseHoverLayer) {
  352. if (!states.length) {
  353. this.clearStates();
  354. }
  355. else {
  356. var stateObjects = [];
  357. var currentStates = this.currentStates;
  358. var len = states.length;
  359. var notChange = len === currentStates.length;
  360. if (notChange) {
  361. for (var i = 0; i < len; i++) {
  362. if (states[i] !== currentStates[i]) {
  363. notChange = false;
  364. break;
  365. }
  366. }
  367. }
  368. if (notChange) {
  369. return;
  370. }
  371. for (var i = 0; i < len; i++) {
  372. var stateName = states[i];
  373. var stateObj = void 0;
  374. if (this.stateProxy) {
  375. stateObj = this.stateProxy(stateName, states);
  376. }
  377. if (!stateObj) {
  378. stateObj = this.states[stateName];
  379. }
  380. if (stateObj) {
  381. stateObjects.push(stateObj);
  382. }
  383. }
  384. var lastStateObj = stateObjects[len - 1];
  385. var useHoverLayer = !!((lastStateObj && lastStateObj.hoverLayer) || forceUseHoverLayer);
  386. if (useHoverLayer) {
  387. this._toggleHoverLayerFlag(true);
  388. }
  389. var mergedState = this._mergeStates(stateObjects);
  390. var animationCfg = this.stateTransition;
  391. this.saveCurrentToNormalState(mergedState);
  392. this._applyStateObj(states.join(','), mergedState, this._normalState, false, !noAnimation && !this.__inHover && animationCfg && animationCfg.duration > 0, animationCfg);
  393. var textContent = this._textContent;
  394. var textGuide = this._textGuide;
  395. if (textContent) {
  396. textContent.useStates(states, noAnimation, useHoverLayer);
  397. }
  398. if (textGuide) {
  399. textGuide.useStates(states, noAnimation, useHoverLayer);
  400. }
  401. this._updateAnimationTargets();
  402. this.currentStates = states.slice();
  403. this.markRedraw();
  404. if (!useHoverLayer && this.__inHover) {
  405. this._toggleHoverLayerFlag(false);
  406. this.__dirty &= ~REDRAW_BIT;
  407. }
  408. }
  409. };
  410. Element.prototype._updateAnimationTargets = function () {
  411. for (var i = 0; i < this.animators.length; i++) {
  412. var animator = this.animators[i];
  413. if (animator.targetName) {
  414. animator.changeTarget(this[animator.targetName]);
  415. }
  416. }
  417. };
  418. Element.prototype.removeState = function (state) {
  419. var idx = indexOf(this.currentStates, state);
  420. if (idx >= 0) {
  421. var currentStates = this.currentStates.slice();
  422. currentStates.splice(idx, 1);
  423. this.useStates(currentStates);
  424. }
  425. };
  426. Element.prototype.replaceState = function (oldState, newState, forceAdd) {
  427. var currentStates = this.currentStates.slice();
  428. var idx = indexOf(currentStates, oldState);
  429. var newStateExists = indexOf(currentStates, newState) >= 0;
  430. if (idx >= 0) {
  431. if (!newStateExists) {
  432. currentStates[idx] = newState;
  433. }
  434. else {
  435. currentStates.splice(idx, 1);
  436. }
  437. }
  438. else if (forceAdd && !newStateExists) {
  439. currentStates.push(newState);
  440. }
  441. this.useStates(currentStates);
  442. };
  443. Element.prototype.toggleState = function (state, enable) {
  444. if (enable) {
  445. this.useState(state, true);
  446. }
  447. else {
  448. this.removeState(state);
  449. }
  450. };
  451. Element.prototype._mergeStates = function (states) {
  452. var mergedState = {};
  453. var mergedTextConfig;
  454. for (var i = 0; i < states.length; i++) {
  455. var state = states[i];
  456. extend(mergedState, state);
  457. if (state.textConfig) {
  458. mergedTextConfig = mergedTextConfig || {};
  459. extend(mergedTextConfig, state.textConfig);
  460. }
  461. }
  462. if (mergedTextConfig) {
  463. mergedState.textConfig = mergedTextConfig;
  464. }
  465. return mergedState;
  466. };
  467. Element.prototype._applyStateObj = function (stateName, state, normalState, keepCurrentStates, transition, animationCfg) {
  468. var needsRestoreToNormal = !(state && keepCurrentStates);
  469. if (state && state.textConfig) {
  470. this.textConfig = extend({}, keepCurrentStates ? this.textConfig : normalState.textConfig);
  471. extend(this.textConfig, state.textConfig);
  472. }
  473. else if (needsRestoreToNormal) {
  474. if (normalState.textConfig) {
  475. this.textConfig = normalState.textConfig;
  476. }
  477. }
  478. var transitionTarget = {};
  479. var hasTransition = false;
  480. for (var i = 0; i < PRIMARY_STATES_KEYS.length; i++) {
  481. var key = PRIMARY_STATES_KEYS[i];
  482. var propNeedsTransition = transition && DEFAULT_ANIMATABLE_MAP[key];
  483. if (state && state[key] != null) {
  484. if (propNeedsTransition) {
  485. hasTransition = true;
  486. transitionTarget[key] = state[key];
  487. }
  488. else {
  489. this[key] = state[key];
  490. }
  491. }
  492. else if (needsRestoreToNormal) {
  493. if (normalState[key] != null) {
  494. if (propNeedsTransition) {
  495. hasTransition = true;
  496. transitionTarget[key] = normalState[key];
  497. }
  498. else {
  499. this[key] = normalState[key];
  500. }
  501. }
  502. }
  503. }
  504. if (!transition) {
  505. for (var i = 0; i < this.animators.length; i++) {
  506. var animator = this.animators[i];
  507. var targetName = animator.targetName;
  508. animator.__changeFinalValue(targetName
  509. ? (state || normalState)[targetName]
  510. : (state || normalState));
  511. }
  512. }
  513. if (hasTransition) {
  514. this._transitionState(stateName, transitionTarget, animationCfg);
  515. }
  516. };
  517. Element.prototype._attachComponent = function (componentEl) {
  518. if (componentEl.__zr && !componentEl.__hostTarget) {
  519. throw new Error('Text element has been added to zrender.');
  520. }
  521. if (componentEl === this) {
  522. throw new Error('Recursive component attachment.');
  523. }
  524. var zr = this.__zr;
  525. if (zr) {
  526. componentEl.addSelfToZr(zr);
  527. }
  528. componentEl.__zr = zr;
  529. componentEl.__hostTarget = this;
  530. };
  531. Element.prototype._detachComponent = function (componentEl) {
  532. if (componentEl.__zr) {
  533. componentEl.removeSelfFromZr(componentEl.__zr);
  534. }
  535. componentEl.__zr = null;
  536. componentEl.__hostTarget = null;
  537. };
  538. Element.prototype.getClipPath = function () {
  539. return this._clipPath;
  540. };
  541. Element.prototype.setClipPath = function (clipPath) {
  542. if (this._clipPath && this._clipPath !== clipPath) {
  543. this.removeClipPath();
  544. }
  545. this._attachComponent(clipPath);
  546. this._clipPath = clipPath;
  547. this.markRedraw();
  548. };
  549. Element.prototype.removeClipPath = function () {
  550. var clipPath = this._clipPath;
  551. if (clipPath) {
  552. this._detachComponent(clipPath);
  553. this._clipPath = null;
  554. this.markRedraw();
  555. }
  556. };
  557. Element.prototype.getTextContent = function () {
  558. return this._textContent;
  559. };
  560. Element.prototype.setTextContent = function (textEl) {
  561. var previousTextContent = this._textContent;
  562. if (previousTextContent === textEl) {
  563. return;
  564. }
  565. if (previousTextContent && previousTextContent !== textEl) {
  566. this.removeTextContent();
  567. }
  568. if (textEl.__zr && !textEl.__hostTarget) {
  569. throw new Error('Text element has been added to zrender.');
  570. }
  571. textEl.innerTransformable = new Transformable();
  572. this._attachComponent(textEl);
  573. this._textContent = textEl;
  574. this.markRedraw();
  575. };
  576. Element.prototype.setTextConfig = function (cfg) {
  577. if (!this.textConfig) {
  578. this.textConfig = {};
  579. }
  580. extend(this.textConfig, cfg);
  581. this.markRedraw();
  582. };
  583. Element.prototype.removeTextConfig = function () {
  584. this.textConfig = null;
  585. this.markRedraw();
  586. };
  587. Element.prototype.removeTextContent = function () {
  588. var textEl = this._textContent;
  589. if (textEl) {
  590. textEl.innerTransformable = null;
  591. this._detachComponent(textEl);
  592. this._textContent = null;
  593. this._innerTextDefaultStyle = null;
  594. this.markRedraw();
  595. }
  596. };
  597. Element.prototype.getTextGuideLine = function () {
  598. return this._textGuide;
  599. };
  600. Element.prototype.setTextGuideLine = function (guideLine) {
  601. if (this._textGuide && this._textGuide !== guideLine) {
  602. this.removeTextGuideLine();
  603. }
  604. this._attachComponent(guideLine);
  605. this._textGuide = guideLine;
  606. this.markRedraw();
  607. };
  608. Element.prototype.removeTextGuideLine = function () {
  609. var textGuide = this._textGuide;
  610. if (textGuide) {
  611. this._detachComponent(textGuide);
  612. this._textGuide = null;
  613. this.markRedraw();
  614. }
  615. };
  616. Element.prototype.markRedraw = function () {
  617. this.__dirty |= REDRAW_BIT;
  618. var zr = this.__zr;
  619. if (zr) {
  620. if (this.__inHover) {
  621. zr.refreshHover();
  622. }
  623. else {
  624. zr.refresh();
  625. }
  626. }
  627. if (this.__hostTarget) {
  628. this.__hostTarget.markRedraw();
  629. }
  630. };
  631. Element.prototype.dirty = function () {
  632. this.markRedraw();
  633. };
  634. Element.prototype._toggleHoverLayerFlag = function (inHover) {
  635. this.__inHover = inHover;
  636. var textContent = this._textContent;
  637. var textGuide = this._textGuide;
  638. if (textContent) {
  639. textContent.__inHover = inHover;
  640. }
  641. if (textGuide) {
  642. textGuide.__inHover = inHover;
  643. }
  644. };
  645. Element.prototype.addSelfToZr = function (zr) {
  646. if (this.__zr === zr) {
  647. return;
  648. }
  649. this.__zr = zr;
  650. var animators = this.animators;
  651. if (animators) {
  652. for (var i = 0; i < animators.length; i++) {
  653. zr.animation.addAnimator(animators[i]);
  654. }
  655. }
  656. if (this._clipPath) {
  657. this._clipPath.addSelfToZr(zr);
  658. }
  659. if (this._textContent) {
  660. this._textContent.addSelfToZr(zr);
  661. }
  662. if (this._textGuide) {
  663. this._textGuide.addSelfToZr(zr);
  664. }
  665. };
  666. Element.prototype.removeSelfFromZr = function (zr) {
  667. if (!this.__zr) {
  668. return;
  669. }
  670. this.__zr = null;
  671. var animators = this.animators;
  672. if (animators) {
  673. for (var i = 0; i < animators.length; i++) {
  674. zr.animation.removeAnimator(animators[i]);
  675. }
  676. }
  677. if (this._clipPath) {
  678. this._clipPath.removeSelfFromZr(zr);
  679. }
  680. if (this._textContent) {
  681. this._textContent.removeSelfFromZr(zr);
  682. }
  683. if (this._textGuide) {
  684. this._textGuide.removeSelfFromZr(zr);
  685. }
  686. };
  687. Element.prototype.animate = function (key, loop) {
  688. var target = key ? this[key] : this;
  689. if (!target) {
  690. logError('Property "'
  691. + key
  692. + '" is not existed in element '
  693. + this.id);
  694. return;
  695. }
  696. var animator = new Animator(target, loop);
  697. this.addAnimator(animator, key);
  698. return animator;
  699. };
  700. Element.prototype.addAnimator = function (animator, key) {
  701. var zr = this.__zr;
  702. var el = this;
  703. animator.during(function () {
  704. el.updateDuringAnimation(key);
  705. }).done(function () {
  706. var animators = el.animators;
  707. var idx = indexOf(animators, animator);
  708. if (idx >= 0) {
  709. animators.splice(idx, 1);
  710. }
  711. });
  712. this.animators.push(animator);
  713. if (zr) {
  714. zr.animation.addAnimator(animator);
  715. }
  716. zr && zr.wakeUp();
  717. };
  718. Element.prototype.updateDuringAnimation = function (key) {
  719. this.markRedraw();
  720. };
  721. Element.prototype.stopAnimation = function (scope, forwardToLast) {
  722. var animators = this.animators;
  723. var len = animators.length;
  724. var leftAnimators = [];
  725. for (var i = 0; i < len; i++) {
  726. var animator = animators[i];
  727. if (!scope || scope === animator.scope) {
  728. animator.stop(forwardToLast);
  729. }
  730. else {
  731. leftAnimators.push(animator);
  732. }
  733. }
  734. this.animators = leftAnimators;
  735. return this;
  736. };
  737. Element.prototype.animateTo = function (target, cfg, animationProps) {
  738. animateTo(this, target, cfg, animationProps);
  739. };
  740. Element.prototype.animateFrom = function (target, cfg, animationProps) {
  741. animateTo(this, target, cfg, animationProps, true);
  742. };
  743. Element.prototype._transitionState = function (stateName, target, cfg, animationProps) {
  744. var animators = animateTo(this, target, cfg, animationProps);
  745. for (var i = 0; i < animators.length; i++) {
  746. animators[i].__fromStateTransition = stateName;
  747. }
  748. };
  749. Element.prototype.getBoundingRect = function () {
  750. return null;
  751. };
  752. Element.prototype.getPaintRect = function () {
  753. return null;
  754. };
  755. Element.initDefaultProps = (function () {
  756. var elProto = Element.prototype;
  757. elProto.type = 'element';
  758. elProto.name = '';
  759. elProto.ignore = false;
  760. elProto.silent = false;
  761. elProto.isGroup = false;
  762. elProto.draggable = false;
  763. elProto.dragging = false;
  764. elProto.ignoreClip = false;
  765. elProto.__inHover = false;
  766. elProto.__dirty = REDRAW_BIT;
  767. var logs = {};
  768. function logDeprecatedError(key, xKey, yKey) {
  769. if (!logs[key + xKey + yKey]) {
  770. console.warn("DEPRECATED: '" + key + "' has been deprecated. use '" + xKey + "', '" + yKey + "' instead");
  771. logs[key + xKey + yKey] = true;
  772. }
  773. }
  774. function createLegacyProperty(key, privateKey, xKey, yKey) {
  775. Object.defineProperty(elProto, key, {
  776. get: function () {
  777. logDeprecatedError(key, xKey, yKey);
  778. if (!this[privateKey]) {
  779. var pos = this[privateKey] = [];
  780. enhanceArray(this, pos);
  781. }
  782. return this[privateKey];
  783. },
  784. set: function (pos) {
  785. logDeprecatedError(key, xKey, yKey);
  786. this[xKey] = pos[0];
  787. this[yKey] = pos[1];
  788. this[privateKey] = pos;
  789. enhanceArray(this, pos);
  790. }
  791. });
  792. function enhanceArray(self, pos) {
  793. Object.defineProperty(pos, 0, {
  794. get: function () {
  795. return self[xKey];
  796. },
  797. set: function (val) {
  798. self[xKey] = val;
  799. }
  800. });
  801. Object.defineProperty(pos, 1, {
  802. get: function () {
  803. return self[yKey];
  804. },
  805. set: function (val) {
  806. self[yKey] = val;
  807. }
  808. });
  809. }
  810. }
  811. if (Object.defineProperty && (!env.browser.ie || env.browser.version > 8)) {
  812. createLegacyProperty('position', '_legacyPos', 'x', 'y');
  813. createLegacyProperty('scale', '_legacyScale', 'scaleX', 'scaleY');
  814. createLegacyProperty('origin', '_legacyOrigin', 'originX', 'originY');
  815. }
  816. })();
  817. return Element;
  818. }());
  819. mixin(Element, Eventful);
  820. mixin(Element, Transformable);
  821. function animateTo(animatable, target, cfg, animationProps, reverse) {
  822. cfg = cfg || {};
  823. var animators = [];
  824. animateToShallow(animatable, '', animatable, target, cfg, animationProps, animators, reverse);
  825. var finishCount = animators.length;
  826. var doneHappened = false;
  827. var cfgDone = cfg.done;
  828. var cfgAborted = cfg.aborted;
  829. var doneCb = function () {
  830. doneHappened = true;
  831. finishCount--;
  832. if (finishCount <= 0) {
  833. doneHappened
  834. ? (cfgDone && cfgDone())
  835. : (cfgAborted && cfgAborted());
  836. }
  837. };
  838. var abortedCb = function () {
  839. finishCount--;
  840. if (finishCount <= 0) {
  841. doneHappened
  842. ? (cfgDone && cfgDone())
  843. : (cfgAborted && cfgAborted());
  844. }
  845. };
  846. if (!finishCount) {
  847. cfgDone && cfgDone();
  848. }
  849. if (animators.length > 0 && cfg.during) {
  850. animators[0].during(function (target, percent) {
  851. cfg.during(percent);
  852. });
  853. }
  854. for (var i = 0; i < animators.length; i++) {
  855. var animator = animators[i];
  856. if (doneCb) {
  857. animator.done(doneCb);
  858. }
  859. if (abortedCb) {
  860. animator.aborted(abortedCb);
  861. }
  862. animator.start(cfg.easing, cfg.force);
  863. }
  864. return animators;
  865. }
  866. function copyArrShallow(source, target, len) {
  867. for (var i = 0; i < len; i++) {
  868. source[i] = target[i];
  869. }
  870. }
  871. function is2DArray(value) {
  872. return isArrayLike(value[0]);
  873. }
  874. function copyValue(target, source, key) {
  875. if (isArrayLike(source[key])) {
  876. if (!isArrayLike(target[key])) {
  877. target[key] = [];
  878. }
  879. if (isTypedArray(source[key])) {
  880. var len = source[key].length;
  881. if (target[key].length !== len) {
  882. target[key] = new (source[key].constructor)(len);
  883. copyArrShallow(target[key], source[key], len);
  884. }
  885. }
  886. else {
  887. var sourceArr = source[key];
  888. var targetArr = target[key];
  889. var len0 = sourceArr.length;
  890. if (is2DArray(sourceArr)) {
  891. var len1 = sourceArr[0].length;
  892. for (var i = 0; i < len0; i++) {
  893. if (!targetArr[i]) {
  894. targetArr[i] = Array.prototype.slice.call(sourceArr[i]);
  895. }
  896. else {
  897. copyArrShallow(targetArr[i], sourceArr[i], len1);
  898. }
  899. }
  900. }
  901. else {
  902. copyArrShallow(targetArr, sourceArr, len0);
  903. }
  904. targetArr.length = sourceArr.length;
  905. }
  906. }
  907. else {
  908. target[key] = source[key];
  909. }
  910. }
  911. function animateToShallow(animatable, topKey, source, target, cfg, animationProps, animators, reverse) {
  912. var animatableKeys = [];
  913. var changedKeys = [];
  914. var targetKeys = keys(target);
  915. var duration = cfg.duration;
  916. var delay = cfg.delay;
  917. var additive = cfg.additive;
  918. var setToFinal = cfg.setToFinal;
  919. var animateAll = !isObject(animationProps);
  920. for (var k = 0; k < targetKeys.length; k++) {
  921. var innerKey = targetKeys[k];
  922. if (source[innerKey] != null
  923. && target[innerKey] != null
  924. && (animateAll || animationProps[innerKey])) {
  925. if (isObject(target[innerKey]) && !isArrayLike(target[innerKey])) {
  926. if (topKey) {
  927. if (!reverse) {
  928. source[innerKey] = target[innerKey];
  929. animatable.updateDuringAnimation(topKey);
  930. }
  931. continue;
  932. }
  933. animateToShallow(animatable, innerKey, source[innerKey], target[innerKey], cfg, animationProps && animationProps[innerKey], animators, reverse);
  934. }
  935. else {
  936. animatableKeys.push(innerKey);
  937. changedKeys.push(innerKey);
  938. }
  939. }
  940. else if (!reverse) {
  941. source[innerKey] = target[innerKey];
  942. animatable.updateDuringAnimation(topKey);
  943. changedKeys.push(innerKey);
  944. }
  945. }
  946. var keyLen = animatableKeys.length;
  947. if (keyLen > 0
  948. || (cfg.force && !animators.length)) {
  949. var existsAnimators = animatable.animators;
  950. var existsAnimatorsOnSameTarget = [];
  951. for (var i = 0; i < existsAnimators.length; i++) {
  952. if (existsAnimators[i].targetName === topKey) {
  953. existsAnimatorsOnSameTarget.push(existsAnimators[i]);
  954. }
  955. }
  956. if (!additive && existsAnimatorsOnSameTarget.length) {
  957. for (var i = 0; i < existsAnimatorsOnSameTarget.length; i++) {
  958. var allAborted = existsAnimatorsOnSameTarget[i].stopTracks(changedKeys);
  959. if (allAborted) {
  960. var idx = indexOf(existsAnimators, existsAnimatorsOnSameTarget[i]);
  961. existsAnimators.splice(idx, 1);
  962. }
  963. }
  964. }
  965. var revertedSource = void 0;
  966. var reversedTarget = void 0;
  967. var sourceClone = void 0;
  968. if (reverse) {
  969. reversedTarget = {};
  970. if (setToFinal) {
  971. revertedSource = {};
  972. }
  973. for (var i = 0; i < keyLen; i++) {
  974. var innerKey = animatableKeys[i];
  975. reversedTarget[innerKey] = source[innerKey];
  976. if (setToFinal) {
  977. revertedSource[innerKey] = target[innerKey];
  978. }
  979. else {
  980. source[innerKey] = target[innerKey];
  981. }
  982. }
  983. }
  984. else if (setToFinal) {
  985. sourceClone = {};
  986. for (var i = 0; i < keyLen; i++) {
  987. var innerKey = animatableKeys[i];
  988. sourceClone[innerKey] = cloneValue(source[innerKey]);
  989. copyValue(source, target, innerKey);
  990. }
  991. }
  992. var animator = new Animator(source, false, additive ? existsAnimatorsOnSameTarget : null);
  993. animator.targetName = topKey;
  994. if (cfg.scope) {
  995. animator.scope = cfg.scope;
  996. }
  997. if (setToFinal && revertedSource) {
  998. animator.whenWithKeys(0, revertedSource, animatableKeys);
  999. }
  1000. if (sourceClone) {
  1001. animator.whenWithKeys(0, sourceClone, animatableKeys);
  1002. }
  1003. animator.whenWithKeys(duration == null ? 500 : duration, reverse ? reversedTarget : target, animatableKeys).delay(delay || 0);
  1004. animatable.addAnimator(animator, topKey);
  1005. animators.push(animator);
  1006. }
  1007. }
  1008. export default Element;