pax_global_header 0000666 0000000 0000000 00000000064 13060564427 0014521 g ustar 00root root 0000000 0000000 52 comment=1c1b7927faa4948f91fff8bd7ee81edfaa330d73
d3-path-1.0.5/ 0000775 0000000 0000000 00000000000 13060564427 0012764 5 ustar 00root root 0000000 0000000 d3-path-1.0.5/.eslintrc 0000664 0000000 0000000 00000000176 13060564427 0014614 0 ustar 00root root 0000000 0000000 parserOptions:
sourceType: module
env:
es6: true
browser: true
node: true
extends:
"eslint:recommended"
d3-path-1.0.5/.gitignore 0000664 0000000 0000000 00000000100 13060564427 0014743 0 ustar 00root root 0000000 0000000 *.sublime-workspace
.DS_Store
build/
node_modules
npm-debug.log
d3-path-1.0.5/.npmignore 0000664 0000000 0000000 00000000036 13060564427 0014762 0 ustar 00root root 0000000 0000000 *.sublime-*
build/*.zip
test/
d3-path-1.0.5/LICENSE 0000664 0000000 0000000 00000002703 13060564427 0013773 0 ustar 00root root 0000000 0000000 Copyright 2015-2016 Mike Bostock
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of the author nor the names of contributors may be used to
endorse or promote products derived from this software without specific prior
written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
d3-path-1.0.5/README.md 0000664 0000000 0000000 00000015175 13060564427 0014254 0 ustar 00root root 0000000 0000000 # d3-path
Say you have some code that draws to a 2D canvas:
```js
function drawCircle(context, radius) {
context.moveTo(radius, 0);
context.arc(0, 0, radius, 0, 2 * Math.PI);
}
```
The d3-path module lets you take this exact code and additionally render to [SVG](http://www.w3.org/TR/SVG/paths.html). It works by [serializing](#path_toString) [CanvasPathMethods](http://www.w3.org/TR/2dcontext/#canvaspathmethods) calls to [SVG path data](http://www.w3.org/TR/SVG/paths.html#PathData). For example:
```js
var context = d3.path();
drawCircle(context, 40);
pathElement.setAttribute("d", context.toString());
```
Now code you write once can be used with both Canvas (for performance) and SVG (for convenience). For a practical example, see [d3-shape](https://github.com/d3/d3-shape).
## Installing
If you use NPM, `npm install d3-path`. Otherwise, download the [latest release](https://github.com/d3/d3-path/releases/latest). You can also load directly from [d3js.org](https://d3js.org), either as a [standalone library](https://d3js.org/d3-path.v1.min.js) or as part of [D3 4.0](https://github.com/d3/d3). AMD, CommonJS, and vanilla environments are supported. In vanilla, a `d3` global is exported:
```html
```
[Try d3-path in your browser.](https://tonicdev.com/npm/d3-path)
## API Reference
# d3.path() [<>](https://github.com/d3/d3-path/blob/master/src/path.js "Source")
Constructs a new path serializer that implements [CanvasPathMethods](http://www.w3.org/TR/2dcontext/#canvaspathmethods).
# path.moveTo(x, y) [<>](https://github.com/d3/d3-path/blob/master/src/path.js#L18 "Source")
Move to the specified point ⟨*x*, *y*⟩. Equivalent to [*context*.moveTo](http://www.w3.org/TR/2dcontext/#dom-context-2d-moveto) and SVG’s [“moveto” command](http://www.w3.org/TR/SVG/paths.html#PathDataMovetoCommands).
# path.closePath() [<>](https://github.com/d3/d3-path/blob/master/src/path.js#L21 "Source")
Ends the current subpath and causes an automatic straight line to be drawn from the current point to the initial point of the current subpath. Equivalent to [*context*.closePath](http://www.w3.org/TR/2dcontext/#dom-context-2d-closepath) and SVG’s [“closepath” command](http://www.w3.org/TR/SVG/paths.html#PathDataClosePathCommand).
# path.lineTo(x, y) [<>](https://github.com/d3/d3-path/blob/master/src/path.js#L27 "Source")
Draws a straight line from the current point to the specified point ⟨*x*, *y*⟩. Equivalent to [*context*.lineTo](http://www.w3.org/TR/2dcontext/#dom-context-2d-lineto) and SVG’s [“lineto” command](http://www.w3.org/TR/SVG/paths.html#PathDataLinetoCommands).
# path.quadraticCurveTo(cpx, cpy, x, y) [<>](https://github.com/d3/d3-path/blob/master/src/path.js#L30 "Source")
Draws a quadratic Bézier segment from the current point to the specified point ⟨*x*, *y*⟩, with the specified control point ⟨*cpx*, *cpy*⟩. Equivalent to [*context*.quadraticCurveTo](http://www.w3.org/TR/2dcontext/#dom-context-2d-quadraticcurveto) and SVG’s [quadratic Bézier curve commands](http://www.w3.org/TR/SVG/paths.html#PathDataQuadraticBezierCommands).
# path.bezierCurveTo(cpx1, cpy1, cpx2, cpy2, x, y) [<>](https://github.com/d3/d3-path/blob/master/src/path.js#L33 "Source")
Draws a cubic Bézier segment from the current point to the specified point ⟨*x*, *y*⟩, with the specified control points ⟨*cpx1*, *cpy1*⟩ and ⟨*cpx2*, *cpy2*⟩. Equivalent to [*context*.bezierCurveTo](http://www.w3.org/TR/2dcontext/#dom-context-2d-beziercurveto) and SVG’s [cubic Bézier curve commands](http://www.w3.org/TR/SVG/paths.html#PathDataCubicBezierCommands).
# path.arcTo(x1, y1, x2, y2, radius) [<>](https://github.com/d3/d3-path/blob/master/src/path.js#L36 "Source")
Draws a circular arc segment with the specified *radius* that starts tangent to the line between the current point and the specified point ⟨*x1*, *y1*⟩ and ends tangent to the line between the specified points ⟨*x1*, *y1*⟩ and ⟨*x2*, *y2*⟩. If the first tangent point is not equal to the current point, a straight line is drawn between the current point and the first tangent point. Equivalent to [*context*.arcTo](http://www.w3.org/TR/2dcontext/#dom-context-2d-arcto) and uses SVG’s [elliptical arc curve commands](http://www.w3.org/TR/SVG/paths.html#PathDataEllipticalArcCommands).
# path.arc(x, y, radius, startAngle, endAngle[, anticlockwise]) [<>](https://github.com/d3/d3-path/blob/master/src/path.js#L84 "Source")
Draws a circular arc segment with the specified center ⟨*x*, *y*⟩, *radius*, *startAngle* and *endAngle*. If *anticlockwise* is true, the arc is drawn in the anticlockwise direction; otherwise, it is drawn in the clockwise direction. If the current point is not equal to the starting point of the arc, a straight line is drawn from the current point to the start of the arc. Equivalent to [*context*.arc](http://www.w3.org/TR/2dcontext/#dom-context-2d-arc) and uses SVG’s [elliptical arc curve commands](http://www.w3.org/TR/SVG/paths.html#PathDataEllipticalArcCommands).
# path.rect(x, y, w, h) [<>](https://github.com/d3/d3-path/blob/master/src/path.js#L122 "Source")
Creates a new subpath containing just the four points ⟨*x*, *y*⟩, ⟨*x* + *w*, *y*⟩, ⟨*x* + *w*, *y* + *h*⟩, ⟨*x*, *y* + *h*⟩, with those four points connected by straight lines, and then marks the subpath as closed. Equivalent to [*context*.rect](http://www.w3.org/TR/2dcontext/#dom-context-2d-rect) and uses SVG’s [“lineto” commands](http://www.w3.org/TR/SVG/paths.html#PathDataLinetoCommands).
# path.toString() [<>](https://github.com/d3/d3-path/blob/master/src/path.js#L125 "Source")
Returns the string representation of this *path* according to SVG’s [path data specficiation](http://www.w3.org/TR/SVG/paths.html#PathData).
d3-path-1.0.5/d3-path.sublime-project 0000664 0000000 0000000 00000000271 13060564427 0017252 0 ustar 00root root 0000000 0000000 {
"folders": [
{
"path": ".",
"file_exclude_patterns": [
"*.sublime-workspace"
],
"folder_exclude_patterns": [
"build"
]
}
]
}
d3-path-1.0.5/index.js 0000664 0000000 0000000 00000000054 13060564427 0014430 0 ustar 00root root 0000000 0000000 export {default as path} from "./src/path";
d3-path-1.0.5/package.json 0000664 0000000 0000000 00000002667 13060564427 0015265 0 ustar 00root root 0000000 0000000 {
"name": "d3-path",
"version": "1.0.5",
"description": "Serialize Canvas path commands to SVG.",
"keywords": [
"d3",
"d3-module",
"canvas",
"path",
"svg",
"graphics",
"CanvasRenderingContext2D",
"CanvasPathMethods",
"Path2D"
],
"homepage": "https://d3js.org/d3-path/",
"license": "BSD-3-Clause",
"author": {
"name": "Mike Bostock",
"url": "http://bost.ocks.org/mike"
},
"main": "build/d3-path.js",
"module": "index",
"jsnext:main": "index",
"repository": {
"type": "git",
"url": "https://github.com/d3/d3-path.git"
},
"scripts": {
"pretest": "rm -rf build && mkdir build && rollup --banner \"$(preamble)\" -f umd -n d3 -o build/d3-path.js -- index.js",
"test": "tape 'test/**/*-test.js' && eslint index.js src",
"prepublish": "npm run test && uglifyjs --preamble \"$(preamble)\" build/d3-path.js -c -m -o build/d3-path.min.js",
"postpublish": "git push && git push --tags && cd ../d3.github.com && git pull && cp ../d3-path/build/d3-path.js d3-path.v1.js && cp ../d3-path/build/d3-path.min.js d3-path.v1.min.js && git add d3-path.v1.js d3-path.v1.min.js && git commit -m \"d3-path ${npm_package_version}\" && git push && cd - && zip -j build/d3-path.zip -- LICENSE README.md build/d3-path.js build/d3-path.min.js"
},
"devDependencies": {
"eslint": "3",
"package-preamble": "0.0",
"rollup": "0.41",
"tape": "4",
"uglify-js": "^2.8.11"
}
}
d3-path-1.0.5/src/ 0000775 0000000 0000000 00000000000 13060564427 0013553 5 ustar 00root root 0000000 0000000 d3-path-1.0.5/src/path.js 0000664 0000000 0000000 00000010122 13060564427 0015041 0 ustar 00root root 0000000 0000000 var pi = Math.PI,
tau = 2 * pi,
epsilon = 1e-6,
tauEpsilon = tau - epsilon;
function Path() {
this._x0 = this._y0 = // start of current subpath
this._x1 = this._y1 = null; // end of current subpath
this._ = "";
}
function path() {
return new Path;
}
Path.prototype = path.prototype = {
constructor: Path,
moveTo: function(x, y) {
this._ += "M" + (this._x0 = this._x1 = +x) + "," + (this._y0 = this._y1 = +y);
},
closePath: function() {
if (this._x1 !== null) {
this._x1 = this._x0, this._y1 = this._y0;
this._ += "Z";
}
},
lineTo: function(x, y) {
this._ += "L" + (this._x1 = +x) + "," + (this._y1 = +y);
},
quadraticCurveTo: function(x1, y1, x, y) {
this._ += "Q" + (+x1) + "," + (+y1) + "," + (this._x1 = +x) + "," + (this._y1 = +y);
},
bezierCurveTo: function(x1, y1, x2, y2, x, y) {
this._ += "C" + (+x1) + "," + (+y1) + "," + (+x2) + "," + (+y2) + "," + (this._x1 = +x) + "," + (this._y1 = +y);
},
arcTo: function(x1, y1, x2, y2, r) {
x1 = +x1, y1 = +y1, x2 = +x2, y2 = +y2, r = +r;
var x0 = this._x1,
y0 = this._y1,
x21 = x2 - x1,
y21 = y2 - y1,
x01 = x0 - x1,
y01 = y0 - y1,
l01_2 = x01 * x01 + y01 * y01;
// Is the radius negative? Error.
if (r < 0) throw new Error("negative radius: " + r);
// Is this path empty? Move to (x1,y1).
if (this._x1 === null) {
this._ += "M" + (this._x1 = x1) + "," + (this._y1 = y1);
}
// Or, is (x1,y1) coincident with (x0,y0)? Do nothing.
else if (!(l01_2 > epsilon)) {}
// Or, are (x0,y0), (x1,y1) and (x2,y2) collinear?
// Equivalently, is (x1,y1) coincident with (x2,y2)?
// Or, is the radius zero? Line to (x1,y1).
else if (!(Math.abs(y01 * x21 - y21 * x01) > epsilon) || !r) {
this._ += "L" + (this._x1 = x1) + "," + (this._y1 = y1);
}
// Otherwise, draw an arc!
else {
var x20 = x2 - x0,
y20 = y2 - y0,
l21_2 = x21 * x21 + y21 * y21,
l20_2 = x20 * x20 + y20 * y20,
l21 = Math.sqrt(l21_2),
l01 = Math.sqrt(l01_2),
l = r * Math.tan((pi - Math.acos((l21_2 + l01_2 - l20_2) / (2 * l21 * l01))) / 2),
t01 = l / l01,
t21 = l / l21;
// If the start tangent is not coincident with (x0,y0), line to.
if (Math.abs(t01 - 1) > epsilon) {
this._ += "L" + (x1 + t01 * x01) + "," + (y1 + t01 * y01);
}
this._ += "A" + r + "," + r + ",0,0," + (+(y01 * x20 > x01 * y20)) + "," + (this._x1 = x1 + t21 * x21) + "," + (this._y1 = y1 + t21 * y21);
}
},
arc: function(x, y, r, a0, a1, ccw) {
x = +x, y = +y, r = +r;
var dx = r * Math.cos(a0),
dy = r * Math.sin(a0),
x0 = x + dx,
y0 = y + dy,
cw = 1 ^ ccw,
da = ccw ? a0 - a1 : a1 - a0;
// Is the radius negative? Error.
if (r < 0) throw new Error("negative radius: " + r);
// Is this path empty? Move to (x0,y0).
if (this._x1 === null) {
this._ += "M" + x0 + "," + y0;
}
// Or, is (x0,y0) not coincident with the previous point? Line to (x0,y0).
else if (Math.abs(this._x1 - x0) > epsilon || Math.abs(this._y1 - y0) > epsilon) {
this._ += "L" + x0 + "," + y0;
}
// Is this arc empty? We’re done.
if (!r) return;
// Does the angle go the wrong way? Flip the direction.
if (da < 0) da = da % tau + tau;
// Is this a complete circle? Draw two arcs to complete the circle.
if (da > tauEpsilon) {
this._ += "A" + r + "," + r + ",0,1," + cw + "," + (x - dx) + "," + (y - dy) + "A" + r + "," + r + ",0,1," + cw + "," + (this._x1 = x0) + "," + (this._y1 = y0);
}
// Is this arc non-empty? Draw an arc!
else if (da > epsilon) {
this._ += "A" + r + "," + r + ",0," + (+(da >= pi)) + "," + cw + "," + (this._x1 = x + r * Math.cos(a1)) + "," + (this._y1 = y + r * Math.sin(a1));
}
},
rect: function(x, y, w, h) {
this._ += "M" + (this._x0 = this._x1 = +x) + "," + (this._y0 = this._y1 = +y) + "h" + (+w) + "v" + (+h) + "h" + (-w) + "Z";
},
toString: function() {
return this._;
}
};
export default path;
d3-path-1.0.5/test/ 0000775 0000000 0000000 00000000000 13060564427 0013743 5 ustar 00root root 0000000 0000000 d3-path-1.0.5/test/path-test.js 0000664 0000000 0000000 00000032203 13060564427 0016212 0 ustar 00root root 0000000 0000000 var tape = require("tape"),
path = require("../");
require("./pathEqual");
tape("path is an instanceof path", function(test) {
var p = path.path();
test.ok(p instanceof path.path);
test.equal(p.constructor.name, "Path");
test.pathEqual(p, "");
test.end();
});
tape("path.moveTo(x, y) appends an M command", function(test) {
var p = path.path(); p.moveTo(150, 50);
test.pathEqual(p, "M150,50");
p.lineTo(200, 100);
test.pathEqual(p, "M150,50L200,100");
p.moveTo(100, 50);
test.pathEqual(p, "M150,50L200,100M100,50");
test.end();
});
tape("path.closePath() appends a Z command", function(test) {
var p = path.path(); p.moveTo(150, 50);
test.pathEqual(p, "M150,50");
p.closePath();
test.pathEqual(p, "M150,50Z");
p.closePath();
test.pathEqual(p, "M150,50ZZ");
test.end();
});
tape("path.closePath() does nothing if the path is empty", function(test) {
var p = path.path();
test.pathEqual(p, "");
p.closePath();
test.pathEqual(p, "");
test.end();
});
tape("path.lineTo(x, y) appends an L command", function(test) {
var p = path.path(); p.moveTo(150, 50);
test.pathEqual(p, "M150,50");
p.lineTo(200, 100);
test.pathEqual(p, "M150,50L200,100");
p.lineTo(100, 50);
test.pathEqual(p, "M150,50L200,100L100,50");
test.end();
});
tape("path.quadraticCurveTo(x1, y1, x, y) appends a Q command", function(test) {
var p = path.path(); p.moveTo(150, 50);
test.pathEqual(p, "M150,50");
p.quadraticCurveTo(100, 50, 200, 100);
test.pathEqual(p, "M150,50Q100,50,200,100");
test.end();
});
tape("path.bezierCurveTo(x1, y1, x, y) appends a C command", function(test) {
var p = path.path(); p.moveTo(150, 50);
test.pathEqual(p, "M150,50");
p.bezierCurveTo(100, 50, 0, 24, 200, 100);
test.pathEqual(p, "M150,50C100,50,0,24,200,100");
test.end();
});
tape("path.arc(x, y, radius, startAngle, endAngle) throws an error if the radius is negative", function(test) {
var p = path.path(); p.moveTo(150, 100);
test.throws(function() { p.arc(100, 100, -50, 0, Math.PI / 2); }, /negative radius/);
test.end();
});
tape("path.arc(x, y, radius, startAngle, endAngle) may append only an M command if the radius is zero", function(test) {
var p = path.path(); p.arc(100, 100, 0, 0, Math.PI / 2);
test.pathEqual(p, "M100,100");
test.end();
});
tape("path.arc(x, y, radius, startAngle, endAngle) may append only an L command if the radius is zero", function(test) {
var p = path.path(); p.moveTo(0, 0); p.arc(100, 100, 0, 0, Math.PI / 2);
test.pathEqual(p, "M0,0L100,100");
test.end();
});
tape("path.arc(x, y, radius, startAngle, endAngle) may append only an M command if the angle is zero", function(test) {
var p = path.path(); p.arc(100, 100, 0, 0, 0);
test.pathEqual(p, "M100,100");
test.end();
});
tape("path.arc(x, y, radius, startAngle, endAngle) may append only an M command if the angle is near zero", function(test) {
var p = path.path(); p.arc(100, 100, 0, 0, 1e-16);
test.pathEqual(p, "M100,100");
test.end();
});
tape("path.arc(x, y, radius, startAngle, endAngle) may append an M command if the path was empty", function(test) {
var p = path.path(); p.arc(100, 100, 50, 0, Math.PI * 2);
test.pathEqual(p, "M150,100A50,50,0,1,1,50,100A50,50,0,1,1,150,100");
p = path.path(); p.arc(0, 50, 50, -Math.PI / 2, 0);
test.pathEqual(p, "M0,0A50,50,0,0,1,50,50");
test.end();
});
tape("path.arc(x, y, radius, startAngle, endAngle) may append an L command if the arc doesn’t start at the current point", function(test) {
var p = path.path(); p.moveTo(100, 100); p.arc(100, 100, 50, 0, Math.PI * 2);
test.pathEqual(p, "M100,100L150,100A50,50,0,1,1,50,100A50,50,0,1,1,150,100");
test.end();
});
tape("path.arc(x, y, radius, startAngle, endAngle) appends a single A command if the angle is less than π", function(test) {
var p = path.path(); p.moveTo(150, 100); p.arc(100, 100, 50, 0, Math.PI / 2);
test.pathEqual(p, "M150,100A50,50,0,0,1,100,150");
test.end();
});
tape("path.arc(x, y, radius, startAngle, endAngle) appends a single A command if the angle is less than τ", function(test) {
var p = path.path(); p.moveTo(150, 100); p.arc(100, 100, 50, 0, Math.PI * 1);
test.pathEqual(p, "M150,100A50,50,0,1,1,50,100");
test.end();
});
tape("path.arc(x, y, radius, startAngle, endAngle) appends two A commands if the angle is greater than τ", function(test) {
var p = path.path(); p.moveTo(150, 100); p.arc(100, 100, 50, 0, Math.PI * 2);
test.pathEqual(p, "M150,100A50,50,0,1,1,50,100A50,50,0,1,1,150,100");
test.end();
});
tape("path.arc(x, y, radius, 0, π/2, false) draws a small clockwise arc", function(test) {
var p = path.path(); p.moveTo(150, 100); p.arc(100, 100, 50, 0, Math.PI / 2, false);
test.pathEqual(p, "M150,100A50,50,0,0,1,100,150");
test.end();
});
tape("path.arc(x, y, radius, -π/2, 0, false) draws a small clockwise arc", function(test) {
var p = path.path(); p.moveTo(100, 50); p.arc(100, 100, 50, -Math.PI / 2, 0, false);
test.pathEqual(p, "M100,50A50,50,0,0,1,150,100");
test.end();
});
tape("path.arc(x, y, radius, 0, ε, true) draws an anticlockwise circle", function(test) {
var p = path.path(); p.moveTo(150, 100); p.arc(100, 100, 50, 0, 1e-16, true);
test.pathEqual(p, "M150,100A50,50,0,1,0,50,100A50,50,0,1,0,150,100");
test.end();
});
tape("path.arc(x, y, radius, 0, ε, false) draws nothing", function(test) {
var p = path.path(); p.moveTo(150, 100); p.arc(100, 100, 50, 0, 1e-16, false);
test.pathEqual(p, "M150,100");
test.end();
});
tape("path.arc(x, y, radius, 0, -ε, true) draws nothing", function(test) {
var p = path.path(); p.moveTo(150, 100); p.arc(100, 100, 50, 0, -1e-16, true);
test.pathEqual(p, "M150,100");
test.end();
});
tape("path.arc(x, y, radius, 0, -ε, false) draws a clockwise circle", function(test) {
var p = path.path(); p.moveTo(150, 100); p.arc(100, 100, 50, 0, -1e-16, false);
test.pathEqual(p, "M150,100A50,50,0,1,1,50,100A50,50,0,1,1,150,100");
test.end();
});
tape("path.arc(x, y, radius, 0, τ, true) draws an anticlockwise circle", function(test) {
var p = path.path(); p.moveTo(150, 100); p.arc(100, 100, 50, 0, 2 * Math.PI, true);
test.pathEqual(p, "M150,100A50,50,0,1,0,50,100A50,50,0,1,0,150,100");
test.end();
});
tape("path.arc(x, y, radius, 0, τ, false) draws a clockwise circle", function(test) {
var p = path.path(); p.moveTo(150, 100); p.arc(100, 100, 50, 0, 2 * Math.PI, false);
test.pathEqual(p, "M150,100A50,50,0,1,1,50,100A50,50,0,1,1,150,100");
test.end();
});
tape("path.arc(x, y, radius, 0, τ + ε, true) draws an anticlockwise circle", function(test) {
var p = path.path(); p.moveTo(150, 100); p.arc(100, 100, 50, 0, 2 * Math.PI + 1e-13, true);
test.pathEqual(p, "M150,100A50,50,0,1,0,50,100A50,50,0,1,0,150,100");
test.end();
});
tape("path.arc(x, y, radius, 0, τ - ε, false) draws a clockwise circle", function(test) {
var p = path.path(); p.moveTo(150, 100); p.arc(100, 100, 50, 0, 2 * Math.PI - 1e-13, false);
test.pathEqual(p, "M150,100A50,50,0,1,1,50,100A50,50,0,1,1,150,100");
test.end();
});
tape("path.arc(x, y, radius, τ, 0, true) draws an anticlockwise circle", function(test) {
var p = path.path(); p.moveTo(150, 100); p.arc(100, 100, 50, 0, 2 * Math.PI, true);
test.pathEqual(p, "M150,100A50,50,0,1,0,50,100A50,50,0,1,0,150,100");
test.end();
});
tape("path.arc(x, y, radius, τ, 0, false) draws a clockwise circle", function(test) {
var p = path.path(); p.moveTo(150, 100); p.arc(100, 100, 50, 0, 2 * Math.PI, false);
test.pathEqual(p, "M150,100A50,50,0,1,1,50,100A50,50,0,1,1,150,100");
test.end();
});
tape("path.arc(x, y, radius, 0, 13π/2, false) draws a clockwise circle", function(test) {
var p = path.path(); p.moveTo(150, 100); p.arc(100, 100, 50, 0, 13 * Math.PI / 2, false);
test.pathEqual(p, "M150,100A50,50,0,1,1,50,100A50,50,0,1,1,150,100");
test.end();
});
tape("path.arc(x, y, radius, 13π/2, 0, false) draws a big clockwise arc", function(test) {
var p = path.path(); p.moveTo(100, 150); p.arc(100, 100, 50, 13 * Math.PI / 2, 0, false);
test.pathEqual(p, "M100,150A50,50,0,1,1,150,100");
test.end();
});
tape("path.arc(x, y, radius, π/2, 0, false) draws a big clockwise arc", function(test) {
var p = path.path(); p.moveTo(100, 150); p.arc(100, 100, 50, Math.PI / 2, 0, false);
test.pathEqual(p, "M100,150A50,50,0,1,1,150,100");
test.end();
});
tape("path.arc(x, y, radius, 3π/2, 0, false) draws a small clockwise arc", function(test) {
var p = path.path(); p.moveTo(100, 50); p.arc(100, 100, 50, 3 * Math.PI / 2, 0, false);
test.pathEqual(p, "M100,50A50,50,0,0,1,150,100");
test.end();
});
tape("path.arc(x, y, radius, 15π/2, 0, false) draws a small clockwise arc", function(test) {
var p = path.path(); p.moveTo(100, 50); p.arc(100, 100, 50, 15 * Math.PI / 2, 0, false);
test.pathEqual(p, "M100,50A50,50,0,0,1,150,100");
test.end();
});
tape("path.arc(x, y, radius, 0, π/2, true) draws a big anticlockwise arc", function(test) {
var p = path.path(); p.moveTo(150, 100); p.arc(100, 100, 50, 0, Math.PI / 2, true);
test.pathEqual(p, "M150,100A50,50,0,1,0,100,150");
test.end();
});
tape("path.arc(x, y, radius, -π/2, 0, true) draws a big anticlockwise arc", function(test) {
var p = path.path(); p.moveTo(100, 50); p.arc(100, 100, 50, -Math.PI / 2, 0, true);
test.pathEqual(p, "M100,50A50,50,0,1,0,150,100");
test.end();
});
tape("path.arc(x, y, radius, -13π/2, 0, true) draws a big anticlockwise arc", function(test) {
var p = path.path(); p.moveTo(100, 50); p.arc(100, 100, 50, -13 * Math.PI / 2, 0, true);
test.pathEqual(p, "M100,50A50,50,0,1,0,150,100");
test.end();
});
tape("path.arc(x, y, radius, -13π/2, 0, false) draws a big anticlockwise arc", function(test) {
var p = path.path(); p.moveTo(150, 100); p.arc(100, 100, 50, 0, -13 * Math.PI / 2, false);
test.pathEqual(p, "M150,100A50,50,0,1,1,100,50");
test.end();
});
tape("path.arc(x, y, radius, 0, 13π/2, true) draws a big anticlockwise arc", function(test) {
var p = path.path(); p.moveTo(150, 100); p.arc(100, 100, 50, 0, 13 * Math.PI / 2, true);
test.pathEqual(p, "M150,100A50,50,0,1,0,100,150");
test.end();
});
tape("path.arc(x, y, radius, π/2, 0, true) draws a small anticlockwise arc", function(test) {
var p = path.path(); p.moveTo(100, 150); p.arc(100, 100, 50, Math.PI / 2, 0, true);
test.pathEqual(p, "M100,150A50,50,0,0,0,150,100");
test.end();
});
tape("path.arc(x, y, radius, 3π/2, 0, true) draws a big anticlockwise arc", function(test) {
var p = path.path(); p.moveTo(100, 50); p.arc(100, 100, 50, 3 * Math.PI / 2, 0, true);
test.pathEqual(p, "M100,50A50,50,0,1,0,150,100");
test.end();
});
tape("path.arcTo(x1, y1, x2, y2, radius) throws an error if the radius is negative", function(test) {
var p = path.path(); p.moveTo(150, 100);
test.throws(function() { p.arcTo(270, 39, 163, 100, -53); }, /negative radius/);
test.end();
});
tape("path.arcTo(x1, y1, x2, y2, radius) appends an M command if the path was empty", function(test) {
var p = path.path(); p.arcTo(270, 39, 163, 100, 53);
test.pathEqual(p, "M270,39");
test.end();
});
tape("path.arcTo(x1, y1, x2, y2, radius) does nothing if the previous point was ⟨x1,y1⟩", function(test) {
var p = path.path(); p.moveTo(270, 39); p.arcTo(270, 39, 163, 100, 53);
test.pathEqual(p, "M270,39");
test.end();
});
tape("path.arcTo(x1, y1, x2, y2, radius) appends an L command if the previous point, ⟨x1,y1⟩ and ⟨x2,y2⟩ are collinear", function(test) {
var p = path.path(); p.moveTo(100, 50); p.arcTo(101, 51, 102, 52, 10);
test.pathEqual(p, "M100,50L101,51");
test.end();
});
tape("path.arcTo(x1, y1, x2, y2, radius) appends an L command if ⟨x1,y1⟩ and ⟨x2,y2⟩ are coincident", function(test) {
var p = path.path(); p.moveTo(100, 50); p.arcTo(101, 51, 101, 51, 10);
test.pathEqual(p, "M100,50L101,51");
test.end();
});
tape("path.arcTo(x1, y1, x2, y2, radius) appends an L command if the radius is zero", function(test) {
var p = path.path(); p.moveTo(270, 182), p.arcTo(270, 39, 163, 100, 0);
test.pathEqual(p, "M270,182L270,39");
test.end();
});
tape("path.arcTo(x1, y1, x2, y2, radius) appends L and A commands if the arc does not start at the current point", function(test) {
var p = path.path(); p.moveTo(270, 182), p.arcTo(270, 39, 163, 100, 53);
test.pathEqual(p, "M270,182L270,130.222686A53,53,0,0,0,190.750991,84.179342");
p = path.path(); p.moveTo(270, 182), p.arcTo(270, 39, 363, 100, 53);
test.pathEqual(p, "M270,182L270,137.147168A53,53,0,0,1,352.068382,92.829799");
test.end();
});
tape("path.arcTo(x1, y1, x2, y2, radius) appends only an A command if the arc starts at the current point", function(test) {
var p = path.path(); p.moveTo(100, 100), p.arcTo(200, 100, 200, 200, 100);
test.pathEqual(p, "M100,100A100,100,0,0,1,200,200");
test.end();
});
tape("path.arcTo(x1, y1, x2, y2, radius) sets the last point to be the end tangent of the arc", function(test) {
var p = path.path(); p.moveTo(100, 100), p.arcTo(200, 100, 200, 200, 50); p.arc(150, 150, 50, 0, Math.PI);
test.pathEqual(p, "M100,100L150,100A50,50,0,0,1,200,150A50,50,0,1,1,100,150");
test.end();
});
tape("path.rect(x, y, w, h) appends M, h, v, h, and Z commands", function(test) {
var p = path.path(); p.moveTo(150, 100), p.rect(100, 200, 50, 25);
test.pathEqual(p, "M150,100M100,200h50v25h-50Z");
test.end();
});
d3-path-1.0.5/test/pathEqual.js 0000664 0000000 0000000 00000001111 13060564427 0016217 0 ustar 00root root 0000000 0000000 var tape = require("tape");
var reNumber = /[-+]?(?:\d+\.\d+|\d+\.|\.\d+|\d+)(?:[eE][-]?\d+)?/g;
tape.Test.prototype.pathEqual = function(actual, expected) {
actual = normalizePath(actual + "");
expected = normalizePath(expected + "");
this._assert(actual === expected, {
message: "should be equal",
operator: "pathEqual",
actual: actual,
expected: expected
});
};
function normalizePath(path) {
return path.replace(reNumber, formatNumber);
}
function formatNumber(s) {
return Math.abs((s = +s) - Math.round(s)) < 1e-6 ? Math.round(s) : s.toFixed(6);
}