UNPKG

jointjs

Version:

JavaScript diagramming library

947 lines (844 loc) 236 kB
'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