stateful.mixin.js
3.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
(function() {
var extend = fabric.util.object.extend,
originalSet = 'stateProperties';
/*
Depends on `stateProperties`
*/
function saveProps(origin, destination, props) {
var tmpObj = { }, deep = true;
props.forEach(function(prop) {
tmpObj[prop] = origin[prop];
});
extend(origin[destination], tmpObj, deep);
}
function _isEqual(origValue, currentValue, firstPass) {
if (origValue === currentValue) {
// if the objects are identical, return
return true;
}
else if (Array.isArray(origValue)) {
if (!Array.isArray(currentValue) || origValue.length !== currentValue.length) {
return false;
}
for (var i = 0, len = origValue.length; i < len; i++) {
if (!_isEqual(origValue[i], currentValue[i])) {
return false;
}
}
return true;
}
else if (origValue && typeof origValue === 'object') {
var keys = Object.keys(origValue), key;
if (!currentValue ||
typeof currentValue !== 'object' ||
(!firstPass && keys.length !== Object.keys(currentValue).length)
) {
return false;
}
for (var i = 0, len = keys.length; i < len; i++) {
key = keys[i];
// since clipPath is in the statefull cache list and the clipPath objects
// would be iterated as an object, this would lead to possible infinite recursion
// we do not want to compare those.
if (key === 'canvas' || key === 'group') {
continue;
}
if (!_isEqual(origValue[key], currentValue[key])) {
return false;
}
}
return true;
}
}
fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prototype */ {
/**
* Returns true if object state (one of its state properties) was changed
* @param {String} [propertySet] optional name for the set of property we want to save
* @return {Boolean} true if instance' state has changed since `{@link fabric.Object#saveState}` was called
*/
hasStateChanged: function(propertySet) {
propertySet = propertySet || originalSet;
var dashedPropertySet = '_' + propertySet;
if (Object.keys(this[dashedPropertySet]).length < this[propertySet].length) {
return true;
}
return !_isEqual(this[dashedPropertySet], this, true);
},
/**
* Saves state of an object
* @param {Object} [options] Object with additional `stateProperties` array to include when saving state
* @return {fabric.Object} thisArg
*/
saveState: function(options) {
var propertySet = options && options.propertySet || originalSet,
destination = '_' + propertySet;
if (!this[destination]) {
return this.setupState(options);
}
saveProps(this, destination, this[propertySet]);
if (options && options.stateProperties) {
saveProps(this, destination, options.stateProperties);
}
return this;
},
/**
* Setups state of an object
* @param {Object} [options] Object with additional `stateProperties` array to include when saving state
* @return {fabric.Object} thisArg
*/
setupState: function(options) {
options = options || { };
var propertySet = options.propertySet || originalSet;
options.propertySet = propertySet;
this['_' + propertySet] = { };
this.saveState(options);
return this;
}
});
})();