jointjs
Version:
JavaScript diagramming library
947 lines (844 loc) • 236 kB
JavaScript
'use strict';
QUnit.module('path', function(hooks) {
var fixture = document.createElement('div');
fixture.id = 'qunit-fixture';
var getSvg = function() {
var svg = document.createElementNS('http://www.w3.org/2000/svg', 'path');
svg.setAttribute('width', 600);
svg.setAttribute('height', 800);
document.body.appendChild(fixture);
fixture.appendChild(svg);
return svg;
};
QUnit.module('constructor', function() {
QUnit.test('creates a new Path object', function(assert) {
var error;
var path;
// no arguments (invalid)
path = new g.Path();
assert.ok(path instanceof g.Path, 'returns instance of g.Path');
assert.ok(typeof path.segments !== 'undefined', 'has "segments" property');
assert.ok(Array.isArray(path.segments));
assert.equal(path.segments.length, 0);
// path data string -> g.Path.parse()
// path segments array
path = new g.Path([
g.Path.createSegment('M', 0, 100),
g.Path.createSegment('L', 100, 100),
g.Path.createSegment('C', 150, 150, 250, 50, 300, 100),
g.Path.createSegment('Z')
]);
assert.ok(path instanceof g.Path, 'returns instance of g.Path');
assert.ok(typeof path.segments !== 'undefined', 'has "segments" property');
assert.ok(Array.isArray(path.segments));
assert.equal(path.segments.length, 4);
assert.ok(path.segments[0] instanceof g.Path.segmentTypes.M);
assert.ok(path.segments[1] instanceof g.Path.segmentTypes.L);
assert.ok(path.segments[2] instanceof g.Path.segmentTypes.C);
assert.ok(path.segments[3] instanceof g.Path.segmentTypes.Z);
assert.equal(path.segments[0].end.toString(), '0@100');
assert.equal(path.segments[1].start.toString(), '0@100');
assert.equal(path.segments[1].end.toString(), '100@100');
assert.equal(path.segments[2].start.toString(), '100@100');
assert.equal(path.segments[2].controlPoint1.toString(), '150@150');
assert.equal(path.segments[2].controlPoint2.toString(), '250@50');
assert.equal(path.segments[2].end.toString(), '300@100');
assert.equal(path.segments[3].start.toString(), '300@100');
assert.equal(path.segments[3].end.toString(), '0@100');
// path segments nested array
path = new g.Path([
g.Path.createSegment('M', 0, 100, 100, 100), // creates array - M followed by L
g.Path.createSegment('C', 150, 150, 250, 50, 300, 100),
g.Path.createSegment('Z')
]);
assert.ok(path instanceof g.Path, 'returns instance of g.Path');
assert.ok(typeof path.segments !== 'undefined', 'has "segments" property');
assert.ok(Array.isArray(path.segments));
assert.equal(path.segments.length, 4);
assert.ok(path.segments[0] instanceof g.Path.segmentTypes.M);
assert.ok(path.segments[1] instanceof g.Path.segmentTypes.L);
assert.ok(path.segments[2] instanceof g.Path.segmentTypes.C);
assert.ok(path.segments[3] instanceof g.Path.segmentTypes.Z);
assert.equal(path.segments[0].end.toString(), '0@100');
assert.equal(path.segments[1].start.toString(), '0@100');
assert.equal(path.segments[1].end.toString(), '100@100');
assert.equal(path.segments[2].start.toString(), '100@100');
assert.equal(path.segments[2].controlPoint1.toString(), '150@150');
assert.equal(path.segments[2].controlPoint2.toString(), '250@50');
assert.equal(path.segments[2].end.toString(), '300@100');
assert.equal(path.segments[3].start.toString(), '300@100');
assert.equal(path.segments[3].end.toString(), '0@100');
// array of lines (linked)
path = new g.Path([
new g.Line(new g.Point(10, 10), new g.Point(11, 11)),
new g.Line(new g.Point(11, 11), new g.Point(21, 21))
]);
assert.ok(path instanceof g.Path, 'returns instance of g.Path');
assert.ok(typeof path.segments !== 'undefined', 'has "segments" property');
assert.ok(Array.isArray(path.segments));
assert.equal(path.segments.length, 3);
assert.ok(path.segments[0] instanceof g.Path.segmentTypes.M);
assert.ok(path.segments[1] instanceof g.Path.segmentTypes.L);
assert.ok(path.segments[2] instanceof g.Path.segmentTypes.L);
assert.equal(path.segments[0].end.toString(), '10@10');
assert.equal(path.segments[1].start.toString(), '10@10');
assert.equal(path.segments[1].end.toString(), '11@11');
assert.equal(path.segments[2].start.toString(), '11@11');
assert.equal(path.segments[2].end.toString(), '21@21');
// array of lines (unlinked)
path = new g.Path([
new g.Line(new g.Point(10, 10), new g.Point(11, 11)),
new g.Line(new g.Point(20, 20), new g.Point(21, 21))
]);
assert.ok(path instanceof g.Path, 'returns instance of g.Path');
assert.ok(typeof path.segments !== 'undefined', 'has "segments" property');
assert.ok(Array.isArray(path.segments));
assert.equal(path.segments.length, 4);
assert.ok(path.segments[0] instanceof g.Path.segmentTypes.M);
assert.ok(path.segments[1] instanceof g.Path.segmentTypes.L);
assert.ok(path.segments[2] instanceof g.Path.segmentTypes.M);
assert.ok(path.segments[3] instanceof g.Path.segmentTypes.L);
assert.equal(path.segments[0].end.toString(), '10@10');
assert.equal(path.segments[1].start.toString(), '10@10');
assert.equal(path.segments[1].end.toString(), '11@11');
assert.equal(path.segments[2].end.toString(), '20@20');
assert.equal(path.segments[3].start.toString(), '20@20');
assert.equal(path.segments[3].end.toString(), '21@21');
// array of curves (linked)
path = new g.Path([
new g.Curve(new g.Point(10, 10), new g.Point(11, 11), new g.Point(12, 12), new g.Point(13, 13)),
new g.Curve(new g.Point(13, 13), new g.Point(21, 21), new g.Point(22, 22), new g.Point(23, 23))
]);
assert.ok(path instanceof g.Path, 'returns instance of g.Path');
assert.ok(typeof path.segments !== 'undefined', 'has "segments" property');
assert.ok(Array.isArray(path.segments));
assert.equal(path.segments.length, 3);
assert.ok(path.segments[0] instanceof g.Path.segmentTypes.M);
assert.ok(path.segments[1] instanceof g.Path.segmentTypes.C);
assert.ok(path.segments[2] instanceof g.Path.segmentTypes.C);
assert.equal(path.segments[0].end.toString(), '10@10');
assert.equal(path.segments[1].start.toString(), '10@10');
assert.equal(path.segments[1].controlPoint1.toString(), '11@11');
assert.equal(path.segments[1].controlPoint2.toString(), '12@12');
assert.equal(path.segments[1].end.toString(), '13@13');
assert.equal(path.segments[2].start.toString(), '13@13');
assert.equal(path.segments[2].controlPoint1.toString(), '21@21');
assert.equal(path.segments[2].controlPoint2.toString(), '22@22');
assert.equal(path.segments[2].end.toString(), '23@23');
// array of curves (unlinked)
path = new g.Path([
new g.Curve(new g.Point(10, 10), new g.Point(11, 11), new g.Point(12, 12), new g.Point(13, 13)),
new g.Curve(new g.Point(20, 20), new g.Point(21, 21), new g.Point(22, 22), new g.Point(23, 23))
]);
assert.ok(path instanceof g.Path, 'returns instance of g.Path');
assert.ok(typeof path.segments !== 'undefined', 'has "segments" property');
assert.ok(Array.isArray(path.segments));
assert.equal(path.segments.length, 4);
assert.ok(path.segments[0] instanceof g.Path.segmentTypes.M);
assert.ok(path.segments[1] instanceof g.Path.segmentTypes.C);
assert.ok(path.segments[2] instanceof g.Path.segmentTypes.M);
assert.ok(path.segments[3] instanceof g.Path.segmentTypes.C);
assert.equal(path.segments[0].end.toString(), '10@10');
assert.equal(path.segments[1].start.toString(), '10@10');
assert.equal(path.segments[1].controlPoint1.toString(), '11@11');
assert.equal(path.segments[1].controlPoint2.toString(), '12@12');
assert.equal(path.segments[1].end.toString(), '13@13');
assert.equal(path.segments[2].end.toString(), '20@20');
assert.equal(path.segments[3].start.toString(), '20@20');
assert.equal(path.segments[3].controlPoint1.toString(), '21@21');
assert.equal(path.segments[3].controlPoint2.toString(), '22@22');
assert.equal(path.segments[3].end.toString(), '23@23');
// array of curves from g.Curve.throughPoints (linked)
path = new g.Path(g.Curve.throughPoints([
new g.Point(0, 100),
new g.Point(45.3125, 128.125),
new g.Point(154.6875, 71.875),
new g.Point(200, 100)
]));
assert.ok(path instanceof g.Path, 'returns instance of g.Path');
assert.ok(typeof path.segments !== 'undefined', 'has "segments" property');
assert.ok(Array.isArray(path.segments));
assert.equal(path.segments.length, 4);
assert.ok(path.segments[0] instanceof g.Path.segmentTypes.M);
assert.ok(path.segments[1] instanceof g.Path.segmentTypes.C);
assert.ok(path.segments[2] instanceof g.Path.segmentTypes.C);
assert.ok(path.segments[3] instanceof g.Path.segmentTypes.C);
assert.equal(path.segments[0].end.toString(), '0@100');
assert.equal(path.segments[1].start.toString(), '0@100');
assert.equal(path.segments[1].controlPoint1.toString(), '7.986111111111107@118.75');
assert.equal(path.segments[1].controlPoint2.toString(), '15.972222222222214@137.5');
assert.equal(path.segments[1].end.toString(), '45.3125@128.125');
assert.equal(path.segments[2].start.toString(), '45.3125@128.125');
assert.equal(path.segments[2].controlPoint1.toString(), '74.65277777777779@118.75');
assert.equal(path.segments[2].controlPoint2.toString(), '125.34722222222223@81.25');
assert.equal(path.segments[2].end.toString(), '154.6875@71.875');
assert.equal(path.segments[3].start.toString(), '154.6875@71.875');
assert.equal(path.segments[3].controlPoint1.toString(), '184.02777777777777@62.49999999999999');
assert.equal(path.segments[3].controlPoint2.toString(), '192.01388888888889@81.25');
assert.equal(path.segments[3].end.toString(), '200@100');
// array of lines and curves (linked)
path = new g.Path([
new g.Curve(new g.Point(10, 10), new g.Point(11, 11), new g.Point(12, 12), new g.Point(13, 13)),
new g.Line(new g.Point(13, 13), new g.Point(21, 21))
]);
assert.ok(path instanceof g.Path, 'returns instance of g.Path');
assert.ok(typeof path.segments !== 'undefined', 'has "segments" property');
assert.ok(Array.isArray(path.segments));
assert.equal(path.segments.length, 3);
assert.ok(path.segments[0] instanceof g.Path.segmentTypes.M);
assert.ok(path.segments[1] instanceof g.Path.segmentTypes.C);
assert.ok(path.segments[2] instanceof g.Path.segmentTypes.L);
assert.equal(path.segments[0].end.toString(), '10@10');
assert.equal(path.segments[1].start.toString(), '10@10');
assert.equal(path.segments[1].controlPoint1.toString(), '11@11');
assert.equal(path.segments[1].controlPoint2.toString(), '12@12');
assert.equal(path.segments[1].end.toString(), '13@13');
assert.equal(path.segments[2].start.toString(), '13@13');
assert.equal(path.segments[2].end.toString(), '21@21');
// array of lines and curves (unlinked)
path = new g.Path([
new g.Curve(new g.Point(10, 10), new g.Point(11, 11), new g.Point(12, 12), new g.Point(13, 13)),
new g.Line(new g.Point(20, 20), new g.Point(21, 21))
]);
assert.ok(path instanceof g.Path, 'returns instance of g.Path');
assert.ok(typeof path.segments !== 'undefined', 'has "segments" property');
assert.ok(Array.isArray(path.segments));
assert.equal(path.segments.length, 4);
assert.ok(path.segments[0] instanceof g.Path.segmentTypes.M);
assert.ok(path.segments[1] instanceof g.Path.segmentTypes.C);
assert.ok(path.segments[2] instanceof g.Path.segmentTypes.M);
assert.ok(path.segments[3] instanceof g.Path.segmentTypes.L);
assert.equal(path.segments[0].end.toString(), '10@10');
assert.equal(path.segments[1].start.toString(), '10@10');
assert.equal(path.segments[1].controlPoint1.toString(), '11@11');
assert.equal(path.segments[1].controlPoint2.toString(), '12@12');
assert.equal(path.segments[1].end.toString(), '13@13');
assert.equal(path.segments[2].end.toString(), '20@20');
assert.equal(path.segments[3].start.toString(), '20@20');
assert.equal(path.segments[3].end.toString(), '21@21');
// nested array of curves from g.Curve.throughPoints and lines from divideAt (linked)
path = new g.Path([
g.Curve.throughPoints([
new g.Point(0, 100),
new g.Point(45.3125, 128.125),
new g.Point(154.6875, 71.875),
new g.Point(200, 100)
]),
(new g.Line(new g.Point(200, 100), new g.Point(200, 200))).divideAt(0.5)
]);
assert.ok(path instanceof g.Path, 'returns instance of g.Path');
assert.ok(typeof path.segments !== 'undefined', 'has "segments" property');
assert.ok(Array.isArray(path.segments));
assert.equal(path.segments.length, 6);
assert.ok(path.segments[0] instanceof g.Path.segmentTypes.M);
assert.ok(path.segments[1] instanceof g.Path.segmentTypes.C);
assert.ok(path.segments[2] instanceof g.Path.segmentTypes.C);
assert.ok(path.segments[3] instanceof g.Path.segmentTypes.C);
assert.ok(path.segments[4] instanceof g.Path.segmentTypes.L);
assert.ok(path.segments[5] instanceof g.Path.segmentTypes.L);
assert.equal(path.segments[0].end.toString(), '0@100');
assert.equal(path.segments[1].start.toString(), '0@100');
assert.equal(path.segments[1].controlPoint1.toString(), '7.986111111111107@118.75');
assert.equal(path.segments[1].controlPoint2.toString(), '15.972222222222214@137.5');
assert.equal(path.segments[1].end.toString(), '45.3125@128.125');
assert.equal(path.segments[2].start.toString(), '45.3125@128.125');
assert.equal(path.segments[2].controlPoint1.toString(), '74.65277777777779@118.75');
assert.equal(path.segments[2].controlPoint2.toString(), '125.34722222222223@81.25');
assert.equal(path.segments[2].end.toString(), '154.6875@71.875');
assert.equal(path.segments[3].start.toString(), '154.6875@71.875');
assert.equal(path.segments[3].controlPoint1.toString(), '184.02777777777777@62.49999999999999');
assert.equal(path.segments[3].controlPoint2.toString(), '192.01388888888889@81.25');
assert.equal(path.segments[3].end.toString(), '200@100');
assert.equal(path.segments[4].start.toString(), '200@100');
assert.equal(path.segments[4].end.toString(), '200@150');
assert.equal(path.segments[5].start.toString(), '200@150');
assert.equal(path.segments[5].end.toString(), '200@200');
// nested array of curves from g.Curve.throughPoints and lines from divideAt (unlinked)
path = new g.Path([
g.Curve.throughPoints([
new g.Point(0, 100),
new g.Point(45.3125, 128.125),
new g.Point(154.6875, 71.875),
new g.Point(200, 100)
]),
(new g.Line(new g.Point(200, 200), new g.Point(200, 300))).divideAt(0.5)
]);
assert.ok(path instanceof g.Path, 'returns instance of g.Path');
assert.ok(typeof path.segments !== 'undefined', 'has "segments" property');
assert.ok(Array.isArray(path.segments));
assert.equal(path.segments.length, 7);
assert.ok(path.segments[0] instanceof g.Path.segmentTypes.M);
assert.ok(path.segments[1] instanceof g.Path.segmentTypes.C);
assert.ok(path.segments[2] instanceof g.Path.segmentTypes.C);
assert.ok(path.segments[3] instanceof g.Path.segmentTypes.C);
assert.ok(path.segments[4] instanceof g.Path.segmentTypes.M);
assert.ok(path.segments[5] instanceof g.Path.segmentTypes.L);
assert.ok(path.segments[6] instanceof g.Path.segmentTypes.L);
assert.equal(path.segments[0].end.toString(), '0@100');
assert.equal(path.segments[1].start.toString(), '0@100');
assert.equal(path.segments[1].controlPoint1.toString(), '7.986111111111107@118.75');
assert.equal(path.segments[1].controlPoint2.toString(), '15.972222222222214@137.5');
assert.equal(path.segments[1].end.toString(), '45.3125@128.125');
assert.equal(path.segments[2].start.toString(), '45.3125@128.125');
assert.equal(path.segments[2].controlPoint1.toString(), '74.65277777777779@118.75');
assert.equal(path.segments[2].controlPoint2.toString(), '125.34722222222223@81.25');
assert.equal(path.segments[2].end.toString(), '154.6875@71.875');
assert.equal(path.segments[3].start.toString(), '154.6875@71.875');
assert.equal(path.segments[3].controlPoint1.toString(), '184.02777777777777@62.49999999999999');
assert.equal(path.segments[3].controlPoint2.toString(), '192.01388888888889@81.25');
assert.equal(path.segments[3].end.toString(), '200@100');
assert.equal(path.segments[4].end.toString(), '200@200');
assert.equal(path.segments[5].start.toString(), '200@200');
assert.equal(path.segments[5].end.toString(), '200@250');
assert.equal(path.segments[6].start.toString(), '200@250');
assert.equal(path.segments[6].end.toString(), '200@300');
// array of unexpected objects (error)
try {
new g.Path([new g.Point(100, 100), new g.Point(200, 200)]);
} catch (e) {
error = e;
}
assert.ok(typeof error !== 'undefined', 'Should throw an error when constructor called with an array of unexpected objects.');
// single segment
path = new g.Path(g.Path.createSegment('L', 100, 100));
assert.ok(path instanceof g.Path, 'returns instance of g.Path');
assert.ok(typeof path.segments !== 'undefined', 'has "segments" property');
assert.ok(Array.isArray(path.segments));
assert.equal(path.segments.length, 1);
assert.ok(path.segments[0] instanceof g.Path.segmentTypes.L);
assert.equal(path.segments[0].end.toString(), '100@100');
// single line
path = new g.Path(new g.Line(new g.Point(100, 100), new g.Point(200, 200)));
assert.ok(path instanceof g.Path, 'returns instance of g.Path');
assert.ok(typeof path.segments !== 'undefined', 'has "segments" property');
assert.ok(Array.isArray(path.segments));
assert.equal(path.segments.length, 2);
assert.ok(path.segments[0] instanceof g.Path.segmentTypes.M);
assert.ok(path.segments[1] instanceof g.Path.segmentTypes.L);
assert.equal(path.segments[0].end.toString(), '100@100');
assert.equal(path.segments[1].start.toString(), '100@100');
assert.equal(path.segments[1].end.toString(), '200@200');
// single curve
path = new g.Path(new g.Curve(new g.Point(100, 100), new g.Point(100, 200), new g.Point(200, 200), new g.Point(200, 100)));
assert.ok(path instanceof g.Path, 'returns instance of g.Path');
assert.ok(typeof path.segments !== 'undefined', 'has "segments" property');
assert.ok(Array.isArray(path.segments));
assert.equal(path.segments.length, 2);
assert.ok(path.segments[0] instanceof g.Path.segmentTypes.M);
assert.ok(path.segments[1] instanceof g.Path.segmentTypes.C);
assert.equal(path.segments[0].end.toString(), '100@100');
assert.equal(path.segments[1].start.toString(), '100@100');
assert.equal(path.segments[1].controlPoint1.toString(), '100@200');
assert.equal(path.segments[1].controlPoint2.toString(), '200@200');
assert.equal(path.segments[1].end.toString(), '200@100');
// polyline with points
path = new g.Path(new g.Polyline([
new g.Point(0, 100),
new g.Point(50, 200),
new g.Point(150, 0),
new g.Point(200, 100)
]));
assert.ok(path instanceof g.Path, 'returns instance of g.Path');
assert.ok(typeof path.segments !== 'undefined', 'has "segments" property');
assert.ok(Array.isArray(path.segments));
assert.equal(path.segments.length, 4);
assert.ok(path.segments[0] instanceof g.Path.segmentTypes.M);
assert.ok(path.segments[1] instanceof g.Path.segmentTypes.L);
assert.ok(path.segments[2] instanceof g.Path.segmentTypes.L);
assert.ok(path.segments[3] instanceof g.Path.segmentTypes.L);
assert.equal(path.segments[0].end.toString(), '0@100');
assert.equal(path.segments[1].start.toString(), '0@100');
assert.equal(path.segments[1].end.toString(), '50@200');
assert.equal(path.segments[2].start.toString(), '50@200');
assert.equal(path.segments[2].end.toString(), '150@0');
assert.equal(path.segments[3].start.toString(), '150@0');
assert.equal(path.segments[3].end.toString(), '200@100');
// polyline with no points (invalid)
path = new g.Path(new g.Polyline());
assert.ok(path instanceof g.Path, 'returns instance of g.Path');
assert.ok(typeof path.segments !== 'undefined', 'has "segments" property');
assert.ok(Array.isArray(path.segments));
assert.equal(path.segments.length, 0);
// unexpected object (error)
try {
new g.Path(new g.Point(100, 100));
} catch (e) {
error = e;
}
assert.ok(typeof error !== 'undefined', 'Should throw an error when constructor called with an unexpected object.');
});
});
QUnit.module('parse()', function() {
QUnit.test('creates a new Path object from string', function(assert) {
var path;
// empty string (invalid)
path = new g.Path('');
assert.ok(path instanceof g.Path, 'returns instance of g.Path');
assert.ok(typeof path.segments !== 'undefined', 'has "segments" property');
assert.ok(Array.isArray(path.segments));
assert.equal(path.segments.length, 0);
// normalized path data string
path = new g.Path('M 0 100 L 100 100 C 150 150 250 50 300 100 Z');
assert.ok(path instanceof g.Path, 'returns instance of g.Path');
assert.ok(typeof path.segments !== 'undefined', 'has "segments" property');
assert.ok(Array.isArray(path.segments));
assert.equal(path.segments.length, 4);
assert.ok(path.segments[0] instanceof g.Path.segmentTypes.M);
assert.ok(path.segments[1] instanceof g.Path.segmentTypes.L);
assert.ok(path.segments[2] instanceof g.Path.segmentTypes.C);
assert.ok(path.segments[3] instanceof g.Path.segmentTypes.Z);
assert.equal(path.segments[0].end.toString(), '0@100');
assert.equal(path.segments[1].start.toString(), '0@100');
assert.equal(path.segments[1].end.toString(), '100@100');
assert.equal(path.segments[2].start.toString(), '100@100');
assert.equal(path.segments[2].controlPoint1.toString(), '150@150');
assert.equal(path.segments[2].controlPoint2.toString(), '250@50');
assert.equal(path.segments[2].end.toString(), '300@100');
assert.equal(path.segments[3].start.toString(), '300@100');
assert.equal(path.segments[3].end.toString(), '0@100');
// path data string without starting moveto (invalid)
path = new g.Path('L 100 100');
assert.ok(path instanceof g.Path, 'returns instance of g.Path');
assert.ok(typeof path.segments !== 'undefined', 'has "segments" property');
assert.ok(Array.isArray(path.segments));
assert.equal(path.segments.length, 1);
assert.ok(path.segments[0] instanceof g.Path.segmentTypes.L);
assert.equal(path.segments[0].end.toString(), '100@100');
// valid unnormalized path data string
path = new g.Path('M100-200L1.6.8ZM10,10C-.6,-.7,4.1 0.2.4-3');
assert.ok(path instanceof g.Path, 'returns instance of g.Path');
assert.ok(typeof path.segments !== 'undefined', 'has "segments" property');
assert.ok(Array.isArray(path.segments));
assert.equal(path.segments.length, 5);
assert.ok(path.segments[0] instanceof g.Path.segmentTypes.M);
assert.ok(path.segments[1] instanceof g.Path.segmentTypes.L);
assert.ok(path.segments[2] instanceof g.Path.segmentTypes.Z);
assert.ok(path.segments[3] instanceof g.Path.segmentTypes.M);
assert.ok(path.segments[4] instanceof g.Path.segmentTypes.C);
assert.equal(path.segments[0].end.toString(), '100@-200');
assert.equal(path.segments[1].start.toString(), '100@-200');
assert.equal(path.segments[1].end.toString(), '1.6@0.8');
assert.equal(path.segments[2].start.toString(), '1.6@0.8');
assert.equal(path.segments[2].end.toString(), '100@-200');
assert.equal(path.segments[3].end.toString(), '10@10');
assert.equal(path.segments[4].start.toString(), '10@10');
assert.equal(path.segments[4].controlPoint1.toString(), '-0.6@-0.7');
assert.equal(path.segments[4].controlPoint2.toString(), '4.1@0.2');
assert.equal(path.segments[4].end.toString(), '0.4@-3');
// valid unnormalized path data string with chained coordinates
path = new g.Path('M 11 11 21 21 C 31 31 32 32 33 33 41 41 42 42 43 43 L 51 51 52 52');
assert.ok(path instanceof g.Path, 'returns instance of g.Path');
assert.ok(typeof path.segments !== 'undefined', 'has "segments" property');
assert.ok(Array.isArray(path.segments));
assert.equal(path.segments.length, 6);
assert.ok(path.segments[0] instanceof g.Path.segmentTypes.M);
assert.ok(path.segments[1] instanceof g.Path.segmentTypes.L);
assert.ok(path.segments[2] instanceof g.Path.segmentTypes.C);
assert.ok(path.segments[3] instanceof g.Path.segmentTypes.C);
assert.ok(path.segments[4] instanceof g.Path.segmentTypes.L);
assert.ok(path.segments[5] instanceof g.Path.segmentTypes.L);
assert.equal(path.segments[0].end.toString(), '11@11');
assert.equal(path.segments[1].start.toString(), '11@11');
assert.equal(path.segments[1].end.toString(), '21@21');
assert.equal(path.segments[2].start.toString(), '21@21');
assert.equal(path.segments[2].controlPoint1.toString(), '31@31');
assert.equal(path.segments[2].controlPoint2.toString(), '32@32');
assert.equal(path.segments[2].end.toString(), '33@33');
assert.equal(path.segments[3].start.toString(), '33@33');
assert.equal(path.segments[3].controlPoint1.toString(), '41@41');
assert.equal(path.segments[3].controlPoint2.toString(), '42@42');
assert.equal(path.segments[3].end.toString(), '43@43');
assert.equal(path.segments[4].start.toString(), '43@43');
assert.equal(path.segments[4].end.toString(), '51@51');
assert.equal(path.segments[5].start.toString(), '51@51');
assert.equal(path.segments[5].end.toString(), '52@52');
// scientific notation
path = new g.Path('M 0 0 L 9.02e-17 -9.02e-7 L 1e-7 -1e-17 L 12.3e55 -12.3e+5 L 12e+55 -12e55');
assert.ok(path instanceof g.Path, 'returns instance of g.Path');
assert.ok(typeof path.segments !== 'undefined', 'has "segments" property');
assert.ok(Array.isArray(path.segments));
assert.equal(path.segments.length, 5);
assert.ok(path.segments[0] instanceof g.Path.segmentTypes.M);
assert.ok(path.segments[1] instanceof g.Path.segmentTypes.L);
assert.ok(path.segments[2] instanceof g.Path.segmentTypes.L);
assert.ok(path.segments[3] instanceof g.Path.segmentTypes.L);
assert.ok(path.segments[4] instanceof g.Path.segmentTypes.L);
assert.equal(path.segments[0].end.toString(), '0@0');
assert.equal(path.segments[1].start.toString(), '0@0');
var coords = path.segments[1].end.toString().split('@');
assert.equal(coords.length, 2);
assert.equal(Number(coords[0]), 9.02e-17);
assert.equal(Number(coords[1]), -9.02e-7);
coords = path.segments[2].end.toString().split('@');
assert.equal(coords.length, 2);
assert.equal(Number(coords[0]), 1e-7);
assert.equal(Number(coords[1]), -1e-17);
coords = path.segments[3].end.toString().split('@');
assert.equal(coords.length, 2);
assert.equal(Number(coords[0]), 12.3e55);
assert.equal(Number(coords[1]), -12.3e5);
coords = path.segments[4].end.toString().split('@');
assert.equal(coords.length, 2);
assert.equal(Number(coords[0]), 12e55);
assert.equal(Number(coords[1]), -12e55);
});
});
QUnit.module('createSegment()', function() {
QUnit.test('incorrect type', function(assert) {
var error;
// no type
try {
g.Path.createSegment();
} catch (e) {
error = e;
}
assert.ok(typeof error !== 'undefined', 'Should throw an error when called with no type.');
// unrecognized type
try {
g.Path.createSegment('X');
} catch (e) {
error = e;
}
assert.ok(typeof error !== 'undefined', 'Should throw an error when called with an unrecognized type.');
});
QUnit.test('moveto', function(assert) {
var segment;
var path = new g.Path();
var clonedPath;
var error;
// moveto -> lowercase
try {
segment = g.Path.createSegment('m');
} catch (e) {
error = e;
}
assert.ok(typeof error !== 'undefined', 'Should throw an error when called with lowercase `m` as type.');
// moveto -> no arguments (incorrect)
try {
segment = g.Path.createSegment('M');
} catch (e) {
error = e;
}
assert.ok(typeof error !== 'undefined', 'Should throw an error when M called with no arguments.');
// moveto -> 1 point (correct)
segment = g.Path.createSegment('M', new g.Point(10, 10));
assert.ok(segment instanceof g.Path.segmentTypes.M);
clonedPath = path.clone();
clonedPath.appendSegment(segment);
assert.equal(clonedPath.toString(), 'M 10 10');
// moveto -> 2 points (correct)
segment = g.Path.createSegment('M', new g.Point(10, 10), new g.Point(11, 11));
assert.ok(Array.isArray(segment));
assert.ok(segment[0] instanceof g.Path.segmentTypes.M);
assert.ok(segment[1] instanceof g.Path.segmentTypes.L);
clonedPath = path.clone();
clonedPath.appendSegment(segment);
assert.equal(clonedPath.toString(), 'M 10 10 L 11 11');
// moveto -> 1 plain object (correct)
segment = g.Path.createSegment('M', { x: 10, y: 10 });
assert.ok(segment instanceof g.Path.segmentTypes.M);
clonedPath = path.clone();
clonedPath.appendSegment(segment);
assert.equal(clonedPath.toString(), 'M 10 10');
// moveto -> 2 plain objects (correct)
segment = g.Path.createSegment('M', { x: 10, y: 10 }, { x: 11, y: 11 });
assert.ok(Array.isArray(segment));
assert.ok(segment[0] instanceof g.Path.segmentTypes.M);
assert.ok(segment[1] instanceof g.Path.segmentTypes.L);
clonedPath = path.clone();
clonedPath.appendSegment(segment);
assert.equal(clonedPath.toString(), 'M 10 10 L 11 11');
// moveto -> 1 string coordinate (incorrect)
try {
segment = g.Path.createSegment('M', '10');
} catch (e) {
error = e;
}
assert.ok(typeof error !== 'undefined', 'Should throw an error when M called with 1 string coordinate.');
// moveto -> 1 number coordinate (incorrect)
try {
segment = g.Path.createSegment('M', 10);
} catch (e) {
error = e;
}
assert.ok(typeof error !== 'undefined', 'Should throw an error when M called with 1 number coordinate.');
// moveto -> 2 string coordinates (correct)
segment = g.Path.createSegment('M', '10', '10');
assert.ok(segment instanceof g.Path.segmentTypes.M);
clonedPath = path.clone();
clonedPath.appendSegment(segment);
assert.equal(clonedPath.toString(), 'M 10 10');
// moveto -> 2 number coordinates (correct)
segment = g.Path.createSegment('M', 10, 10);
assert.ok(segment instanceof g.Path.segmentTypes.M);
clonedPath = path.clone();
clonedPath.appendSegment(segment);
assert.equal(clonedPath.toString(), 'M 10 10');
// moveto -> 2 mixed coordinates (correct)
segment = g.Path.createSegment('M', '10', 10);
assert.ok(segment instanceof g.Path.segmentTypes.M);
clonedPath = path.clone();
clonedPath.appendSegment(segment);
assert.equal(clonedPath.toString(), 'M 10 10');
// moveto -> 3 coordinates (incorrect)
try {
segment = g.Path.createSegment('M', '10', '10', '10');
} catch (e) {
error = e;
}
assert.ok(typeof error !== 'undefined', 'Should throw an error when M called with 3 coordinates.');
// moveto -> 4 coordinates (correct)
segment = g.Path.createSegment('M', '10', '10', '11', '11');
assert.ok(Array.isArray(segment));
assert.ok(segment[0] instanceof g.Path.segmentTypes.M);
assert.ok(segment[1] instanceof g.Path.segmentTypes.L);
clonedPath = path.clone();
clonedPath.appendSegment(segment);
assert.equal(clonedPath.toString(), 'M 10 10 L 11 11');
// moveto -> 1 line (correct)
segment = g.Path.createSegment('M', new g.Line('10 10', '10 20'));
assert.ok(segment instanceof g.Path.segmentTypes.M);
clonedPath = path.clone();
clonedPath.appendSegment(segment);
assert.equal(clonedPath.toString(), 'M 10 20');
// moveto -> 2 lines (incorrect)
try {
segment = g.Path.createSegment('M', new g.Line('10 10', '10 20'), new g.Line('10 20', '20 20'));
} catch (e) {
error = e;
}
assert.ok(typeof error !== 'undefined', 'Should throw an error when M called with 2 lines.');
// moveto -> 1 curve (correct)
segment = g.Path.createSegment('M', new g.Curve('10 10', '10 20', '20 0', '20 10'));
assert.ok(segment instanceof g.Path.segmentTypes.M);
clonedPath = path.clone();
clonedPath.appendSegment(segment);
assert.equal(clonedPath.toString(), 'M 20 10');
// moveto -> 2 curves (incorrect)
try {
segment = g.Path.createSegment('M', new g.Curve('10 10', '10 20', '20 0', '20 10'), new g.Curve('20 10', '20 20', '30 0', '30 10'));
} catch (e) {
error = e;
}
assert.ok(typeof error !== 'undefined', 'Should throw an error when M called with 2 curves.');
// moveto functions
segment = g.Path.createSegment('M', '10', '10');
assert.equal(segment.bbox(), null);
assert.equal(segment.closestPoint(new g.Point('20', '20')).toString(), '10@10');
});
QUnit.test('lineto', function(assert) {
var segment;
var path = new g.Path();
var clonedPath;
var error;
// lineto -> lowercase
try {
segment = g.Path.createSegment('l');
} catch (e) {
error = e;
}
assert.ok(typeof error !== 'undefined', 'Should throw an error when called with lowercase `l` as type.');
// lineto -> no arguments (incorrect)
try {
segment = g.Path.createSegment('L');
} catch (e) {
error = e;
}
assert.ok(typeof error !== 'undefined', 'Should throw an error when L called with no arguments.');
// lineto -> 1 point (correct)
segment = g.Path.createSegment('L', new g.Point(10, 10));
assert.ok(segment instanceof g.Path.segmentTypes.L);
clonedPath = path.clone();
clonedPath.appendSegment(segment);
assert.equal(clonedPath.toString(), 'L 10 10');
// lineto -> 2 points (correct)
segment = g.Path.createSegment('L', new g.Point(10, 10), new g.Point(11, 11));
assert.ok(Array.isArray(segment));
assert.ok(segment[0] instanceof g.Path.segmentTypes.L);
assert.ok(segment[1] instanceof g.Path.segmentTypes.L);
clonedPath = path.clone();
clonedPath.appendSegment(segment);
assert.equal(clonedPath.toString(), 'L 10 10 L 11 11');
// lineto -> 1 plain object (correct)
segment = g.Path.createSegment('L', { x: 10, y: 10 });
assert.ok(segment instanceof g.Path.segmentTypes.L);
clonedPath = path.clone();
clonedPath.appendSegment(segment);
assert.equal(clonedPath.toString(), 'L 10 10');
// lineto -> 2 plain objects (correct)
segment = g.Path.createSegment('L', { x: 10, y: 10 }, { x: 11, y: 11 });
assert.ok(Array.isArray(segment));
assert.ok(segment[0] instanceof g.Path.segmentTypes.L);
assert.ok(segment[1] instanceof g.Path.segmentTypes.L);
clonedPath = path.clone();
clonedPath.appendSegment(segment);
assert.equal(clonedPath.toString(), 'L 10 10 L 11 11');
// lineto -> 1 string coordinate (incorrect)
try {
segment = g.Path.createSegment('L', '10');
} catch (e) {
error = e;
}
assert.ok(typeof error !== 'undefined', 'Should throw an error when L called with 1 string coordinate.');
// lineto -> 1 number coordinate (incorrect)
try {
segment = g.Path.createSegment('L', 10);
} catch (e) {
error = e;
}
assert.ok(typeof error !== 'undefined', 'Should throw an error when L called with 1 number coordinate.');
// lineto -> 2 string coordinates (correct)
segment = g.Path.createSegment('L', '10', '10');
assert.ok(segment instanceof g.Path.segmentTypes.L);
clonedPath = path.clone();
clonedPath.appendSegment(segment);
assert.equal(clonedPath.toString(), 'L 10 10');
// lineto -> 2 number coordinates (correct)
segment = g.Path.createSegment('L', 10, 10);
assert.ok(segment instanceof g.Path.segmentTypes.L);
clonedPath = path.clone();
clonedPath.appendSegment(segment);
assert.equal(clonedPath.toString(), 'L 10 10');
// lineto -> 2 mixed coordinates (correct)
segment = g.Path.createSegment('L', '10', 10);
assert.ok(segment instanceof g.Path.segmentTypes.L);
clonedPath = path.clone();
clonedPath.appendSegment(segment);
assert.equal(clonedPath.toString(), 'L 10 10');
// lineto -> 3 coordinates (incorrect)
try {
segment = g.Path.createSegment('L', '10', '10', '10');
} catch (e) {
error = e;
}
assert.ok(typeof error !== 'undefined', 'Should throw an error when L called with 3 coordinates.');
// lineto -> 4 coordinates (correct)
segment = g.Path.createSegment('L', '10', '10', '11', '11');
assert.ok(Array.isArray(segment));
assert.ok(segment[0] instanceof g.Path.segmentTypes.L);
assert.ok(segment[1] instanceof g.Path.segmentTypes.L);
clonedPath = path.clone();
clonedPath.appendSegment(segment);
assert.equal(clonedPath.toString(), 'L 10 10 L 11 11');
// lineto -> 1 line (correct)
segment = g.Path.createSegment('L', new g.Line('10 10', '10 20'));
assert.ok(segment instanceof g.Path.segmentTypes.L);
clonedPath = path.clone();
clonedPath.appendSegment(segment);
assert.equal(clonedPath.toString(), 'L 10 20');
// lineto -> 2 lines (incorrect)
try {
segment = g.Path.createSegment('L', new g.Line('10 10', '10 20'), new g.Line('10 20', '20 20'));
} catch (e) {
error = e;
}
assert.ok(typeof error !== 'undefined', 'Should throw an error when L called with 2 lines.');
});
QUnit.test('curveto', function(assert) {
var segment;
var path = new g.Path();
var clonedPath;
var error;
// curveto -> lowercase
try {
segment = g.Path.createSegment('c');
} catch (e) {
error = e;
}
assert.ok(typeof error !== 'undefined', 'Should throw an error when called with lowercase `c` as type.');
// curveto -> no arguments (incorrect)
try {
segment = g.Path.createSegment('C');
} catch (e) {
error = e;
}
assert.ok(typeof error !== 'undefined', 'Should throw an error when C called with no arguments.');
// curveto -> 2 points (incorrect)
try {
segment = g.Path.createSegment('C', new g.Point(10, 10), new g.Point(11, 11));
} catch (e) {
error = e;
}
assert.ok(typeof error !== 'undefined', 'Should throw an error when C called with 2 points.');
// curveto -> 3 points (correct)
segment = g.Path.createSegment('C', new g.Point(10, 10), new g.Point(11, 11), new g.Point(12, 12));
assert.ok(segment instanceof g.Path.segmentTypes.C);
clonedPath = path.clone();
clonedPath.appendSegment(segment);
assert.equal(clonedPath.toString(), 'C 10 10 11 11 12 12');
// curveto -> 5 points (incorrect)
try {
segment = g.Path.createSegment('C', new g.Point(10, 10), new g.Point(11, 11), new g.Point(12, 12), new g.Point(13, 13), new g.Point(14, 14));
} catch (e) {
error = e;
}
assert.ok(typeof error !== 'undefined', 'Should throw an error when C called with 5 points.');
// curveto -> 6 points (correct)
segment = g.Path.createSegment('C', new g.Point(10, 10), new g.Point(11, 11), new g.Point(12, 12), new g.Point(13, 13), new g.Point(14, 14), new g.Point(15, 15));
assert.ok(Array.isArray(segment));
assert.ok(segment[0] instanceof g.Path.segmentTypes.C);
assert.ok(segment[1] instanceof g.Path.segmentTypes.C);
clonedPath = path.clone();
clonedPath.appendSegment(segment);
assert.equal(clonedPath.toString(), 'C 10 10 11 11 12 12 C 13 13 14 14 15 15');
// curveto -> 2 plain objects (incorrect)
try {
segment = g.Path.createSegment('C', { x: 10, y: 10 }, { x: 11, y: 11 });
} catch (e) {
error = e;
}
assert.ok(typeof error !== 'undefined', 'Should throw an error when C called with 2 points.');
// curveto -> 3 plain objects (correct)
segment = g.Path.createSegment('C', { x: 10, y: 10 }, { x: 11, y: 11 }, { x: 12, y: 12 });
assert.ok(segment instanceof g.Path.segmentTypes.C);
clonedPath = path.clone();
clonedPath.appendSegment(segment);
assert.equal(clonedPath.toString(), 'C 10 10 11 11 12 12');
// curveto -> 5 plain objects (incorrect)
try {
segment = g.Path.createSegment('C', { x: 10, y: 10 }, { x: 11, y: 11 }, { x: 12, y: 12 }, { x: 13, y: 13 }, { x: 14, y: 14 });
} catch (e) {
error = e;
}
assert.ok(typeof error !== 'undefined', 'Should throw an error when C called with 5 points.');
// curveto -> 6 plain objects (correct)
segment = g.Path.createSegment('C', { x: 10, y: 10 }, { x: 11, y: 11 }, { x: 12, y: 12 }, { x: 13, y: 13 }, { x: 14, y: 14 }, { x: 15, y: 15 });
assert.ok(Array.isArray(segment));
assert.ok(segment[0] instanceof g.Path.segmentTypes.C);
assert.ok(segment[1] instanceof g.Path.segmentTypes.C);
clonedPath = path.clone();
clonedPath.appendSegment(segment);
assert.equal(clonedPath.toString(), 'C 10 10 11 11 12 12 C 13 13 14 14 15 15');
// curveto -> 5 string coordinates (incorrect)
try {
segment = g.Path.createSegment('C', '1', '2', '3', '4', '5');
} catch (e) {
error = e;
}
assert.ok(typeof error !== 'undefined', 'Should throw an error when C called with 5 string coordinates.');
// curveto -> 5 number coordinates (incorrect)
try {
segment = g.Path.createSegment('C', 1, 2, 3, 4, 5);
} catch (e) {
error = e;
}
assert.ok(typeof error !== 'undefined', 'Should throw an error when C called with 5 number coordinates.');
// curveto -> 6 string coordinates (correct)
segment = g.Path.createSegment('C', '10', '10', '11', '11', '12', '12');
assert.ok(segment instanceof g.Path.segmentTypes.C);
clonedPath = path.clone();
clonedPath.appendSegment(segment);
assert.equal(clonedPath.toString(), 'C 10 10 11 11 12 12');
// curveto -> 6 number coordinates (correct)
segment = g.Path.createSegment('C', 10, 10, 11, 11, 12, 12);
assert.ok(segment instanceof g.Path.segmentTypes.C);
clonedPath = path.clone();
clonedPath.appendSegment(segment);
assert.equal(clonedPath.toString(), 'C 10 10 11 11 12 12');
// curveto -> 6 mixed coordinates (correct)
segment = g.Path.createSegment('C', 10, '10', '11', '11', 12, 12);
assert.ok(segment instanceof g.Path.segmentTypes.C);
clonedPath = path.clone();
clonedPath.appendSegment(segment);
assert.equal(clonedPath.toString(), 'C 10 10 11 11 12 12');
// curv