diff --git a/demos/import-graph/import-graph.js b/demos/import-graph/import-graph.js
new file mode 100644
index 0000000..6dcf643
--- /dev/null
+++ b/demos/import-graph/import-graph.js
@@ -0,0 +1,31 @@
+fetch('zdog.json')
+ .then(function( res ) {
+ return res.json();
+ })
+ .then(function(model) {
+ // ----- variables ----- //
+ var sceneSize = 100;
+ var TAU = Zdog.TAU;
+ var initRotate = { x: 20/360 * TAU, y: -50/360 * TAU };
+
+ // ----- model ----- //
+ var illo = new Zdog.Illustration({
+ element: '.illo',
+ rotate: initRotate,
+ dragRotate: true,
+ resize: 'fullscreen',
+ importGraph: model,
+ onResize: function( width, height ) {
+ this.zoom = Math.floor( Math.min( width, height ) * 2 / sceneSize ) / 2;
+ },
+ });
+
+ // ----- animate ----- //
+
+ function animate() {
+ illo.updateRenderGraph();
+ requestAnimationFrame(animate);
+ }
+
+ animate();
+});
diff --git a/demos/import-graph/index.html b/demos/import-graph/index.html
new file mode 100644
index 0000000..6a1f241
--- /dev/null
+++ b/demos/import-graph/index.html
@@ -0,0 +1,47 @@
+
+
+
+
+
+
+ Import graph
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/demos/import-graph/zdog.json b/demos/import-graph/zdog.json
new file mode 100644
index 0000000..5533086
--- /dev/null
+++ b/demos/import-graph/zdog.json
@@ -0,0 +1,797 @@
+{
+ "type": "Illustration",
+ "zoom": 8,
+ "children": [
+ {
+ "type": "Group",
+ "children": [
+ {
+ "type": "Group",
+ "updateSort": true,
+ "children": [
+ {
+ "type": "Rect",
+ "rotate": {
+ "x": 1.5707963267948966
+ },
+ "translate": {
+ "y": -20
+ },
+ "stroke": 8,
+ "fill": true,
+ "color": "#E62",
+ "path": [
+ {
+ "x": -20,
+ "y": -10
+ },
+ {
+ "x": 20,
+ "y": -10
+ },
+ {
+ "x": 20,
+ "y": 10
+ },
+ {
+ "x": -20,
+ "y": 10
+ }
+ ],
+ "front": {
+ "z": 1
+ },
+ "width": 40,
+ "height": 20
+ },
+ {
+ "type": "Rect",
+ "rotate": {
+ "x": -1.5707963267948966
+ },
+ "translate": {
+ "y": 20
+ },
+ "stroke": 8,
+ "fill": true,
+ "color": "#E62",
+ "path": [
+ {
+ "x": -20,
+ "y": -10
+ },
+ {
+ "x": 20,
+ "y": -10
+ },
+ {
+ "x": 20,
+ "y": 10
+ },
+ {
+ "x": -20,
+ "y": 10
+ }
+ ],
+ "front": {
+ "z": 1
+ },
+ "width": 40,
+ "height": 20
+ },
+ {
+ "type": "Rect",
+ "rotate": {
+ "y": 1.5707963267948966
+ },
+ "translate": {
+ "x": -20,
+ "y": -16
+ },
+ "stroke": 8,
+ "fill": true,
+ "color": "#E62",
+ "path": [
+ {
+ "x": -10,
+ "y": -4
+ },
+ {
+ "x": 10,
+ "y": -4
+ },
+ {
+ "x": 10,
+ "y": 4
+ },
+ {
+ "x": -10,
+ "y": 4
+ }
+ ],
+ "front": {
+ "z": 1
+ },
+ "backface": false,
+ "width": 20,
+ "height": 8
+ },
+ {
+ "type": "Rect",
+ "rotate": {
+ "y": -1.5707963267948966
+ },
+ "translate": {
+ "x": 20,
+ "y": 16
+ },
+ "stroke": 8,
+ "fill": true,
+ "color": "#E62",
+ "path": [
+ {
+ "x": -10,
+ "y": -4
+ },
+ {
+ "x": 10,
+ "y": -4
+ },
+ {
+ "x": 10,
+ "y": 4
+ },
+ {
+ "x": -10,
+ "y": 4
+ }
+ ],
+ "front": {
+ "z": 1
+ },
+ "backface": false,
+ "width": 20,
+ "height": 8
+ },
+ {
+ "type": "Rect",
+ "rotate": {
+ "y": 1.5707963267948966
+ },
+ "translate": {
+ "x": -20,
+ "y": 15
+ },
+ "stroke": 8,
+ "fill": true,
+ "color": "#E62",
+ "path": [
+ {
+ "x": -10,
+ "y": -5
+ },
+ {
+ "x": 10,
+ "y": -5
+ },
+ {
+ "x": 10,
+ "y": 5
+ },
+ {
+ "x": -10,
+ "y": 5
+ }
+ ],
+ "front": {
+ "z": 1
+ },
+ "backface": false,
+ "width": 20,
+ "height": 10
+ },
+ {
+ "type": "Rect",
+ "rotate": {
+ "y": -1.5707963267948966
+ },
+ "translate": {
+ "x": 20,
+ "y": -15
+ },
+ "stroke": 8,
+ "fill": true,
+ "color": "#E62",
+ "path": [
+ {
+ "x": -10,
+ "y": -5
+ },
+ {
+ "x": 10,
+ "y": -5
+ },
+ {
+ "x": 10,
+ "y": 5
+ },
+ {
+ "x": -10,
+ "y": 5
+ }
+ ],
+ "front": {
+ "z": 1
+ },
+ "backface": false,
+ "width": 20,
+ "height": 10
+ },
+ {
+ "type": "Rect",
+ "rotate": {
+ "x": -1.5707963267948966
+ },
+ "translate": {
+ "x": -5,
+ "y": -12
+ },
+ "stroke": 8,
+ "fill": true,
+ "color": "#E62",
+ "path": [
+ {
+ "x": -15,
+ "y": -10
+ },
+ {
+ "x": 15,
+ "y": -10
+ },
+ {
+ "x": 15,
+ "y": 10
+ },
+ {
+ "x": -15,
+ "y": 10
+ }
+ ],
+ "front": {
+ "z": 1
+ },
+ "width": 30,
+ "height": 20
+ },
+ {
+ "type": "Rect",
+ "rotate": {
+ "x": 1.5707963267948966
+ },
+ "translate": {
+ "x": 5,
+ "y": 12
+ },
+ "stroke": 8,
+ "fill": true,
+ "color": "#E62",
+ "path": [
+ {
+ "x": -15,
+ "y": -10
+ },
+ {
+ "x": 15,
+ "y": -10
+ },
+ {
+ "x": 15,
+ "y": 10
+ },
+ {
+ "x": -15,
+ "y": 10
+ }
+ ],
+ "front": {
+ "z": 1
+ },
+ "width": 30,
+ "height": 20
+ },
+ {
+ "type": "Rect",
+ "rotate": {
+ "x": 1.5707963267948966,
+ "y": 0.6327488350021832
+ },
+ "translate": {
+ "x": -5,
+ "y": -1
+ },
+ "stroke": 8,
+ "fill": true,
+ "color": "#E62",
+ "path": [
+ {
+ "x": -18.601075237738275,
+ "y": -10
+ },
+ {
+ "x": 18.601075237738275,
+ "y": -10
+ },
+ {
+ "x": 18.601075237738275,
+ "y": 10
+ },
+ {
+ "x": -18.601075237738275,
+ "y": 10
+ }
+ ],
+ "front": {
+ "z": 1
+ },
+ "backface": false,
+ "width": 37.20215047547655,
+ "height": 20
+ },
+ {
+ "type": "Rect",
+ "rotate": {
+ "x": -1.5707963267948966,
+ "y": -0.6327488350021832
+ },
+ "translate": {
+ "x": 5,
+ "y": 1
+ },
+ "stroke": 8,
+ "fill": true,
+ "color": "#E62",
+ "path": [
+ {
+ "x": -18.601075237738275,
+ "y": -10
+ },
+ {
+ "x": 18.601075237738275,
+ "y": -10
+ },
+ {
+ "x": 18.601075237738275,
+ "y": 10
+ },
+ {
+ "x": -18.601075237738275,
+ "y": 10
+ }
+ ],
+ "front": {
+ "z": 1
+ },
+ "backface": false,
+ "width": 37.20215047547655,
+ "height": 20
+ },
+ {
+ "type": "Ellipse",
+ "rotate": {
+ "z": 1.5707963267948966
+ },
+ "translate": {
+ "x": 22,
+ "y": -4
+ },
+ "stroke": 8,
+ "color": "#E62",
+ "path": [
+ {
+ "x": 0,
+ "y": -16
+ },
+ {
+ "arc": [
+ {
+ "x": 16,
+ "y": -16
+ },
+ {
+ "x": 16,
+ "y": 0
+ }
+ ]
+ }
+ ],
+ "front": {
+ "z": 1
+ },
+ "diameter": 32,
+ "quarters": 1
+ },
+ {
+ "type": "Anchor",
+ "rotate": {
+ "y": 1.5707963267948966
+ },
+ "translate": {
+ "x": -6,
+ "y": -7
+ },
+ "children": [
+ {
+ "type": "Shape",
+ "rotate": {
+ "x": 0.9420000403794636
+ },
+ "stroke": 4,
+ "fill": true,
+ "color": "#636",
+ "path": [
+ {
+ "x": -5,
+ "y": 0
+ },
+ {
+ "x": 5,
+ "y": 0
+ },
+ {
+ "x": 5,
+ "y": 12
+ },
+ {
+ "arc": [
+ {
+ "x": 5,
+ "y": 17
+ },
+ {
+ "x": 0,
+ "y": 17
+ }
+ ]
+ },
+ {
+ "arc": [
+ {
+ "x": -5,
+ "y": 17
+ },
+ {
+ "x": -5,
+ "y": 12
+ }
+ ]
+ }
+ ],
+ "front": {
+ "z": 1
+ }
+ }
+ ]
+ },
+ {
+ "type": "Ellipse",
+ "rotate": {
+ "y": 1.5707963267948966,
+ "z": 1.5707963267948966
+ },
+ "translate": {
+ "x": -26,
+ "y": -20
+ },
+ "scale": 8,
+ "stroke": 5,
+ "fill": true,
+ "color": "#636",
+ "closed": true,
+ "path": [
+ {
+ "x": 0,
+ "y": -0.5
+ },
+ {
+ "arc": [
+ {
+ "x": 0.5,
+ "y": -0.5
+ },
+ {
+ "x": 0.5,
+ "y": 0
+ }
+ ]
+ },
+ {
+ "arc": [
+ {
+ "x": 0.5,
+ "y": 0.5
+ },
+ {
+ "x": 0,
+ "y": 0.5
+ }
+ ]
+ }
+ ],
+ "front": {
+ "z": 1
+ },
+ "quarters": 2
+ }
+ ]
+ },
+ {
+ "type": "Group",
+ "updateSort": true,
+ "children": [
+ {
+ "type": "Shape",
+ "translate": {
+ "z": 10
+ },
+ "stroke": 8,
+ "fill": true,
+ "color": "#EA0",
+ "path": [
+ {
+ "x": -20,
+ "y": -20
+ },
+ {
+ "x": 20,
+ "y": -20
+ },
+ {
+ "x": 20,
+ "y": -10
+ },
+ {
+ "x": -10,
+ "y": 12
+ },
+ {
+ "x": 20,
+ "y": 12
+ },
+ {
+ "x": 20,
+ "y": 20
+ },
+ {
+ "x": -20,
+ "y": 20
+ },
+ {
+ "x": -20,
+ "y": 10
+ },
+ {
+ "x": 10,
+ "y": -12
+ },
+ {
+ "x": -20,
+ "y": -12
+ }
+ ],
+ "front": {
+ "z": 1
+ },
+ "backface": false
+ },
+ {
+ "type": "Shape",
+ "rotate": {
+ "y": 3.141592653589793
+ },
+ "translate": {
+ "z": -10
+ },
+ "scale": {
+ "x": -1,
+ "y": 1,
+ "z": 1
+ },
+ "stroke": 8,
+ "fill": true,
+ "color": "#EA0",
+ "path": [
+ {
+ "x": -20,
+ "y": -20
+ },
+ {
+ "x": 20,
+ "y": -20
+ },
+ {
+ "x": 20,
+ "y": -10
+ },
+ {
+ "x": -10,
+ "y": 12
+ },
+ {
+ "x": 20,
+ "y": 12
+ },
+ {
+ "x": 20,
+ "y": 20
+ },
+ {
+ "x": -20,
+ "y": 20
+ },
+ {
+ "x": -20,
+ "y": 10
+ },
+ {
+ "x": 10,
+ "y": -12
+ },
+ {
+ "x": -20,
+ "y": -12
+ }
+ ],
+ "front": {
+ "z": 1
+ },
+ "backface": false
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "type": "Group",
+ "children": [
+ {
+ "type": "Ellipse",
+ "rotate": {
+ "x": 0.39269908169872414,
+ "z": -0.39269908169872414
+ },
+ "translate": {
+ "x": 10,
+ "y": -14,
+ "z": 20
+ },
+ "scale": 24,
+ "stroke": 5,
+ "fill": true,
+ "color": "#636",
+ "closed": true,
+ "path": [
+ {
+ "x": 0,
+ "y": -0.5
+ },
+ {
+ "arc": [
+ {
+ "x": 0.5,
+ "y": -0.5
+ },
+ {
+ "x": 0.5,
+ "y": 0
+ }
+ ]
+ },
+ {
+ "arc": [
+ {
+ "x": 0.5,
+ "y": 0.5
+ },
+ {
+ "x": 0,
+ "y": 0.5
+ }
+ ]
+ }
+ ],
+ "front": {
+ "z": 1
+ },
+ "quarters": 2,
+ "children": [
+ {
+ "type": "Shape",
+ "translate": {
+ "x": -0.5,
+ "z": 0.5
+ },
+ "visible": false,
+ "front": {
+ "z": 1
+ }
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "type": "Group",
+ "scale": {
+ "x": 1,
+ "y": 1,
+ "z": -1
+ },
+ "children": [
+ {
+ "type": "Ellipse",
+ "rotate": {
+ "x": 0.39269908169872414,
+ "z": -0.39269908169872414
+ },
+ "translate": {
+ "x": 10,
+ "y": -14,
+ "z": 20
+ },
+ "scale": 24,
+ "stroke": 5,
+ "fill": true,
+ "color": "#636",
+ "closed": true,
+ "path": [
+ {
+ "x": 0,
+ "y": -0.5
+ },
+ {
+ "arc": [
+ {
+ "x": 0.5,
+ "y": -0.5
+ },
+ {
+ "x": 0.5,
+ "y": 0
+ }
+ ]
+ },
+ {
+ "arc": [
+ {
+ "x": 0.5,
+ "y": 0.5
+ },
+ {
+ "x": 0,
+ "y": 0.5
+ }
+ ]
+ }
+ ],
+ "front": {
+ "z": 1
+ },
+ "quarters": 2,
+ "children": [
+ {
+ "type": "Shape",
+ "translate": {
+ "x": -0.5,
+ "z": 0.5
+ },
+ "visible": false,
+ "front": {
+ "z": 1
+ }
+ }
+ ]
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/js/anchor.js b/js/anchor.js
index 0744810..4926693 100644
--- a/js/anchor.js
+++ b/js/anchor.js
@@ -22,6 +22,7 @@ var onePoint = { x: 1, y: 1, z: 1 };
function Anchor( options ) {
this.create( options || {} );
}
+Anchor.type = 'Anchor';
Anchor.prototype.create = function( options ) {
// set defaults & options
@@ -40,6 +41,9 @@ Anchor.prototype.create = function( options ) {
if ( this.addTo ) {
this.addTo.addChild( this );
}
+ if ( options.importGraph ) {
+ this.importGraph( options.importGraph );
+ }
};
Anchor.defaults = {};
@@ -51,11 +55,15 @@ Anchor.optionKeys = Object.keys( Anchor.defaults ).concat([
'addTo',
]);
+Anchor.ignoreKeysJSON = [
+ 'addTo',
+];
+
Anchor.prototype.setOptions = function( options ) {
var optionKeys = this.constructor.optionKeys;
for ( var key in options ) {
- if ( optionKeys.includes( key ) ) {
+ if ( optionKeys.indexOf( key ) > -1 ) {
this[ key ] = options[ key ];
}
}
@@ -207,12 +215,73 @@ Anchor.prototype.copyGraph = function( options ) {
return clone;
};
+Anchor.prototype.importGraph = function( model ) {
+ this.addChild( revive( model ) );
+
+ function revive( graph ) {
+ graph = utils.extend( {}, graph );
+ // quick hack to avoid nested Illustration items
+ var type = graph.type === 'Illustration' ? 'Anchor' : graph.type;
+ var children = (graph.children || []).slice( 0 );
+ delete graph.children;
+
+ var Item = utils[ type ];
+ var rootGraph;
+ if ( Item ) {
+ rootGraph = new Item( graph );
+ children.forEach( function( child ) {
+ revive( utils.extend( child, { addTo: rootGraph } ) );
+ } );
+ }
+ return rootGraph;
+ }
+};
+
Anchor.prototype.normalizeRotate = function() {
this.rotate.x = utils.modulo( this.rotate.x, TAU );
this.rotate.y = utils.modulo( this.rotate.y, TAU );
this.rotate.z = utils.modulo( this.rotate.z, TAU );
};
+Anchor.prototype.toJSON = function() {
+ var type = this.constructor.type;
+ var result = { type: type };
+ var defaults = this.constructor.defaults;
+ var optionKeys = this.constructor.optionKeys.slice(0).concat('children');
+ var ignoreKeys = Anchor.ignoreKeysJSON
+ .slice(0)
+ .concat(this.constructor.ignoreKeysJSON || []);
+
+ optionKeys.forEach(function( key ) {
+ if (ignoreKeys.indexOf(key) > -1) {
+ return;
+ }
+ var value = this[key];
+
+ if (
+ ![ 'undefined', 'function' ].indexOf(typeof value) > -1 &&
+ value !== defaults[key]
+ ) {
+ if (Array.isArray(value) && value.length === 0) {
+ return;
+ }
+ if (value.toJSON) {
+ var serialized = value.toJSON();
+ if (typeof serialized !== 'undefined') {
+ if (key === 'scale' && serialized === 1) {
+ return;
+ }
+ result[key] = serialized;
+ }
+ } else {
+ result[key] = value;
+ }
+ }
+ }, this);
+
+ return result;
+};
+
// ----- subclass ----- //
function getSubclass( Super ) {
@@ -231,10 +300,12 @@ function getSubclass( Super ) {
Item.optionKeys = Super.optionKeys.slice(0);
// add defaults keys to optionKeys, dedupe
Object.keys( Item.defaults ).forEach( function( key ) {
- if ( !Item.optionKeys.includes( key ) ) {
+ if ( !Item.optionKeys.indexOf( key ) > -1 ) {
Item.optionKeys.push( key );
}
});
+ // create ignoreKeysJSON
+ Item.ignoreKeysJSON = Super.ignoreKeysJSON.slice(0);
Item.subclass = getSubclass( Item );
diff --git a/js/boilerplate.js b/js/boilerplate.js
index a22ddc9..413c0fd 100644
--- a/js/boilerplate.js
+++ b/js/boilerplate.js
@@ -70,6 +70,10 @@ Zdog.easeInOut = function( alpha, power ) {
return isFirstHalf ? curve : 1 - curve;
};
+Zdog.exportGraph = function(model) {
+ return JSON.parse( JSON.stringify( model ) );
+};
+
return Zdog;
}));
diff --git a/js/box.js b/js/box.js
index 4f8735f..e12ce3e 100644
--- a/js/box.js
+++ b/js/box.js
@@ -18,9 +18,10 @@
// ----- BoxRect ----- //
var BoxRect = Rect.subclass();
+
// prevent double-creation in parent.copyGraph()
// only create in Box.create()
-BoxRect.prototype.copyGraph = function() {};
+BoxRect.prototype.copyGraph = function() { };
// ----- Box ----- //
@@ -38,8 +39,9 @@ var boxDefaults = utils.extend( {
// default fill
boxDefaults.fill = true;
delete boxDefaults.path;
-
var Box = Anchor.subclass( boxDefaults );
+Box.ignoreKeysJSON = [ 'children' ];
+Box.type = 'Box';
var TAU = utils.TAU;
diff --git a/js/cone.js b/js/cone.js
index 4535e5a..73a63a8 100644
--- a/js/cone.js
+++ b/js/cone.js
@@ -20,6 +20,7 @@ var Cone = Ellipse.subclass({
length: 1,
fill: true,
});
+Cone.type = 'Cone';
var TAU = utils.TAU;
diff --git a/js/cylinder.js b/js/cylinder.js
index cc2a4f0..d1b9979 100644
--- a/js/cylinder.js
+++ b/js/cylinder.js
@@ -26,6 +26,8 @@ var CylinderGroup = Group.subclass({
updateSort: true,
});
+CylinderGroup.type = 'CylinderGroup';
+
CylinderGroup.prototype.create = function() {
Group.prototype.create.apply( this, arguments );
this.pathCommands = [
@@ -97,6 +99,9 @@ var Cylinder = Shape.subclass({
fill: true,
});
+Cylinder.type = 'Cylinder';
+
+
var TAU = utils.TAU;
Cylinder.prototype.create = function(/* options */) {
diff --git a/js/ellipse.js b/js/ellipse.js
index fafbe98..def1a05 100644
--- a/js/ellipse.js
+++ b/js/ellipse.js
@@ -23,6 +23,8 @@ var Ellipse = Shape.subclass({
closed: false,
});
+Ellipse.type = 'Ellipse';
+
Ellipse.prototype.setPath = function() {
var width = this.width != undefined ? this.width : this.diameter;
var height = this.height != undefined ? this.height : this.diameter;
diff --git a/js/group.js b/js/group.js
index ffafb84..746e2a6 100644
--- a/js/group.js
+++ b/js/group.js
@@ -19,6 +19,9 @@ var Group = Anchor.subclass({
visible: true,
});
+Group.type = 'Group';
+
+
// ----- update ----- //
Group.prototype.updateSortValue = function() {
diff --git a/js/hemisphere.js b/js/hemisphere.js
index fa92c4e..abaeb00 100644
--- a/js/hemisphere.js
+++ b/js/hemisphere.js
@@ -18,6 +18,8 @@ var Hemisphere = Ellipse.subclass({
fill: true,
});
+Hemisphere.type = 'Hemisphere';
+
var TAU = utils.TAU;
Hemisphere.prototype.render = function( ctx, renderer ) {
diff --git a/js/illustration.js b/js/illustration.js
index a8751bb..f433bf3 100644
--- a/js/illustration.js
+++ b/js/illustration.js
@@ -30,6 +30,8 @@ var Illustration = Anchor.subclass({
onDragEnd: noop,
onResize: noop,
});
+Illustration.ignoreKeysJSON = [ 'dragRotate', 'element', 'resize' ];
+Illustration.type = 'Illustration';
utils.extend( Illustration.prototype, Dragger.prototype );
diff --git a/js/polygon.js b/js/polygon.js
index a3ea770..e7da3f1 100644
--- a/js/polygon.js
+++ b/js/polygon.js
@@ -19,6 +19,8 @@ var Polygon = Shape.subclass({
radius: 0.5,
});
+Polygon.type = 'Polygon';
+
var TAU = utils.TAU;
Polygon.prototype.setPath = function() {
diff --git a/js/rect.js b/js/rect.js
index 9e69542..ffedaa9 100644
--- a/js/rect.js
+++ b/js/rect.js
@@ -19,6 +19,8 @@ var Rect = Shape.subclass({
height: 1,
});
+Rect.type = 'Rect';
+
Rect.prototype.setPath = function() {
var x = this.width / 2;
var y = this.height / 2;
diff --git a/js/rounded-rect.js b/js/rounded-rect.js
index 30c8a3f..28316e3 100644
--- a/js/rounded-rect.js
+++ b/js/rounded-rect.js
@@ -21,6 +21,8 @@ var RoundedRect = Shape.subclass({
closed: false,
});
+RoundedRect.type = 'RoundedRect';
+
RoundedRect.prototype.setPath = function() {
/* eslint
id-length: [ "error", { "min": 2, "exceptions": [ "x", "y" ] }],
diff --git a/js/shape.js b/js/shape.js
index 40c927c..673289b 100644
--- a/js/shape.js
+++ b/js/shape.js
@@ -26,6 +26,8 @@ var Shape = Anchor.subclass({
backface: true,
});
+Shape.type = 'Shape';
+
Shape.prototype.create = function( options ) {
Anchor.prototype.create.call( this, options );
this.updatePath();
@@ -60,7 +62,7 @@ Shape.prototype.updatePathCommands = function() {
var method = keys[0];
var points = pathPart[ method ];
// default to line if no instruction
- var isInstruction = keys.length == 1 && actionNames.includes( method );
+ var isInstruction = keys.length == 1 && actionNames.indexOf( method ) > -1;
if ( !isInstruction ) {
method = 'line';
points = pathPart;
diff --git a/js/vector.js b/js/vector.js
index b896526..2d1f6d5 100644
--- a/js/vector.js
+++ b/js/vector.js
@@ -149,6 +149,32 @@ Vector.prototype.copy = function() {
return new Vector( this );
};
+function round( num ) {
+ return Math.round( num * 1000 ) / 1000;
+}
+
+Vector.prototype.toJSON = function() {
+ var x = this.x;
+ var y = this.y;
+ var z = this.z;
+
+ if ( x === y && y === z ) {
+ return x !== 0 ? round( x ) : undefined;
+ }
+
+ var obj = { x: x, y: y, z: z };
+ var result = {};
+
+ Object.keys( obj ).forEach( function( key ) {
+ var value = obj[ key ];
+ if ( value !== 0 ) {
+ result[ key ] = round( value );
+ }
+ });
+
+ return Object.keys( result ).length ? result : undefined;
+};
+
return Vector;
}));