mirror of
https://github.com/scratchfoundation/paper.js.git
synced 2025-01-04 03:45:58 -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).
|
||||
*/
|
||||
var Matrix = this.Matrix = Base.extend(/** @lends Matrix# */{
|
||||
_type: 'matrix',
|
||||
|
||||
/**
|
||||
* Creates a 2D affine transform.
|
||||
*
|
||||
|
@ -74,6 +76,10 @@ var Matrix = this.Matrix = Base.extend(/** @lends Matrix# */{
|
|||
throw new Error('Unsupported matrix parameters');
|
||||
},
|
||||
|
||||
_serialize: function() {
|
||||
return this.getValues();
|
||||
},
|
||||
|
||||
/**
|
||||
* @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
|
||||
*
|
||||
|
|
|
@ -282,6 +282,17 @@ var Color = this.Color = Base.extend(new function() {
|
|||
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
|
||||
*/
|
||||
|
|
|
@ -50,8 +50,23 @@ this.Base = Base.inject(/** @lends Base# */{
|
|||
}, []).join(', ') + ' }';
|
||||
},
|
||||
|
||||
toJson: function() {
|
||||
return Base.toJson(this);
|
||||
},
|
||||
|
||||
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
|
||||
* equals() methods if available, and also comparing elements of arrays
|
||||
|
@ -164,6 +179,75 @@ this.Base = Base.inject(/** @lends Base# */{
|
|||
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
|
||||
* each entry keeps a reference to its index in the list in the private
|
||||
|
|
|
@ -25,6 +25,13 @@
|
|||
* that they inherit from 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) {
|
||||
// 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
|
||||
// instance.
|
||||
_setProperties: function(props) {
|
||||
if (Base.isObject(props)) {
|
||||
this.set(props);
|
||||
return true;
|
||||
}
|
||||
if (Base.isObject(props))
|
||||
return this.set(props);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -133,6 +138,27 @@ var Item = this.Item = Base.extend(Callback, /** @lends Item# */{
|
|||
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
|
||||
* its sub-elements, such as Segments, Curves, PathStyles, etc.
|
||||
|
|
|
@ -24,6 +24,10 @@
|
|||
// DOCS: Explain that path matrix is always applied with each transformation.
|
||||
var Path = this.Path = PathItem.extend(/** @lends Path# */{
|
||||
_type: 'path',
|
||||
_serializeFields: {
|
||||
segments: [],
|
||||
closed: false
|
||||
},
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
var Segment = this.Segment = Base.extend(/** @lends Segment# */{
|
||||
_type: 'segment',
|
||||
|
||||
/**
|
||||
* Creates a new Segment object.
|
||||
*
|
||||
|
@ -86,6 +88,12 @@ var Segment = this.Segment = Base.extend(/** @lends Segment# */{
|
|||
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) {
|
||||
if (!this._path)
|
||||
return;
|
||||
|
|
Loading…
Reference in a new issue