More tests and small fixes to the path

master
Dmitry Baranovskiy 2013-08-02 14:07:42 +10:00
parent fe71fc7505
commit c40144d90c
4 changed files with 318 additions and 34 deletions

View File

@ -99,8 +99,8 @@ Savage.plugin(function (Savage, Element, Paper, glob) {
A = Savage.color(a);
B = Savage.color(b);
return {
from: [A.r, A.g, A.b],
to: [B.r, B.g, B.b],
from: [A.r, A.g, A.b, A.opacity],
to: [B.r, B.g, B.b, B.opacity],
f: getColour
};
}

View File

@ -6,6 +6,7 @@ Savage.plugin(function (Savage, Element, Paper, glob) {
p2s = /,?([a-z]),?/gi,
toFloat = parseFloat,
math = Math,
PI = math.PI,
mmin = math.min,
mmax = math.max,
pow = math.pow,
@ -48,11 +49,9 @@ Savage.plugin(function (Savage, Element, Paper, glob) {
y2: y + height,
cx: x + width / 2,
cy: y + height / 2,
rx: width / 2,
ry: height / 2,
r1: math.min(width, height) / 2,
r2: math.max(width, height) / 2,
r: math.sqrt(width * width + height * height) / 2,
r0: math.sqrt(width * width + height * height) / 2,
path: rectPath(x, y, width, height),
vb: [x, y, width, height].join(" ")
};
@ -74,6 +73,9 @@ Savage.plugin(function (Savage, Element, Paper, glob) {
}
}
function getLengthFactory(istotal, subpath) {
function O(val) {
return +(+val).toFixed(3);
}
return function (path, length, onlystart) {
path = path2curve(path);
var x, y, p, l, sp = "", subpaths = {}, point,
@ -88,10 +90,25 @@ Savage.plugin(function (Savage, Element, Paper, glob) {
if (len + l > length) {
if (subpath && !subpaths.start) {
point = getPointAtSegmentLength(x, y, p[1], p[2], p[3], p[4], p[5], p[6], length - len);
sp += ["C" + point.start.x, point.start.y, point.m.x, point.m.y, point.x, point.y];
sp += [
"C" + O(point.start.x),
O(point.start.y),
O(point.m.x),
O(point.m.y),
O(point.x),
O(point.y)
];
if (onlystart) {return sp;}
subpaths.start = sp;
sp = ["M" + point.x, point.y + "C" + point.n.x, point.n.y, point.end.x, point.end.y, p[5], p[6]].join();
sp = [
"M" + O(point.x),
O(point.y) + "C" + O(point.n.x),
O(point.n.y),
O(point.end.x),
O(point.end.y),
O(p[5]),
O(p[6])
].join();
len += l;
x = +p[5];
y = +p[6];
@ -99,7 +116,7 @@ Savage.plugin(function (Savage, Element, Paper, glob) {
}
if (!istotal && !subpath) {
point = getPointAtSegmentLength(x, y, p[1], p[2], p[3], p[4], p[5], p[6], length - len);
return {x: point.x, y: point.y, alpha: point.alpha};
return point;
}
}
len += l;
@ -109,8 +126,7 @@ Savage.plugin(function (Savage, Element, Paper, glob) {
sp += p.shift() + p;
}
subpaths.end = sp;
point = istotal ? len : subpath ? subpaths : R.findDotsAtSegment(x, y, p[0], p[1], p[2], p[3], p[4], p[5], 1);
point.alpha && (point = {x: point.x, y: point.y, alpha: point.alpha});
point = istotal ? len : subpath ? subpaths : findDotsAtSegment(x, y, p[0], p[1], p[2], p[3], p[4], p[5], 1);
return point;
};
}
@ -134,7 +150,7 @@ Savage.plugin(function (Savage, Element, Paper, glob) {
cx = t1 * c2x + t * p2x,
cy = t1 * c2y + t * p2y,
alpha = (90 - math.atan2(mx - nx, my - ny) * 180 / PI);
(mx > nx || my < ny) && (alpha += 180);
// (mx > nx || my < ny) && (alpha += 180);
return {
x: x,
y: y,
@ -158,18 +174,22 @@ Savage.plugin(function (Savage, Element, Paper, glob) {
);
}
function isPointInsideBBox(bbox, x, y) {
return x >= bbox.x && x <= bbox.x2 && y >= bbox.y && y <= bbox.y2;
return x >= bbox.x &&
x <= bbox.x + bbox.width &&
y >= bbox.y &&
y <= bbox.y + bbox.height;
}
function isBBoxIntersect(bbox1, bbox2) {
var i = isPointInsideBBox;
return i(bbox2, bbox1.x, bbox1.y)
|| i(bbox2, bbox1.x2, bbox1.y)
|| i(bbox2, bbox1.x, bbox1.y2)
|| i(bbox2, bbox1.x2, bbox1.y2)
|| i(bbox1, bbox2.x, bbox2.y)
|| i(bbox1, bbox2.x2, bbox2.y)
|| i(bbox1, bbox2.x, bbox2.y2)
|| i(bbox1, bbox2.x2, bbox2.y2)
bbox1 = box(bbox1);
bbox2 = box(bbox2);
return isPointInsideBBox(bbox2, bbox1.x, bbox1.y)
|| isPointInsideBBox(bbox2, bbox1.x2, bbox1.y)
|| isPointInsideBBox(bbox2, bbox1.x, bbox1.y2)
|| isPointInsideBBox(bbox2, bbox1.x2, bbox1.y2)
|| isPointInsideBBox(bbox1, bbox2.x, bbox2.y)
|| isPointInsideBBox(bbox1, bbox2.x2, bbox2.y)
|| isPointInsideBBox(bbox1, bbox2.x, bbox2.y2)
|| isPointInsideBBox(bbox1, bbox2.x2, bbox2.y2)
|| (bbox1.x < bbox2.x2 && bbox1.x > bbox2.x
|| bbox2.x < bbox1.x2 && bbox2.x > bbox1.x)
&& (bbox1.y < bbox2.y2 && bbox1.y > bbox2.y
@ -1184,7 +1204,7 @@ Savage.plugin(function (Savage, Element, Paper, glob) {
**
* Utility method
**
* Returns `true` if given point is inside bounding boxes.
* Returns `true` if given point is inside bounding box.
> Parameters
- bbox (string) bounding box
- x (string) x coordinate of the point
@ -1265,7 +1285,6 @@ Savage.plugin(function (Savage, Element, Paper, glob) {
o }
\*/
Savage.path.getBBox = pathBBox;
// TODO add doc
Savage.path.get = getPath;
/*\
* Savage.path.toRelative

126
svg.js
View File

@ -1,5 +1,6 @@
var $VG, Savage = $VG = (function () {
var Savage = function (w, h) {
Savage.version = "0.0.1";
function Savage(w, h) {
if (w) {
if (w.tagName) {
return new Element(w);
@ -14,6 +15,9 @@ var Savage = function (w, h) {
w = w == null ? "100%" : w;
h = h == null ? "100%" : h;
return new Paper(w, h);
}
Savage.toString = function () {
return "Savage v" + this.version;
};
Savage._ = {};
var glob = {
@ -64,7 +68,6 @@ function $(el, attr) {
return el.getAttribute(attr);
}
for (var key in attr) if (attr[has](key)) {
console.log(attr, key);
var val = Str(attr[key]);
if (val) {
if (key.substring(0, 6) == "xlink:") {
@ -177,9 +180,67 @@ function x_y_w_h() {
return this.x + S + this.y + S + this.width + " \xd7 " + this.height;
}
/*\
* Raphael.rad
[ method ]
**
* Transform angle to radians
> Parameters
- deg (number) angle in degrees
= (number) angle in radians.
\*/
Savage.rad = rad;
/*\
* Raphael.deg
[ method ]
**
* Transform angle to degrees
> Parameters
- deg (number) angle in radians
= (number) angle in degrees.
\*/
Savage.deg = deg;
/*\
* Savage.is
[ method ]
**
* Handfull replacement for `typeof` operator.
> Parameters
- o () any object or primitive
- type (string) name of the type, i.e. string, function, number, etc.
= (boolean) is given value is of given type
\*/
Savage.is = is;
/*\
* Savage.snapTo
[ method ]
**
* Snaps given value to given grid.
> Parameters
- values (array|number) given array of values or step of the grid
- value (number) value to adjust
- tolerance (number) #optional tolerance for snapping. Default is `10`.
= (number) adjusted value.
\*/
Savage.snapTo = function (values, value, tolerance) {
tolerance = is(tolerance, "finite") ? tolerance : 10;
if (is(values, "array")) {
var i = values.length;
while (i--) if (abs(values[i] - value) <= tolerance) {
return values[i];
}
} else {
values = +values;
var rem = value % values;
if (rem < tolerance) {
return value - rem;
}
if (rem > values - tolerance) {
return value - rem + values;
}
}
return value;
};
// MATRIX
function Matrix(a, b, c, d, e, f) {
@ -435,6 +496,24 @@ function Matrix(a, b, c, d, e, f) {
}
};
})(Matrix.prototype);
/*\
* Raphael.Matrix
[ method ]
**
* Utility method
**
* Returns matrix based on given parameters.
> Parameters
- a (number)
- b (number)
- c (number)
- d (number)
- e (number)
- f (number)
* or
- svgMatrix (SVGMatrix)
= (object) @Matrix
\*/
Savage.Matrix = Matrix;
// Colour
/*\
@ -574,7 +653,11 @@ Savage.hsl = cacher(function (h, s, l) {
- b (number) blue
= (string) hex representation of the colour.
\*/
Savage.rgb = cacher(function (r, g, b) {
Savage.rgb = cacher(function (r, g, b, o) {
if (is(o, "finite")) {
var round = math.round;
return "rgba(" + [round(r), round(g), round(b), +o.toFixed(2)] + ")";
}
return "#" + (16777216 | b | (g << 8) | (r << 16)).toString(16).slice(1);
});
var toHex = function (color) {
@ -891,6 +974,17 @@ Savage.rgb2hsl = function (r, g, b) {
pth.arr = Savage.path.clone(data);
return data;
};
/*\
* Savage.parseTransformString
[ method ]
**
* Utility method
**
* Parses given path string into an array of transformations.
> Parameters
- TString (string|array) transform string or array of transformations (in the last case it will be returned straight away)
= (array) array of transformations.
\*/
var parseTransformString = Savage.parseTransformString = function (TString) {
if (!TString) {
return null;
@ -1034,12 +1128,6 @@ function extractTransform(el, tstr) {
}
}
/*\
* Element.matrix
[ property (object) ]
**
* Keeps @Matrix object, which represents element transformation
\*/
el.matrix = m;
_.sx = sx;
@ -1138,10 +1226,27 @@ function unit2px(el, name, value) {
}
return out;
}
/*\
* Savage.select
[ method ]
**
* Wraps DOM element specified by CSS selector as @Element
> Parameters
- query (string) CSS selector of the element
= (Element)
\*/
Savage.select = function (query) {
return new Element(glob.doc.querySelector(query));
};
/*\
* Savage.selectAll
[ method ]
**
* Wraps DOM elements specified by CSS selector as set or array of @Element
> Parameters
- query (string) CSS selector of the element
= (Element)
\*/
Savage.selectAll = function (query) {
var nodelist = glob.doc.querySelectorAll(query),
set = (Savage.set || Array)();
@ -1219,7 +1324,6 @@ function arrayFirstValue(arr) {
this.realPath = Savage.path.get[this.type](this);
}
_.bbox = Savage.path.getBBox(Savage.path.map(this.realPath, this.matrix));
console.log(this.attr("path"), this.realPath, Savage.path.map(this.realPath, this.matrix), _.bbox);
_.bbox.toString = x_y_w_h;
_.dirty = _.dirtyT = 0;
}

View File

@ -15,6 +15,7 @@
<script src="../mina.js"></script>
<script src="../elemental.js"></script>
<script src="../svg.js"></script>
<script src="../savage.path.js"></script>
<script src="../savage.set.js"></script>
</head>
<body>
@ -342,6 +343,166 @@
expect(c.node.getAttribute("rx")).to.be("5%");
expect(c.node.getAttribute("ry")).to.be("6%");
});
it("path core attributes", function () {
var c = s.path("M10,10 110,10");
expect(c.node.getAttribute("d")).to.be("M10,10 110,10");
c.attr({d: "M10,10 210,10"});
expect(c.node.getAttribute("d")).to.be("M10,10 210,10");
c.attr({path: "M10,10 310,10"});
expect(c.node.getAttribute("d")).to.be("M10,10 310,10");
});
it("text core attributes", function () {
var c = s.text(10, 15, "testing");
expect(c.node.getAttribute("x")).to.be("10");
expect(c.node.getAttribute("y")).to.be("15");
expect(c.node.textContent).to.be("testing");
c.attr({
x: 20,
y: 25,
text: "texting"
});
expect(c.node.getAttribute("x")).to.be("20");
expect(c.node.getAttribute("y")).to.be("25");
expect(c.node.textContent).to.be("texting");
});
it("line core attributes", function () {
var c = s.line(10, 15, 110, 17);
expect(c.node.getAttribute("x1")).to.be("10");
expect(c.node.getAttribute("y1")).to.be("15");
expect(c.node.getAttribute("x2")).to.be("110");
expect(c.node.getAttribute("y2")).to.be("17");
c.attr({
x1: 20,
y1: 25,
x2: 220,
y2: 27
});
expect(c.node.getAttribute("x1")).to.be("20");
expect(c.node.getAttribute("y1")).to.be("25");
expect(c.node.getAttribute("x2")).to.be("220");
expect(c.node.getAttribute("y2")).to.be("27");
});
it("polyline core attributes", function () {
var c = s.polyline(10, 15, 20, 25, 30, 35);
expect(c.node.getAttribute("points")).to.be("10,15,20,25,30,35");
c.attr({
points: [20, 25, 30, 35, 40, 45]
});
expect(c.node.getAttribute("points")).to.be("20,25,30,35,40,45");
});
it("polygon core attributes", function () {
var c = s.polygon(10, 15, 20, 25, 30, 35);
expect(c.node.getAttribute("points")).to.be("10,15,20,25,30,35");
c.attr({
points: [20, 25, 30, 35, 40, 45]
});
expect(c.node.getAttribute("points")).to.be("20,25,30,35,40,45");
});
});
describe("Path methods", function () {
it("Savage.path.getTotalLength", function () {
expect(+Savage.path.getTotalLength("M0,0 100,0").toFixed(2)).to.be(100);
});
it("Savage.path.getPointAtLength", function () {
expect(Savage.path.getPointAtLength("M0,0 100,0", 50)).to.eql({
x: 50,
y: 0,
m: {
x: 25,
y: 0
},
n: {
x: 75,
y: 0
},
start: {
x: 0,
y: 0
},
end: {
x: 100,
y: 0
},
alpha: 180
});
});
it("Savage.path.getSubpath", function () {
expect(Savage.path.getSubpath("M0,0 100,0", 10, 90)).to.be("M9.995,0C29.153,0,70.839,0,90,0");
expect(Savage.path.getSubpath("M0,0 100,0", 0, 90)).to.be("M0,0C0,0,64.674,0,90,0");
expect(Savage.path.getSubpath("M0,0 100,0", 10, 120)).to.be("M10,0C35.326,0,100,0,100,0");
});
it("Savage.path.findDotsAtSegment", function () {
expect(Savage.path.findDotsAtSegment(0,0,0,0,100,0,100,0,.5)).to.eql({
x: 50,
y: 0,
m: {
x: 25,
y: 0
},
n: {
x: 75,
y: 0
},
start: {
x: 0,
y: 0
},
end: {
x: 100,
y: 0
},
alpha: 180
});
});
it("Savage.path.bezierBBox", function () {
var bbox = Savage.path.bezierBBox(10, 10, 10, 20, 110, 0, 110, 10);
expect(bbox.cx).to.be(60);
expect(bbox.cy).to.be(10);
expect(bbox.x).to.be(10);
expect(bbox.w).to.be(100);
expect(bbox.width).to.be(100);
expect(bbox.x2).to.be(110);
});
it("Savage.path.isPointInsideBBox", function () {
expect(Savage.path.isPointInsideBBox({x: 0, y: 0, width: 10, height: 10}, 5, 5)).to.be(true);
expect(Savage.path.isPointInsideBBox({x: 0, y: 0, width: 10, height: 10}, 10, 5)).to.be(true);
expect(Savage.path.isPointInsideBBox({x: 0, y: 0, width: 10, height: 10}, 10, 10)).to.be(true);
});
it("Savage.path.isBBoxIntersect", function () {
expect(Savage.path.isBBoxIntersect({
x: 0,
y: 0,
width: 10,
height: 10
}, {
x: 5,
y: 5,
width: 15,
height: 15
})).to.be(true);
expect(Savage.path.isBBoxIntersect({
x: 0,
y: 0,
width: 10,
height: 10
}, {
x: 5,
y: 5,
width: 7,
height: 7
})).to.be(true);
expect(Savage.path.isBBoxIntersect({
x: 0,
y: 0,
width: 10,
height: 10
}, {
x: 15,
y: 15,
width: 10,
height: 10
})).to.be(false);
});
});
</script>
<script>