mirror of
https://github.com/scratchfoundation/paper.js.git
synced 2025-01-06 04:42:15 -05:00
Commit first version of serialization / deserialization mechanism.
It appears to work fine already for Paths and Groups.
This commit is contained in:
parent
ae4e5d4be5
commit
4f83e0eee6
7 changed files with 147 additions and 4 deletions
|
@ -42,6 +42,8 @@
|
||||||
* matrix multiplication).
|
* matrix multiplication).
|
||||||
*/
|
*/
|
||||||
var Matrix = this.Matrix = Base.extend(/** @lends Matrix# */{
|
var Matrix = this.Matrix = Base.extend(/** @lends Matrix# */{
|
||||||
|
_type: 'matrix',
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a 2D affine transform.
|
* Creates a 2D affine transform.
|
||||||
*
|
*
|
||||||
|
@ -74,6 +76,10 @@ var Matrix = this.Matrix = Base.extend(/** @lends Matrix# */{
|
||||||
throw new Error('Unsupported matrix parameters');
|
throw new Error('Unsupported matrix parameters');
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_serialize: function() {
|
||||||
|
return this.getValues();
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return {Matrix} A copy of this transform.
|
* @return {Matrix} A copy of this transform.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -168,6 +168,10 @@ var Point = this.Point = Base.extend(/** @lends Point# */{
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_serialize: function() {
|
||||||
|
return [this.x, this.y];
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The x coordinate of the point
|
* The x coordinate of the point
|
||||||
*
|
*
|
||||||
|
|
|
@ -282,6 +282,17 @@ var Color = this.Color = Base.extend(new function() {
|
||||||
return res;
|
return res;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_serialize: function() {
|
||||||
|
var res = [];
|
||||||
|
for (var i = 0, l = this._components.length; i < l; i++) {
|
||||||
|
var component = this._components[i],
|
||||||
|
value = this['_' + component];
|
||||||
|
if (component !== 'alpha' || value != null && value < 1)
|
||||||
|
res.push(value);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return {RgbColor|GrayColor|HsbColor} a copy of the color object
|
* @return {RgbColor|GrayColor|HsbColor} a copy of the color object
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -50,8 +50,23 @@ this.Base = Base.inject(/** @lends Base# */{
|
||||||
}, []).join(', ') + ' }';
|
}, []).join(', ') + ' }';
|
||||||
},
|
},
|
||||||
|
|
||||||
|
toJson: function() {
|
||||||
|
return Base.toJson(this);
|
||||||
|
},
|
||||||
|
|
||||||
statics: /** @lends Base */{
|
statics: /** @lends Base */{
|
||||||
|
|
||||||
|
_types: {},
|
||||||
|
|
||||||
|
extend: function(src) {
|
||||||
|
// Override Base.extend() with a version that registers classes that
|
||||||
|
// define #_type inside the Base._types lookup, for deserialization.
|
||||||
|
var res = this.base.apply(this, arguments);
|
||||||
|
if (src._type)
|
||||||
|
Base._types[src._type] = res;
|
||||||
|
return res;
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if two values or objects are equals to each other, by using their
|
* Checks if two values or objects are equals to each other, by using their
|
||||||
* equals() methods if available, and also comparing elements of arrays
|
* equals() methods if available, and also comparing elements of arrays
|
||||||
|
@ -164,6 +179,75 @@ this.Base = Base.inject(/** @lends Base# */{
|
||||||
return res;
|
return res;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serializes the passed object into a format that can be passed to
|
||||||
|
* JSON.stringify() for JSON serialization.
|
||||||
|
*/
|
||||||
|
serialize: function(obj, compact) {
|
||||||
|
if (obj && obj._serialize) {
|
||||||
|
var res = obj._serialize();
|
||||||
|
if (!compact && res[0] !== obj._type)
|
||||||
|
res.unshift(obj._type);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
if (typeof obj !== 'object')
|
||||||
|
return obj;
|
||||||
|
var res = obj;
|
||||||
|
if (Array.isArray(obj)) {
|
||||||
|
res = [];
|
||||||
|
for (var i = 0, l = obj.length; i < l; i++)
|
||||||
|
res[i] = Base.serialize(obj[i], true);
|
||||||
|
} else if (Base.isObject(obj)) {
|
||||||
|
res = {};
|
||||||
|
for (var i in obj)
|
||||||
|
if (obj.hasOwnProperty(i))
|
||||||
|
res[i] = Base.serialize(obj[i], true);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deserializes from parsed JSON data. A simple convention is followed:
|
||||||
|
* Array values with a string at the first position are links to
|
||||||
|
* deserializable types through Base._types, and the values following in
|
||||||
|
* the array are the arguments to their initialize function.
|
||||||
|
* Any other value is passed on unmodified.
|
||||||
|
* The passed data is recoursively traversed and converted, leaves first
|
||||||
|
*/
|
||||||
|
deserialize: function(obj) {
|
||||||
|
var res = obj;
|
||||||
|
if (Array.isArray(obj)) {
|
||||||
|
// See if it's a serialized type. If so, the rest of the array
|
||||||
|
// are the arguments to #initialize(). Either way, we simply
|
||||||
|
// deserialize all elements of the array.
|
||||||
|
var type = Base._types[obj[0]];
|
||||||
|
res = [];
|
||||||
|
// Skip first type entry for arguments
|
||||||
|
for (var i = type ? 1 : 0, l = obj.length; i < l; i++)
|
||||||
|
res.push(Base.deserialize(obj[i]));
|
||||||
|
if (type) {
|
||||||
|
// Create serialized type and pass collected arguments to
|
||||||
|
// #initialize().
|
||||||
|
var args = res;
|
||||||
|
res = Base.create(type);
|
||||||
|
res.initialize.apply(res, args);
|
||||||
|
}
|
||||||
|
} else if (Base.isObject(obj)) {
|
||||||
|
res = {};
|
||||||
|
for (var key in obj)
|
||||||
|
res[key] = Base.deserialize(obj[key]);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
},
|
||||||
|
|
||||||
|
toJson: function(obj) {
|
||||||
|
return JSON.stringify(Base.serialize(obj));
|
||||||
|
},
|
||||||
|
|
||||||
|
fromJson: function(json) {
|
||||||
|
return Base.deserialize(JSON.parse(json));
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utility function for adding and removing items from a list of which
|
* Utility function for adding and removing items from a list of which
|
||||||
* each entry keeps a reference to its index in the list in the private
|
* each entry keeps a reference to its index in the list in the private
|
||||||
|
|
|
@ -25,6 +25,13 @@
|
||||||
* that they inherit from Item.
|
* that they inherit from Item.
|
||||||
*/
|
*/
|
||||||
var Item = this.Item = Base.extend(Callback, /** @lends Item# */{
|
var Item = this.Item = Base.extend(Callback, /** @lends Item# */{
|
||||||
|
// Provide information about fields to be serialized, with their defaults
|
||||||
|
// that can be ommited.
|
||||||
|
_serializeFields: {
|
||||||
|
name: null,
|
||||||
|
children: [],
|
||||||
|
matrix: new Matrix()
|
||||||
|
},
|
||||||
|
|
||||||
initialize: function(point) {
|
initialize: function(point) {
|
||||||
// Define this Item's unique id.
|
// Define this Item's unique id.
|
||||||
|
@ -116,10 +123,8 @@ var Item = this.Item = Base.extend(Callback, /** @lends Item# */{
|
||||||
// one object literal describing all the properties to be set on the created
|
// one object literal describing all the properties to be set on the created
|
||||||
// instance.
|
// instance.
|
||||||
_setProperties: function(props) {
|
_setProperties: function(props) {
|
||||||
if (Base.isObject(props)) {
|
if (Base.isObject(props))
|
||||||
this.set(props);
|
return this.set(props);
|
||||||
return true;
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -133,6 +138,27 @@ var Item = this.Item = Base.extend(Callback, /** @lends Item# */{
|
||||||
return this;
|
return this;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_serialize: function() {
|
||||||
|
var props = {},
|
||||||
|
that = this;
|
||||||
|
|
||||||
|
function serialize(fields) {
|
||||||
|
for (var key in fields) {
|
||||||
|
var value = that[key];
|
||||||
|
if (!Base.equals(value, fields[key]))
|
||||||
|
props[key] = Base.serialize(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Serialize fields that this Item subclass defines first
|
||||||
|
serialize(this._serializeFields);
|
||||||
|
// Serialize style fields, but only if they differ from defaults
|
||||||
|
serialize(this._style._defaults);
|
||||||
|
// There is no compact form for Item serialization, we always keep the
|
||||||
|
// type.
|
||||||
|
return [ this._type, props ];
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Private notifier that is called whenever a change occurs in this item or
|
* Private notifier that is called whenever a change occurs in this item or
|
||||||
* its sub-elements, such as Segments, Curves, PathStyles, etc.
|
* its sub-elements, such as Segments, Curves, PathStyles, etc.
|
||||||
|
|
|
@ -24,6 +24,10 @@
|
||||||
// DOCS: Explain that path matrix is always applied with each transformation.
|
// DOCS: Explain that path matrix is always applied with each transformation.
|
||||||
var Path = this.Path = PathItem.extend(/** @lends Path# */{
|
var Path = this.Path = PathItem.extend(/** @lends Path# */{
|
||||||
_type: 'path',
|
_type: 'path',
|
||||||
|
_serializeFields: {
|
||||||
|
segments: [],
|
||||||
|
closed: false
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new Path item and places it at the top of the active layer.
|
* Creates a new Path item and places it at the top of the active layer.
|
||||||
|
|
|
@ -27,6 +27,8 @@
|
||||||
* objects that are connected by this segment.
|
* objects that are connected by this segment.
|
||||||
*/
|
*/
|
||||||
var Segment = this.Segment = Base.extend(/** @lends Segment# */{
|
var Segment = this.Segment = Base.extend(/** @lends Segment# */{
|
||||||
|
_type: 'segment',
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new Segment object.
|
* Creates a new Segment object.
|
||||||
*
|
*
|
||||||
|
@ -86,6 +88,12 @@ var Segment = this.Segment = Base.extend(/** @lends Segment# */{
|
||||||
createPoint(this, '_handleOut', handleOut);
|
createPoint(this, '_handleOut', handleOut);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_serialize: function() {
|
||||||
|
return Base.serialize(this._handleIn.isZero() && this._handleOut.isZero()
|
||||||
|
? this._point
|
||||||
|
: [this._point, this._handleIn, this._handleOut], true);
|
||||||
|
},
|
||||||
|
|
||||||
_changed: function(point) {
|
_changed: function(point) {
|
||||||
if (!this._path)
|
if (!this._path)
|
||||||
return;
|
return;
|
||||||
|
|
Loading…
Reference in a new issue