customGraphicTransition.js 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494
  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. /**
  20. * AUTO-GENERATED FILE. DO NOT MODIFY.
  21. */
  22. /*
  23. * Licensed to the Apache Software Foundation (ASF) under one
  24. * or more contributor license agreements. See the NOTICE file
  25. * distributed with this work for additional information
  26. * regarding copyright ownership. The ASF licenses this file
  27. * to you under the Apache License, Version 2.0 (the
  28. * "License"); you may not use this file except in compliance
  29. * with the License. You may obtain a copy of the License at
  30. *
  31. * http://www.apache.org/licenses/LICENSE-2.0
  32. *
  33. * Unless required by applicable law or agreed to in writing,
  34. * software distributed under the License is distributed on an
  35. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  36. * KIND, either express or implied. See the License for the
  37. * specific language governing permissions and limitations
  38. * under the License.
  39. */
  40. import { makeInner, normalizeToArray } from '../util/model.js';
  41. import { assert, bind, each, eqNaN, extend, hasOwn, indexOf, isArrayLike, keys, reduce } from 'zrender/lib/core/util.js';
  42. import { cloneValue } from 'zrender/lib/animation/Animator.js';
  43. import Displayable from 'zrender/lib/graphic/Displayable.js';
  44. import { getAnimationConfig } from './basicTransition.js';
  45. import { Path } from '../util/graphic.js';
  46. import { warn } from '../util/log.js';
  47. import { TRANSFORMABLE_PROPS } from 'zrender/lib/core/Transformable.js';
  48. var LEGACY_TRANSFORM_PROPS_MAP = {
  49. position: ['x', 'y'],
  50. scale: ['scaleX', 'scaleY'],
  51. origin: ['originX', 'originY']
  52. };
  53. var LEGACY_TRANSFORM_PROPS = keys(LEGACY_TRANSFORM_PROPS_MAP);
  54. var TRANSFORM_PROPS_MAP = reduce(TRANSFORMABLE_PROPS, function (obj, key) {
  55. obj[key] = 1;
  56. return obj;
  57. }, {});
  58. var transformPropNamesStr = TRANSFORMABLE_PROPS.join(', ');
  59. // '' means root
  60. export var ELEMENT_ANIMATABLE_PROPS = ['', 'style', 'shape', 'extra'];
  61. ;
  62. var transitionInnerStore = makeInner();
  63. ;
  64. function getElementAnimationConfig(animationType, el, elOption, parentModel, dataIndex) {
  65. var animationProp = animationType + "Animation";
  66. var config = getAnimationConfig(animationType, parentModel, dataIndex) || {};
  67. var userDuring = transitionInnerStore(el).userDuring;
  68. // Only set when duration is > 0 and it's need to be animated.
  69. if (config.duration > 0) {
  70. // For simplicity, if during not specified, the previous during will not work any more.
  71. config.during = userDuring ? bind(duringCall, {
  72. el: el,
  73. userDuring: userDuring
  74. }) : null;
  75. config.setToFinal = true;
  76. config.scope = animationType;
  77. }
  78. extend(config, elOption[animationProp]);
  79. return config;
  80. }
  81. export function applyUpdateTransition(el, elOption, animatableModel, opts) {
  82. opts = opts || {};
  83. var dataIndex = opts.dataIndex,
  84. isInit = opts.isInit,
  85. clearStyle = opts.clearStyle;
  86. var hasAnimation = animatableModel.isAnimationEnabled();
  87. // Save the meta info for further morphing. Like apply on the sub morphing elements.
  88. var store = transitionInnerStore(el);
  89. var styleOpt = elOption.style;
  90. store.userDuring = elOption.during;
  91. var transFromProps = {};
  92. var propsToSet = {};
  93. prepareTransformAllPropsFinal(el, elOption, propsToSet);
  94. if (el.type === 'compound') {
  95. /**
  96. * We cannot directly clone shape for compoundPath,
  97. * because it makes the path to be an object instead of a Path instance,
  98. * and thus missing `buildPath` method.
  99. */
  100. var paths = el.shape.paths;
  101. var optionPaths = elOption.shape.paths;
  102. for (var i = 0; i < optionPaths.length; i++) {
  103. var path = optionPaths[i];
  104. prepareShapeOrExtraAllPropsFinal('shape', path, paths[i]);
  105. }
  106. } else {
  107. prepareShapeOrExtraAllPropsFinal('shape', elOption, propsToSet);
  108. prepareShapeOrExtraAllPropsFinal('extra', elOption, propsToSet);
  109. }
  110. if (!isInit && hasAnimation) {
  111. prepareTransformTransitionFrom(el, elOption, transFromProps);
  112. prepareShapeOrExtraTransitionFrom('shape', el, elOption, transFromProps);
  113. prepareShapeOrExtraTransitionFrom('extra', el, elOption, transFromProps);
  114. prepareStyleTransitionFrom(el, elOption, styleOpt, transFromProps);
  115. }
  116. propsToSet.style = styleOpt;
  117. applyPropsDirectly(el, propsToSet, clearStyle);
  118. applyMiscProps(el, elOption);
  119. if (hasAnimation) {
  120. if (isInit) {
  121. var enterFromProps_1 = {};
  122. each(ELEMENT_ANIMATABLE_PROPS, function (propName) {
  123. var prop = propName ? elOption[propName] : elOption;
  124. if (prop && prop.enterFrom) {
  125. if (propName) {
  126. enterFromProps_1[propName] = enterFromProps_1[propName] || {};
  127. }
  128. extend(propName ? enterFromProps_1[propName] : enterFromProps_1, prop.enterFrom);
  129. }
  130. });
  131. var config = getElementAnimationConfig('enter', el, elOption, animatableModel, dataIndex);
  132. if (config.duration > 0) {
  133. el.animateFrom(enterFromProps_1, config);
  134. }
  135. } else {
  136. applyPropsTransition(el, elOption, dataIndex || 0, animatableModel, transFromProps);
  137. }
  138. }
  139. // Store leave to be used in leave transition.
  140. updateLeaveTo(el, elOption);
  141. styleOpt ? el.dirty() : el.markRedraw();
  142. }
  143. export function updateLeaveTo(el, elOption) {
  144. // Try merge to previous set leaveTo
  145. var leaveToProps = transitionInnerStore(el).leaveToProps;
  146. for (var i = 0; i < ELEMENT_ANIMATABLE_PROPS.length; i++) {
  147. var propName = ELEMENT_ANIMATABLE_PROPS[i];
  148. var prop = propName ? elOption[propName] : elOption;
  149. if (prop && prop.leaveTo) {
  150. if (!leaveToProps) {
  151. leaveToProps = transitionInnerStore(el).leaveToProps = {};
  152. }
  153. if (propName) {
  154. leaveToProps[propName] = leaveToProps[propName] || {};
  155. }
  156. extend(propName ? leaveToProps[propName] : leaveToProps, prop.leaveTo);
  157. }
  158. }
  159. }
  160. export function applyLeaveTransition(el, elOption, animatableModel, onRemove) {
  161. if (el) {
  162. var parent_1 = el.parent;
  163. var leaveToProps = transitionInnerStore(el).leaveToProps;
  164. if (leaveToProps) {
  165. // TODO TODO use leave after leaveAnimation in series is introduced
  166. // TODO Data index?
  167. var config = getElementAnimationConfig('update', el, elOption, animatableModel, 0);
  168. config.done = function () {
  169. parent_1 && parent_1.remove(el);
  170. onRemove && onRemove();
  171. };
  172. el.animateTo(leaveToProps, config);
  173. } else {
  174. parent_1 && parent_1.remove(el);
  175. onRemove && onRemove();
  176. }
  177. }
  178. }
  179. export function isTransitionAll(transition) {
  180. return transition === 'all';
  181. }
  182. function applyPropsDirectly(el,
  183. // Can be null/undefined
  184. allPropsFinal, clearStyle) {
  185. var styleOpt = allPropsFinal.style;
  186. if (!el.isGroup && styleOpt) {
  187. if (clearStyle) {
  188. el.useStyle({});
  189. // When style object changed, how to trade the existing animation?
  190. // It is probably complicated and not needed to cover all the cases.
  191. // But still need consider the case:
  192. // (1) When using init animation on `style.opacity`, and before the animation
  193. // ended users triggers an update by mousewhel. At that time the init
  194. // animation should better be continued rather than terminated.
  195. // So after `useStyle` called, we should change the animation target manually
  196. // to continue the effect of the init animation.
  197. // (2) PENDING: If the previous animation targeted at a `val1`, and currently we need
  198. // to update the value to `val2` and no animation declared, should be terminate
  199. // the previous animation or just modify the target of the animation?
  200. // Therotically That will happen not only on `style` but also on `shape` and
  201. // `transfrom` props. But we haven't handle this case at present yet.
  202. // (3) PENDING: Is it proper to visit `animators` and `targetName`?
  203. var animators = el.animators;
  204. for (var i = 0; i < animators.length; i++) {
  205. var animator = animators[i];
  206. // targetName is the "topKey".
  207. if (animator.targetName === 'style') {
  208. animator.changeTarget(el.style);
  209. }
  210. }
  211. }
  212. el.setStyle(styleOpt);
  213. }
  214. if (allPropsFinal) {
  215. // Not set style here.
  216. allPropsFinal.style = null;
  217. // Set el to the final state firstly.
  218. allPropsFinal && el.attr(allPropsFinal);
  219. allPropsFinal.style = styleOpt;
  220. }
  221. }
  222. function applyPropsTransition(el, elOption, dataIndex, model,
  223. // Can be null/undefined
  224. transFromProps) {
  225. if (transFromProps) {
  226. var config = getElementAnimationConfig('update', el, elOption, model, dataIndex);
  227. if (config.duration > 0) {
  228. el.animateFrom(transFromProps, config);
  229. }
  230. }
  231. }
  232. function applyMiscProps(el, elOption) {
  233. // Merge by default.
  234. hasOwn(elOption, 'silent') && (el.silent = elOption.silent);
  235. hasOwn(elOption, 'ignore') && (el.ignore = elOption.ignore);
  236. if (el instanceof Displayable) {
  237. hasOwn(elOption, 'invisible') && (el.invisible = elOption.invisible);
  238. }
  239. if (el instanceof Path) {
  240. hasOwn(elOption, 'autoBatch') && (el.autoBatch = elOption.autoBatch);
  241. }
  242. }
  243. // Use it to avoid it be exposed to user.
  244. var tmpDuringScope = {};
  245. var transitionDuringAPI = {
  246. // Usually other props do not need to be changed in animation during.
  247. setTransform: function (key, val) {
  248. if (process.env.NODE_ENV !== 'production') {
  249. assert(hasOwn(TRANSFORM_PROPS_MAP, key), 'Only ' + transformPropNamesStr + ' available in `setTransform`.');
  250. }
  251. tmpDuringScope.el[key] = val;
  252. return this;
  253. },
  254. getTransform: function (key) {
  255. if (process.env.NODE_ENV !== 'production') {
  256. assert(hasOwn(TRANSFORM_PROPS_MAP, key), 'Only ' + transformPropNamesStr + ' available in `getTransform`.');
  257. }
  258. return tmpDuringScope.el[key];
  259. },
  260. setShape: function (key, val) {
  261. if (process.env.NODE_ENV !== 'production') {
  262. assertNotReserved(key);
  263. }
  264. var el = tmpDuringScope.el;
  265. var shape = el.shape || (el.shape = {});
  266. shape[key] = val;
  267. el.dirtyShape && el.dirtyShape();
  268. return this;
  269. },
  270. getShape: function (key) {
  271. if (process.env.NODE_ENV !== 'production') {
  272. assertNotReserved(key);
  273. }
  274. var shape = tmpDuringScope.el.shape;
  275. if (shape) {
  276. return shape[key];
  277. }
  278. },
  279. setStyle: function (key, val) {
  280. if (process.env.NODE_ENV !== 'production') {
  281. assertNotReserved(key);
  282. }
  283. var el = tmpDuringScope.el;
  284. var style = el.style;
  285. if (style) {
  286. if (process.env.NODE_ENV !== 'production') {
  287. if (eqNaN(val)) {
  288. warn('style.' + key + ' must not be assigned with NaN.');
  289. }
  290. }
  291. style[key] = val;
  292. el.dirtyStyle && el.dirtyStyle();
  293. }
  294. return this;
  295. },
  296. getStyle: function (key) {
  297. if (process.env.NODE_ENV !== 'production') {
  298. assertNotReserved(key);
  299. }
  300. var style = tmpDuringScope.el.style;
  301. if (style) {
  302. return style[key];
  303. }
  304. },
  305. setExtra: function (key, val) {
  306. if (process.env.NODE_ENV !== 'production') {
  307. assertNotReserved(key);
  308. }
  309. var extra = tmpDuringScope.el.extra || (tmpDuringScope.el.extra = {});
  310. extra[key] = val;
  311. return this;
  312. },
  313. getExtra: function (key) {
  314. if (process.env.NODE_ENV !== 'production') {
  315. assertNotReserved(key);
  316. }
  317. var extra = tmpDuringScope.el.extra;
  318. if (extra) {
  319. return extra[key];
  320. }
  321. }
  322. };
  323. function assertNotReserved(key) {
  324. if (process.env.NODE_ENV !== 'production') {
  325. if (key === 'transition' || key === 'enterFrom' || key === 'leaveTo') {
  326. throw new Error('key must not be "' + key + '"');
  327. }
  328. }
  329. }
  330. function duringCall() {
  331. // Do not provide "percent" until some requirements come.
  332. // Because consider thies case:
  333. // enterFrom: {x: 100, y: 30}, transition: 'x'.
  334. // And enter duration is different from update duration.
  335. // Thus it might be confused about the meaning of "percent" in during callback.
  336. var scope = this;
  337. var el = scope.el;
  338. if (!el) {
  339. return;
  340. }
  341. // If el is remove from zr by reason like legend, during still need to called,
  342. // because el will be added back to zr and the prop value should not be incorrect.
  343. var latestUserDuring = transitionInnerStore(el).userDuring;
  344. var scopeUserDuring = scope.userDuring;
  345. // Ensured a during is only called once in each animation frame.
  346. // If a during is called multiple times in one frame, maybe some users' calculation logic
  347. // might be wrong (not sure whether this usage exists).
  348. // The case of a during might be called twice can be: by default there is a animator for
  349. // 'x', 'y' when init. Before the init animation finished, call `setOption` to start
  350. // another animators for 'style'/'shape'/'extra'.
  351. if (latestUserDuring !== scopeUserDuring) {
  352. // release
  353. scope.el = scope.userDuring = null;
  354. return;
  355. }
  356. tmpDuringScope.el = el;
  357. // Give no `this` to user in "during" calling.
  358. scopeUserDuring(transitionDuringAPI);
  359. // FIXME: if in future meet the case that some prop will be both modified in `during` and `state`,
  360. // consider the issue that the prop might be incorrect when return to "normal" state.
  361. }
  362. function prepareShapeOrExtraTransitionFrom(mainAttr, fromEl, elOption, transFromProps) {
  363. var attrOpt = elOption[mainAttr];
  364. if (!attrOpt) {
  365. return;
  366. }
  367. var elPropsInAttr = fromEl[mainAttr];
  368. var transFromPropsInAttr;
  369. if (elPropsInAttr) {
  370. var transition = elOption.transition;
  371. var attrTransition = attrOpt.transition;
  372. if (attrTransition) {
  373. !transFromPropsInAttr && (transFromPropsInAttr = transFromProps[mainAttr] = {});
  374. if (isTransitionAll(attrTransition)) {
  375. extend(transFromPropsInAttr, elPropsInAttr);
  376. } else {
  377. var transitionKeys = normalizeToArray(attrTransition);
  378. for (var i = 0; i < transitionKeys.length; i++) {
  379. var key = transitionKeys[i];
  380. var elVal = elPropsInAttr[key];
  381. transFromPropsInAttr[key] = elVal;
  382. }
  383. }
  384. } else if (isTransitionAll(transition) || indexOf(transition, mainAttr) >= 0) {
  385. !transFromPropsInAttr && (transFromPropsInAttr = transFromProps[mainAttr] = {});
  386. var elPropsInAttrKeys = keys(elPropsInAttr);
  387. for (var i = 0; i < elPropsInAttrKeys.length; i++) {
  388. var key = elPropsInAttrKeys[i];
  389. var elVal = elPropsInAttr[key];
  390. if (isNonStyleTransitionEnabled(attrOpt[key], elVal)) {
  391. transFromPropsInAttr[key] = elVal;
  392. }
  393. }
  394. }
  395. }
  396. }
  397. function prepareShapeOrExtraAllPropsFinal(mainAttr, elOption, allProps) {
  398. var attrOpt = elOption[mainAttr];
  399. if (!attrOpt) {
  400. return;
  401. }
  402. var allPropsInAttr = allProps[mainAttr] = {};
  403. var keysInAttr = keys(attrOpt);
  404. for (var i = 0; i < keysInAttr.length; i++) {
  405. var key = keysInAttr[i];
  406. // To avoid share one object with different element, and
  407. // to avoid user modify the object inexpectedly, have to clone.
  408. allPropsInAttr[key] = cloneValue(attrOpt[key]);
  409. }
  410. }
  411. function prepareTransformTransitionFrom(el, elOption, transFromProps) {
  412. var transition = elOption.transition;
  413. var transitionKeys = isTransitionAll(transition) ? TRANSFORMABLE_PROPS : normalizeToArray(transition || []);
  414. for (var i = 0; i < transitionKeys.length; i++) {
  415. var key = transitionKeys[i];
  416. if (key === 'style' || key === 'shape' || key === 'extra') {
  417. continue;
  418. }
  419. var elVal = el[key];
  420. if (process.env.NODE_ENV !== 'production') {
  421. checkTransformPropRefer(key, 'el.transition');
  422. }
  423. // Do not clone, animator will perform that clone.
  424. transFromProps[key] = elVal;
  425. }
  426. }
  427. function prepareTransformAllPropsFinal(el, elOption, allProps) {
  428. for (var i = 0; i < LEGACY_TRANSFORM_PROPS.length; i++) {
  429. var legacyName = LEGACY_TRANSFORM_PROPS[i];
  430. var xyName = LEGACY_TRANSFORM_PROPS_MAP[legacyName];
  431. var legacyArr = elOption[legacyName];
  432. if (legacyArr) {
  433. allProps[xyName[0]] = legacyArr[0];
  434. allProps[xyName[1]] = legacyArr[1];
  435. }
  436. }
  437. for (var i = 0; i < TRANSFORMABLE_PROPS.length; i++) {
  438. var key = TRANSFORMABLE_PROPS[i];
  439. if (elOption[key] != null) {
  440. allProps[key] = elOption[key];
  441. }
  442. }
  443. }
  444. function prepareStyleTransitionFrom(fromEl, elOption, styleOpt, transFromProps) {
  445. if (!styleOpt) {
  446. return;
  447. }
  448. var fromElStyle = fromEl.style;
  449. var transFromStyleProps;
  450. if (fromElStyle) {
  451. var styleTransition = styleOpt.transition;
  452. var elTransition = elOption.transition;
  453. if (styleTransition && !isTransitionAll(styleTransition)) {
  454. var transitionKeys = normalizeToArray(styleTransition);
  455. !transFromStyleProps && (transFromStyleProps = transFromProps.style = {});
  456. for (var i = 0; i < transitionKeys.length; i++) {
  457. var key = transitionKeys[i];
  458. var elVal = fromElStyle[key];
  459. // Do not clone, see `checkNonStyleTansitionRefer`.
  460. transFromStyleProps[key] = elVal;
  461. }
  462. } else if (fromEl.getAnimationStyleProps && (isTransitionAll(elTransition) || isTransitionAll(styleTransition) || indexOf(elTransition, 'style') >= 0)) {
  463. var animationProps = fromEl.getAnimationStyleProps();
  464. var animationStyleProps = animationProps ? animationProps.style : null;
  465. if (animationStyleProps) {
  466. !transFromStyleProps && (transFromStyleProps = transFromProps.style = {});
  467. var styleKeys = keys(styleOpt);
  468. for (var i = 0; i < styleKeys.length; i++) {
  469. var key = styleKeys[i];
  470. if (animationStyleProps[key]) {
  471. var elVal = fromElStyle[key];
  472. transFromStyleProps[key] = elVal;
  473. }
  474. }
  475. }
  476. }
  477. }
  478. }
  479. function isNonStyleTransitionEnabled(optVal, elVal) {
  480. // The same as `checkNonStyleTansitionRefer`.
  481. return !isArrayLike(optVal) ? optVal != null && isFinite(optVal) : optVal !== elVal;
  482. }
  483. var checkTransformPropRefer;
  484. if (process.env.NODE_ENV !== 'production') {
  485. checkTransformPropRefer = function (key, usedIn) {
  486. if (!hasOwn(TRANSFORM_PROPS_MAP, key)) {
  487. warn('Prop `' + key + '` is not a permitted in `' + usedIn + '`. ' + 'Only `' + keys(TRANSFORM_PROPS_MAP).join('`, `') + '` are permitted.');
  488. }
  489. };
  490. }