123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400 |
- var zrUtil = require("../core/util");
- var Style = require("./Style");
- var _vector = require("../core/vector");
- var vec2Copy = _vector.copy;
- /**
- * States machine for managing graphic states
- */
- /**
- * @typedef {Object} IGraphicState
- * @property {number} [zlevel]
- * @property {number} [z]
- * @property {Array.<number>} {position}
- * @property {Array.<number>|number} {rotation}
- * @property {Array.<number>} {scale}
- * @property {Object} style
- *
- * @property {Function} onenter
- * @property {Function} onleave
- * @property {Function} ontransition
- * @property {Array.<IGraphicStateTransition|string>} transition
- * Transition object or a string descriptor like '* 30 0 Linear'
- */
- var transitionProperties = ['position', 'rotation', 'scale', 'style', 'shape'];
- /**
- * @module zrender/graphic/States~TransitionObject
- */
- var TransitionObject = function (opts) {
- if (typeof opts === 'string') {
- this._fromStr(opts);
- } else if (opts) {
- opts.property && (this.property = opts.property);
- opts.duration != null && (this.duration = opts.duration);
- opts.easing && (this.easing = opts.easing);
- opts.delay && (this.delay = opts.delay);
- }
- if (this.property !== '*') {
- this.property = this.property.split(',');
- } else {
- this.property = transitionProperties;
- }
- };
- TransitionObject.prototype = {
- constructor: TransitionObject,
- /**
- * List of all transition properties. Splitted by comma. Must not have spaces in the string.
- * e.g. 'position,style.color'. '*' will match all the valid properties.
- * @type {string}
- * @default *
- */
- property: '*',
- /**
- * @type {string}
- * @default 'Linear'
- */
- easing: 'Linear',
- /**
- * @type {number}
- * @default 'number'
- */
- duration: 500,
- /**
- * @type {number}
- */
- delay: 0,
- _fromStr: function (str) {
- var arr = str.split(/\s+/g);
- this.property = arr[0];
- this.duration = +arr[1];
- this.delay = +arr[2];
- this.easing = arr[3];
- }
- };
- /**
- * @alias module:zrender/graphic/States
- */
- var GraphicStates = function (opts) {
- opts = opts || {};
- this._states = {};
- /**
- * Target element
- * @type {zrender/graphic/Displayable|zrender/container/Group}
- */
- this._el = opts.el;
- this._subStates = [];
- this._transitionAnimators = [];
- if (opts.initialState) {
- this._initialState = opts.initialState;
- }
- var optsStates = opts.states;
- if (optsStates) {
- for (var name in optsStates) {
- if (optsStates.hasOwnProperty(name)) {
- var state = optsStates[name];
- this._addState(name, state);
- }
- }
- }
- this.setState(this._initialState);
- };
- GraphicStates.prototype = {
- constructor: GraphicStates,
- /**
- * All other state will be extended from initial state
- * @type {string}
- * @private
- */
- _initialState: 'normal',
- /**
- * Current state
- * @type {string}
- * @private
- */
- _currentState: '',
- el: function () {
- return this._el;
- },
- _addState: function (name, state) {
- this._states[name] = state;
- if (state.transition) {
- state.transition = new TransitionObject(state.transition);
- } // Extend from initial state
- if (name !== this._initialState) {
- this._extendFromInitial(state);
- } else {
- var el = this._el; // setState 的时候自带的 style 和 shape 都会被直接覆盖
- // 所以这边先把自带的 style 和 shape 扩展到初始状态中
- zrUtil.merge(state.style, el.style, false, false);
- if (state.shape) {
- zrUtil.merge(state.shape, el.shape, false, true);
- } else {
- state.shape = zrUtil.clone(el.shape, true);
- }
- for (var name in this._states) {
- if (this._states.hasOwnProperty(name)) {
- this._extendFromInitial(this._states[name]);
- }
- }
- }
- },
- _extendFromInitial: function (state) {
- var initialState = this._states[this._initialState];
- if (initialState && state !== initialState) {
- zrUtil.merge(state, initialState, false, true);
- }
- },
- setState: function (name, silent) {
- if (name === this._currentState && !this.transiting()) {
- return;
- }
- var state = this._states[name];
- if (state) {
- this._stopTransition();
- if (!silent) {
- var prevState = this._states[this._currentState];
- if (prevState) {
- prevState.onleave && prevState.onleave.call(this);
- }
- state.onenter && state.onenter.call(this);
- }
- this._currentState = name;
- if (this._el) {
- var el = this._el; // Setting attributes
- if (state.zlevel != null) {
- el.zlevel = state.zlevel;
- }
- if (state.z != null) {
- el.z = state.z;
- } // SRT
- state.position && vec2Copy(el.position, state.position);
- state.scale && vec2Copy(el.scale, state.scale);
- if (state.rotation != null) {
- el.rotation = state.rotation;
- } // Style
- if (state.style) {
- var initialState = this._states[this._initialState];
- el.style = new Style();
- if (initialState) {
- el.style.extendFrom(initialState.style, false);
- }
- if ( // Not initial state
- name !== this._initialState // Not copied from initial state in _extendFromInitial method
- && initialState.style !== state.style) {
- el.style.extendFrom(state.style, true);
- }
- }
- if (state.shape) {
- el.shape = zrUtil.clone(state.shape, true);
- }
- el.dirty();
- }
- }
- for (var i = 0; i < this._subStates.length; i++) {
- this._subStates.setState(name);
- }
- },
- getState: function () {
- return this._currentState;
- },
- transitionState: function (target, done) {
- if (target === this._currentState && !this.transiting()) {
- return;
- }
- var state = this._states[target];
- var styleShapeReg = /$[style|shape]\./;
- var self = this; // Animation 去重
- var propPathMap = {};
- if (state) {
- self._stopTransition();
- var el = self._el;
- if (state.transition && el && el.__zr) {
- // El can be animated
- var transitionCfg = state.transition;
- var property = transitionCfg.property;
- var animatingCount = 0;
- var animationDone = function () {
- animatingCount--;
- if (animatingCount === 0) {
- self.setState(target);
- done && done();
- }
- };
- for (var i = 0; i < property.length; i++) {
- var propName = property[i]; // Animating all the properties in style or shape
- if (propName === 'style' || propName === 'shape') {
- if (state[propName]) {
- for (var key in state[propName]) {
- /* eslint-disable max-depth */
- if (!state[propName].hasOwnProperty(key)) {
- continue;
- }
- var path = propName + '.' + key;
- if (propPathMap[path]) {
- continue;
- }
- /* eslint-enable max-depth */
- propPathMap[path] = 1;
- animatingCount += self._animProp(state, propName, key, transitionCfg, animationDone);
- }
- }
- } else {
- if (propPathMap[propName]) {
- continue;
- }
- propPathMap[propName] = 1; // Animating particular property in style or style
- if (propName.match(styleShapeReg)) {
- // remove 'style.', 'shape.' prefix
- var subProp = propName.slice(0, 5);
- propName = propName.slice(6);
- animatingCount += self._animProp(state, subProp, propName, transitionCfg, animationDone);
- } else {
- animatingCount += self._animProp(state, '', propName, transitionCfg, animationDone);
- }
- }
- } // No transition properties
- if (animatingCount === 0) {
- self.setState(target);
- done && done();
- }
- } else {
- self.setState(target);
- done && done();
- }
- }
- var subStates = self._subStates;
- for (var i = 0; i < subStates.length; i++) {
- subStates.transitionState(target);
- }
- },
- /**
- * Do transition animation of particular property
- * @param {Object} state
- * @param {string} subPropKey
- * @param {string} key
- * @param {Object} transitionCfg
- * @param {Function} done
- * @private
- */
- _animProp: function (state, subPropKey, key, transitionCfg, done) {
- var el = this._el;
- var stateObj = subPropKey ? state[subPropKey] : state;
- var elObj = subPropKey ? el[subPropKey] : el;
- var availableProp = stateObj && key in stateObj && elObj && key in elObj;
- var transitionAnimators = this._transitionAnimators;
- if (availableProp) {
- var obj = {};
- if (stateObj[key] === elObj[key]) {
- return 0;
- }
- obj[key] = stateObj[key];
- var animator = el.animate(subPropKey).when(transitionCfg.duration, obj).delay(transitionCfg.dealy).done(function () {
- var idx = zrUtil.indexOf(transitionAnimators, 1);
- if (idx > 0) {
- transitionAnimators.splice(idx, 1);
- }
- done();
- }).start(transitionCfg.easing);
- transitionAnimators.push(animator);
- return 1;
- }
- return 0;
- },
- _stopTransition: function () {
- var transitionAnimators = this._transitionAnimators;
- for (var i = 0; i < transitionAnimators.length; i++) {
- transitionAnimators[i].stop();
- }
- transitionAnimators.length = 0;
- },
- transiting: function () {
- return this._transitionAnimators.length > 0;
- },
- addSubStates: function (states) {
- this._subStates.push(states);
- },
- removeSubStates: function (states) {
- var idx = zrUtil.indexOf(this._subStates, states);
- if (idx >= 0) {
- this._subStates.splice(states, 1);
- }
- }
- };
- var _default = GraphicStates;
- module.exports = _default;
|