mirror of
https://github.com/scratchfoundation/paper.js.git
synced 2024-12-28 17:02:24 -05:00
Initial commit
This commit is contained in:
commit
b19ba2014c
29 changed files with 4031 additions and 0 deletions
53
examples/animatedStar.html
Normal file
53
examples/animatedStar.html
Normal file
|
@ -0,0 +1,53 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<title>Example</title>
|
||||
<script type="text/javascript" src="../src/Bootstrap.js"></script>
|
||||
<script type="text/javascript" src="../src/Item.js"></script>
|
||||
<script type="text/javascript" src="../src/PathItem.js"></script>
|
||||
<script type="text/javascript" src="../src/Point.js"></script>
|
||||
<script type="text/javascript" src="../src/Rectangle.js"></script>
|
||||
<script type="text/javascript" src="../src/Size.js"></script>
|
||||
<script type="text/javascript" src="../src/Segment.js"></script>
|
||||
<script type="text/javascript" src="../src/PathItem.js"></script>
|
||||
<script type="text/javascript" src="../src/Path.js"></script>
|
||||
<script type="text/javascript" src="../src/SegmentList.js"></script>
|
||||
<script type="text/javascript" src="../src/Doc.js"></script>
|
||||
<script>
|
||||
var canvas, doc;
|
||||
var count = 0;
|
||||
window.onload = function() {
|
||||
canvas = document.getElementById('canvas');
|
||||
doc = new Doc(canvas);
|
||||
setInterval(draw, 60);
|
||||
}
|
||||
|
||||
function draw() {
|
||||
count++;
|
||||
doc.children = [];
|
||||
var point = new Point(1024, 768).divide(2);
|
||||
for(var i = 0; i < 35; i++) {
|
||||
var vector = new Point(20 + 10 * i, 0).rotate(i * (360 / 35 * 2) * Math.sin(count / 150));
|
||||
var l = vector.getLength();
|
||||
var path = new Path();
|
||||
// path.strokeColor = '#000000';
|
||||
path.fillColor = i % 2 ? 'red' : 'black';
|
||||
path.closed = true;
|
||||
for(var j = 0; j < 32; j++) {
|
||||
vector = vector.rotate(45 / 4);
|
||||
var newPoint = point.add(vector).add(vector.rotate(-180).normalize(l * (j % 2 ? 0.1 : -0.1)));
|
||||
path.add(newPoint);
|
||||
}
|
||||
path.smooth();
|
||||
doc.children.push(path);
|
||||
}
|
||||
doc.children.reverse();
|
||||
doc.draw();
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<canvas id='canvas' width=1024 height=768></canvas>
|
||||
</body>
|
48
examples/arcTo.html
Normal file
48
examples/arcTo.html
Normal file
|
@ -0,0 +1,48 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<title>Example</title>
|
||||
<script type="text/javascript" src="../src/Bootstrap.js"></script>
|
||||
<script type="text/javascript" src="../src/Item.js"></script>
|
||||
<script type="text/javascript" src="../src/PathItem.js"></script>
|
||||
<script type="text/javascript" src="../src/Point.js"></script>
|
||||
<script type="text/javascript" src="../src/Rectangle.js"></script>
|
||||
<script type="text/javascript" src="../src/Size.js"></script>
|
||||
<script type="text/javascript" src="../src/Segment.js"></script>
|
||||
<script type="text/javascript" src="../src/PathItem.js"></script>
|
||||
<script type="text/javascript" src="../src/Path.js"></script>
|
||||
<script type="text/javascript" src="../src/SegmentList.js"></script>
|
||||
<script type="text/javascript" src="../src/Doc.js"></script>
|
||||
<script>
|
||||
window.onload = function() {
|
||||
var canvas = document.getElementById('canvas');
|
||||
var doc = new Doc(canvas);
|
||||
|
||||
var point = new Point(1024, 768).divide(2);
|
||||
for(var i = 0; i < 30; i++) {
|
||||
var vector = new Point(10 + 20 * i, 0).rotate(i);
|
||||
var l = vector.getLength();
|
||||
var path = new Path();
|
||||
path.fillColor = i % 2 ? 'red' : 'black';
|
||||
path.closed = true;
|
||||
for(var j = 0; j < 17; j++) {
|
||||
vector = vector.rotate(45 / 2);
|
||||
if(j == 0) {
|
||||
path.add(point.add(vector));
|
||||
} else {
|
||||
path.arcTo(point.add(vector), true);
|
||||
}
|
||||
}
|
||||
doc.children.push(path);
|
||||
}
|
||||
doc.children.reverse();
|
||||
|
||||
doc.draw();
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<canvas id='canvas' width=1024 height=768></canvas>
|
||||
</body>
|
36
examples/circle.html
Normal file
36
examples/circle.html
Normal file
|
@ -0,0 +1,36 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<title>Example</title>
|
||||
<script type="text/javascript" src="../src/Bootstrap.js"></script>
|
||||
<script type="text/javascript" src="../src/Item.js"></script>
|
||||
<script type="text/javascript" src="../src/PathItem.js"></script>
|
||||
<script type="text/javascript" src="../src/Point.js"></script>
|
||||
<script type="text/javascript" src="../src/Rectangle.js"></script>
|
||||
<script type="text/javascript" src="../src/Size.js"></script>
|
||||
<script type="text/javascript" src="../src/Segment.js"></script>
|
||||
<script type="text/javascript" src="../src/PathItem.js"></script>
|
||||
<script type="text/javascript" src="../src/Path.js"></script>
|
||||
<script type="text/javascript" src="../src/SegmentList.js"></script>
|
||||
<script type="text/javascript" src="../src/Doc.js"></script>
|
||||
<script>
|
||||
var count = 0;
|
||||
var doc;
|
||||
window.onload = function() {
|
||||
var canvas = document.getElementById('canvas');
|
||||
doc = new Doc(canvas);
|
||||
var center = doc.size.divide(2);
|
||||
for(var i = 0; i < 70; i++) {
|
||||
var path = new Path.Circle(center, i * 5);
|
||||
path.strokeColor = 'black';
|
||||
doc.children.push(path);
|
||||
}
|
||||
doc.draw();
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<canvas id='canvas' width=1024 height=768></canvas>
|
||||
</body>
|
47
examples/letter.html
Normal file
47
examples/letter.html
Normal file
|
@ -0,0 +1,47 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<title>Example</title>
|
||||
<script type="text/javascript" src="../src/Bootstrap.js"></script>
|
||||
<script type="text/javascript" src="../src/Item.js"></script>
|
||||
<script type="text/javascript" src="../src/PathItem.js"></script>
|
||||
<script type="text/javascript" src="../src/Point.js"></script>
|
||||
<script type="text/javascript" src="../src/Rectangle.js"></script>
|
||||
<script type="text/javascript" src="../src/Size.js"></script>
|
||||
<script type="text/javascript" src="../src/Segment.js"></script>
|
||||
<script type="text/javascript" src="../src/PathItem.js"></script>
|
||||
<script type="text/javascript" src="../src/Path.js"></script>
|
||||
<script type="text/javascript" src="../src/SegmentList.js"></script>
|
||||
<script type="text/javascript" src="../src/Doc.js"></script>
|
||||
<script>
|
||||
window.onload = function() {
|
||||
var canvas = document.getElementById('canvas');
|
||||
var doc = new Doc(canvas);
|
||||
|
||||
var letterPath = new Path(
|
||||
new Segment(new Point(63.39306640625, 265.7138671875), null, new Point(10.86669921875, 6.96630859375)),
|
||||
new Segment(new Point(106.58203125, 277.97412109375), new Point(-16.71826171875, 0), new Point(24.79931640625, 0)),
|
||||
new Segment(new Point(145.87060546875, 245.9306640625), new Point(0, 18.947265625), new Point(0, -17.27587890625)),
|
||||
new Segment(new Point(110.4833984375, 208.87158203125), new Point(25.35595703125, 9.4736328125), new Point(-30.65087890625, -11.14599609375)),
|
||||
new Segment(new Point(60.88525390625, 155.37255859375), new Point(0, 26.19189453125), new Point(0, -29.25732421875)),
|
||||
new Segment(new Point(121.62890625, 104.380859375), new Point(-36.501953125, 0), new Point(18.947265625, 0)),
|
||||
new Segment(new Point(162.86767578125, 113.576171875), new Point(-8.08056640625, -4.73681640625)),
|
||||
new Segment(new Point(156.18017578125, 133.35986328125), null, new Point(-5.8515625, -3.62255859375)),
|
||||
new Segment(new Point(120.79296875, 124.443359375), new Point(16.9970703125, 0), new Point(-25.63525390625, 0)),
|
||||
new Segment(new Point(85.4052734375, 152.5859375), new Point(0, -12.8173828125), new Point(0, 17.55419921875)),
|
||||
new Segment(new Point(122.7431640625, 188.80908203125), new Point(-25.91357421875, -10.03076171875), new Point(31.76513671875, 12.26025390625)),
|
||||
new Segment(new Point(170.39111328125, 243.97998046875), new Point(0, -27.58544921875), new Point(0, 28.97900390625)),
|
||||
new Segment(new Point(104.91015625, 298.31494140625), new Point(44.30419921875, 0), new Point(-18.111328125, 0)),
|
||||
new Segment(new Point(56.984375, 286.0546875), new Point(10.03076171875, 6.6875))
|
||||
);
|
||||
letterPath.fillColor = 'black';
|
||||
doc.children.push(letterPath);
|
||||
doc.draw();
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<canvas id='canvas' width=1024 height=768></canvas>
|
||||
</body>
|
43
examples/lines.html
Normal file
43
examples/lines.html
Normal file
|
@ -0,0 +1,43 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<title>Example</title>
|
||||
<script type="text/javascript" src="../src/Bootstrap.js"></script>
|
||||
<script type="text/javascript" src="../src/Item.js"></script>
|
||||
<script type="text/javascript" src="../src/PathItem.js"></script>
|
||||
<script type="text/javascript" src="../src/Point.js"></script>
|
||||
<script type="text/javascript" src="../src/Rectangle.js"></script>
|
||||
<script type="text/javascript" src="../src/Size.js"></script>
|
||||
<script type="text/javascript" src="../src/Segment.js"></script>
|
||||
<script type="text/javascript" src="../src/PathItem.js"></script>
|
||||
<script type="text/javascript" src="../src/Path.js"></script>
|
||||
<script type="text/javascript" src="../src/SegmentList.js"></script>
|
||||
<script type="text/javascript" src="../src/Doc.js"></script>
|
||||
<script>
|
||||
var count = 0;
|
||||
var doc;
|
||||
window.onload = function() {
|
||||
var canvas = document.getElementById('canvas');
|
||||
doc = new Doc(canvas);
|
||||
setInterval(draw, 20);
|
||||
}
|
||||
|
||||
function draw() {
|
||||
count++;
|
||||
doc.children = [];
|
||||
var point = new Point(1024, 768).divide(2);
|
||||
var vector = new Point(100, 0);
|
||||
for(var i = 0; i < 180; i++) {
|
||||
var path = new Path.Line(point.add(vector.rotate(i * 2).normalize(30)), point.add(vector.rotate(i * 2).normalize(30 + Math.abs(Math.sin((i + count / 20)) * 300))));
|
||||
path.strokeColor = i % 4 ? 'black' : 'red';
|
||||
doc.children.push(path);
|
||||
}
|
||||
doc.draw();
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<canvas id='canvas' width=1024 height=768></canvas>
|
||||
</body>
|
34
examples/rectangle.html
Normal file
34
examples/rectangle.html
Normal file
|
@ -0,0 +1,34 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<title>Example</title>
|
||||
<script type="text/javascript" src="../src/Bootstrap.js"></script>
|
||||
<script type="text/javascript" src="../src/Item.js"></script>
|
||||
<script type="text/javascript" src="../src/PathItem.js"></script>
|
||||
<script type="text/javascript" src="../src/Point.js"></script>
|
||||
<script type="text/javascript" src="../src/Rectangle.js"></script>
|
||||
<script type="text/javascript" src="../src/Size.js"></script>
|
||||
<script type="text/javascript" src="../src/Segment.js"></script>
|
||||
<script type="text/javascript" src="../src/PathItem.js"></script>
|
||||
<script type="text/javascript" src="../src/Path.js"></script>
|
||||
<script type="text/javascript" src="../src/SegmentList.js"></script>
|
||||
<script type="text/javascript" src="../src/Doc.js"></script>
|
||||
<script>
|
||||
var count = 0;
|
||||
var doc;
|
||||
window.onload = function() {
|
||||
var canvas = document.getElementById('canvas');
|
||||
doc = new Doc(canvas);
|
||||
var path = new Path.Rectangle([50, 50], [100, 100]);
|
||||
path.strokeColor = 'black';
|
||||
console.log(path);
|
||||
doc.children.push(path);
|
||||
doc.draw();
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<canvas id='canvas' width=1024 height=768></canvas>
|
||||
</body>
|
46
examples/star.html
Normal file
46
examples/star.html
Normal file
|
@ -0,0 +1,46 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<title>Example</title>
|
||||
<script type="text/javascript" src="../src/Bootstrap.js"></script>
|
||||
<script type="text/javascript" src="../src/Item.js"></script>
|
||||
<script type="text/javascript" src="../src/PathItem.js"></script>
|
||||
<script type="text/javascript" src="../src/Point.js"></script>
|
||||
<script type="text/javascript" src="../src/Rectangle.js"></script>
|
||||
<script type="text/javascript" src="../src/Size.js"></script>
|
||||
<script type="text/javascript" src="../src/Segment.js"></script>
|
||||
<script type="text/javascript" src="../src/PathItem.js"></script>
|
||||
<script type="text/javascript" src="../src/Path.js"></script>
|
||||
<script type="text/javascript" src="../src/SegmentList.js"></script>
|
||||
<script type="text/javascript" src="../src/Doc.js"></script>
|
||||
<script>
|
||||
window.onload = function() {
|
||||
var canvas = document.getElementById('canvas');
|
||||
var doc = new Doc(canvas);
|
||||
|
||||
var point = new Point(1024, 768).divide(2);
|
||||
for(var i = 0; i < 30; i++) {
|
||||
var vector = new Point(1 + 10 * i, 0).rotate(i);
|
||||
var l = vector.getLength();
|
||||
var path = new Path();
|
||||
// path.strokeColor = '#000000';
|
||||
path.fillColor = i % 2 ? 'red' : 'black';
|
||||
path.closed = true;
|
||||
for(var j = 0; j < 32; j++) {
|
||||
vector = vector.rotate(45 / 4);
|
||||
var newPoint = point.add(vector).add(vector.rotate(-180).normalize(l * (j % 2 ? 0.1 : -0.1)));
|
||||
path.add(newPoint);
|
||||
}
|
||||
path.smooth();
|
||||
doc.children.push(path);
|
||||
}
|
||||
doc.children.reverse();
|
||||
doc.draw();
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<canvas id='canvas' width=1024 height=768></canvas>
|
||||
</body>
|
35
examples/strokeJoin.html
Normal file
35
examples/strokeJoin.html
Normal file
|
@ -0,0 +1,35 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<title>Example</title>
|
||||
<script type="text/javascript" src="../src/Bootstrap.js"></script>
|
||||
<script type="text/javascript" src="../src/Item.js"></script>
|
||||
<script type="text/javascript" src="../src/PathItem.js"></script>
|
||||
<script type="text/javascript" src="../src/Point.js"></script>
|
||||
<script type="text/javascript" src="../src/Rectangle.js"></script>
|
||||
<script type="text/javascript" src="../src/Size.js"></script>
|
||||
<script type="text/javascript" src="../src/Segment.js"></script>
|
||||
<script type="text/javascript" src="../src/PathItem.js"></script>
|
||||
<script type="text/javascript" src="../src/Path.js"></script>
|
||||
<script type="text/javascript" src="../src/SegmentList.js"></script>
|
||||
<script type="text/javascript" src="../src/Doc.js"></script>
|
||||
<script>
|
||||
var count = 0;
|
||||
var doc;
|
||||
window.onload = function() {
|
||||
var canvas = document.getElementById('canvas');
|
||||
doc = new Doc(canvas);
|
||||
var path = new Path([100, 150], [150, 200], [200, 150]);
|
||||
path.strokeColor = 'black';
|
||||
path.strokeWidth = 30;
|
||||
path.strokeJoin = 'bevel';
|
||||
doc.children.push(path);
|
||||
doc.draw();
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<canvas id='canvas' width=1024 height=768></canvas>
|
||||
</body>
|
39
examples/temp.html
Normal file
39
examples/temp.html
Normal file
|
@ -0,0 +1,39 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<title>Example</title>
|
||||
<script type="text/javascript" src="../src/Bootstrap.js"></script>
|
||||
<script type="text/javascript" src="../src/Item.js"></script>
|
||||
<script type="text/javascript" src="../src/PathItem.js"></script>
|
||||
<script type="text/javascript" src="../src/Point.js"></script>
|
||||
<script type="text/javascript" src="../src/Rectangle.js"></script>
|
||||
<script type="text/javascript" src="../src/Size.js"></script>
|
||||
<script type="text/javascript" src="../src/Segment.js"></script>
|
||||
<script type="text/javascript" src="../src/PathItem.js"></script>
|
||||
<script type="text/javascript" src="../src/Path.js"></script>
|
||||
<script type="text/javascript" src="../src/SegmentList.js"></script>
|
||||
<script type="text/javascript" src="../src/Doc.js"></script>
|
||||
<script>
|
||||
var count = 0;
|
||||
var doc;
|
||||
window.onload = function() {
|
||||
var canvas = document.getElementById('canvas');
|
||||
doc = new Doc(canvas);
|
||||
var rect = new Rectangle([50, 50], [200, 100])
|
||||
var path = new Path.RoundRectangle(rect, 200);
|
||||
path.strokeColor = 'black';
|
||||
console.log(path);
|
||||
doc.children.push(path);
|
||||
|
||||
// var path = new Path.Rectangle(rect);
|
||||
// path.strokeColor = 'black';
|
||||
// doc.children.push(path);
|
||||
doc.draw();
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<canvas id='canvas' width=1024 height=768></canvas>
|
||||
</body>
|
170
src/Bootstrap.js
Normal file
170
src/Bootstrap.js
Normal file
|
@ -0,0 +1,170 @@
|
|||
new function() {
|
||||
var fix = !this.__proto__ && [Function, Number, Boolean, String, Array, Date, RegExp];
|
||||
if (fix)
|
||||
for (var i in fix)
|
||||
fix[i].prototype.__proto__ = fix[i].prototype;
|
||||
|
||||
var has = {}.hasOwnProperty
|
||||
? function(obj, name) {
|
||||
return (!fix || name != '__proto__') && obj.hasOwnProperty(name);
|
||||
}
|
||||
: function(obj, name) {
|
||||
return obj[name] !== (obj.__proto__ || Object.prototype)[name];
|
||||
};
|
||||
|
||||
function inject(dest, src, enumerable, base, generics) {
|
||||
function field(name, dontCheck, generics) {
|
||||
var val = src[name], func = typeof val == 'function', res = val,
|
||||
prev = dest[name];
|
||||
if (generics && func && (!src.preserve || !generics[name])) generics[name] = function(bind) {
|
||||
return bind && dest[name].apply(bind,
|
||||
Array.prototype.slice.call(arguments, 1));
|
||||
}
|
||||
if ((dontCheck || val !== undefined && has(src, name)) && (!prev || !src.preserve)) {
|
||||
if (func) {
|
||||
if (prev && /\bthis\.base\b/.test(val)) {
|
||||
var fromBase = base && base[name] == prev;
|
||||
res = (function() {
|
||||
var tmp = this.base;
|
||||
this.base = fromBase ? base[name] : prev;
|
||||
try { return val.apply(this, arguments); }
|
||||
finally { tmp ? this.base = tmp : delete this.base; }
|
||||
}).pretend(val);
|
||||
}
|
||||
}
|
||||
dest[name] = res;
|
||||
}
|
||||
}
|
||||
if (src) {
|
||||
for (var name in src)
|
||||
if (has(src, name) && !/^(statics|generics|preserve|prototype|constructor|__proto__|toString|valueOf)$/.test(name))
|
||||
field(name, true, generics);
|
||||
field('toString');
|
||||
field('valueOf');
|
||||
}
|
||||
}
|
||||
|
||||
function extend(obj) {
|
||||
function ctor(dont) {
|
||||
if (fix) this.__proto__ = obj;
|
||||
if (this.initialize && dont !== ctor.dont)
|
||||
return this.initialize.apply(this, arguments);
|
||||
}
|
||||
ctor.prototype = obj;
|
||||
ctor.toString = function() {
|
||||
return (this.prototype.initialize || function() {}).toString();
|
||||
}
|
||||
return ctor;
|
||||
}
|
||||
|
||||
inject(Function.prototype, {
|
||||
inject: function(src) {
|
||||
if (src) {
|
||||
var proto = this.prototype, base = proto.__proto__ && proto.__proto__.constructor;
|
||||
inject(proto, src, false, base && base.prototype, src.generics && this);
|
||||
inject(this, src.statics, true, base);
|
||||
}
|
||||
for (var i = 1, l = arguments.length; i < l; i++)
|
||||
this.inject(arguments[i]);
|
||||
return this;
|
||||
},
|
||||
|
||||
extend: function(src) {
|
||||
var proto = new this(this.dont), ctor = proto.constructor = extend(proto);
|
||||
ctor.dont = {};
|
||||
inject(ctor, this, true);
|
||||
return arguments.length ? this.inject.apply(ctor, arguments) : ctor;
|
||||
},
|
||||
|
||||
pretend: function(fn) {
|
||||
this.toString = function() {
|
||||
return fn.toString();
|
||||
}
|
||||
this.valueOf = function() {
|
||||
return fn.valueOf();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
});
|
||||
|
||||
function each(obj, iter, bind) {
|
||||
return obj ? (typeof obj.length == 'number'
|
||||
? Array : Hash).prototype.each.call(obj, iter, bind) : bind;
|
||||
}
|
||||
|
||||
Base = Object.extend({
|
||||
has: function(name) {
|
||||
return has(this, name);
|
||||
},
|
||||
|
||||
each: function(iter, bind) {
|
||||
return each(this, iter, bind);
|
||||
},
|
||||
|
||||
inject: function() {
|
||||
for (var i = 0, l = arguments.length; i < l; i++)
|
||||
inject(this, arguments[i]);
|
||||
return this;
|
||||
},
|
||||
|
||||
extend: function() {
|
||||
var res = new (extend(this));
|
||||
return res.inject.apply(res, arguments);
|
||||
},
|
||||
|
||||
statics: {
|
||||
has: has,
|
||||
each: each,
|
||||
|
||||
type: function(obj) {
|
||||
return (obj || obj === 0) && (
|
||||
obj._type || obj.nodeName && (
|
||||
obj.nodeType == 1 && 'element' ||
|
||||
obj.nodeType == 3 && 'textnode' ||
|
||||
obj.nodeType == 9 && 'document')
|
||||
|| obj.location && obj.frames && obj.history && 'window'
|
||||
|| typeof obj) || null;
|
||||
},
|
||||
|
||||
check: function(obj) {
|
||||
return !!(obj || obj === 0);
|
||||
},
|
||||
|
||||
pick: function() {
|
||||
for (var i = 0, l = arguments.length; i < l; i++)
|
||||
if (arguments[i] !== undefined)
|
||||
return arguments[i];
|
||||
return null;
|
||||
},
|
||||
|
||||
iterator: function(iter) {
|
||||
return !iter
|
||||
? function(val) { return val }
|
||||
: typeof iter != 'function'
|
||||
? function(val) { return val == iter }
|
||||
: iter;
|
||||
},
|
||||
|
||||
stop: {}
|
||||
}
|
||||
}, {
|
||||
generics: true,
|
||||
|
||||
debug: function() {
|
||||
return /^(string|number|function|regexp)$/.test(Base.type(this)) ? this
|
||||
: Base.each(this, function(val, key) { this.push(key + ': ' + val); }, []).join(', ');
|
||||
},
|
||||
|
||||
clone: function() {
|
||||
return Base.each(this, function(val, i) {
|
||||
this[i] = val;
|
||||
}, new this.constructor());
|
||||
},
|
||||
|
||||
toQueryString: function() {
|
||||
return Base.each(this, function(val, key) {
|
||||
this.push(key + '=' + encodeURIComponent(val));
|
||||
}, []).join('&');
|
||||
}
|
||||
});
|
||||
}
|
14
src/Doc.js
Normal file
14
src/Doc.js
Normal file
|
@ -0,0 +1,14 @@
|
|||
Doc = Base.extend({
|
||||
initialize: function(canvas) {
|
||||
this.canvas = canvas;
|
||||
this.ctx = this.canvas.getContext('2d');
|
||||
this.size = new Size(canvas.offsetWidth, canvas.offsetHeight);
|
||||
this.children = [];
|
||||
},
|
||||
draw: function() {
|
||||
this.ctx.clearRect(0, 0, this.size.width, this.size.height);
|
||||
for(var i = 0, l = this.children.length; i < l; i++) {
|
||||
this.children[i].draw(this.ctx);
|
||||
}
|
||||
}
|
||||
});
|
5
src/Item.js
Normal file
5
src/Item.js
Normal file
|
@ -0,0 +1,5 @@
|
|||
Item = Base.extend({
|
||||
initialize: function() {
|
||||
this.bounds = new Rectangle();
|
||||
}
|
||||
});
|
126
src/Path.js
Normal file
126
src/Path.js
Normal file
|
@ -0,0 +1,126 @@
|
|||
Path = PathItem.extend({
|
||||
initialize: function() {
|
||||
this.base.apply(this, arguments);
|
||||
},
|
||||
|
||||
statics: {
|
||||
Line: PathItem.extend({
|
||||
initialize: function() {
|
||||
this.base();
|
||||
if(arguments.length == 2) {
|
||||
console.log(new Segment(arguments[0]));
|
||||
this.addSegment(new Segment(arguments[0]));
|
||||
this.addSegment(new Segment(arguments[1]));
|
||||
} else if(arguments.length == 4) {
|
||||
this.addSegment(Segment.read(arguments[0], arguments[1]));
|
||||
this.addSegment(Segment.read(arguments[2], arguments[3]));
|
||||
}
|
||||
}
|
||||
}),
|
||||
|
||||
Rectangle: PathItem.extend({
|
||||
initialize: function() {
|
||||
this.base();
|
||||
this.closed = true;
|
||||
var rectangle = Rectangle.read(arguments);
|
||||
var corners = ['getBottomLeft', 'getTopLeft', 'getTopRight', 'getBottomRight'];
|
||||
for(var i = 0; i < 4; i++) {
|
||||
this.add(rectangle[corners[i]]());
|
||||
}
|
||||
}
|
||||
}),
|
||||
|
||||
RoundRectangle: PathItem.extend(new function() {
|
||||
var u = 4 / 3 * (Math.sqrt(2) - 1);
|
||||
return {
|
||||
initialize: function() {
|
||||
this.base();
|
||||
var rect, size;
|
||||
if(arguments.length == 2) {
|
||||
rect = new Rectangle(arguments[0]);
|
||||
size = new Size(arguments[1]);
|
||||
} else {
|
||||
rect = new Rectangle(arguments[0], arguments[1],
|
||||
arguments[2], arguments[3]);
|
||||
size = new Size(arguments[4], arguments[5]);
|
||||
}
|
||||
size = Size.min(size, rect.getSize().divide(2));
|
||||
uSize = size.multiply(u);
|
||||
|
||||
var bl = rect.getBottomLeft();
|
||||
this.add(bl.add(size.width, 0), null, [-uSize.width, 0]);
|
||||
this.add(bl.subtract(0, size.height), [0, uSize.height], null);
|
||||
|
||||
var tl = rect.getTopLeft();
|
||||
this.add(tl.add(0, size.height), null, [0, -uSize.height]);
|
||||
this.add(tl.add(size.width, 0), [-uSize.width, 0], null);
|
||||
|
||||
var tr = rect.getTopRight();
|
||||
this.add(tr.subtract(size.width, 0), null, [uSize.width, 0]);
|
||||
this.add(tr.add(0, size.height), [0, -uSize.height], null);
|
||||
|
||||
var br = rect.getBottomRight();
|
||||
this.add(br.subtract(0, size.height), null, [0, uSize.height]);
|
||||
this.add(br.subtract(size.width, 0), [uSize.width, 0], null);
|
||||
|
||||
this.closed = true;
|
||||
}
|
||||
}
|
||||
}),
|
||||
|
||||
Oval: PathItem.extend(new function() {
|
||||
var u = 2 / 3 * (Math.sqrt(2) - 1);
|
||||
var segments = [
|
||||
{ handleOut: [0, -u], handleIn: [0, u], point: [ 0, 0.5] },
|
||||
{ handleOut: [u, 0], handleIn: [-u, 0], point: [ 0.5, 0] },
|
||||
{ handleOut: [0, u], handleIn: [0, -u], point: [ 1, 0.5] },
|
||||
{ handleOut: [-u, 0], handleIn: [u, 0], point: [0.5, 1] }
|
||||
];
|
||||
return {
|
||||
initialize: function() {
|
||||
this.base();
|
||||
var rect = Rectangle.read(arguments);
|
||||
var topLeft = rect.getTopLeft();
|
||||
var size = new Size(rect.width, rect.height);
|
||||
for(var i = 0; i < 4; i++) {
|
||||
var segment = Segment.read([segments[i]]);
|
||||
segment.handleIn = segment.handleIn.multiply(size);
|
||||
segment.handleOut = segment.handleOut.multiply(size);
|
||||
segment.point = segment.point.multiply(size).add(topLeft);
|
||||
this.segments.push(segment);
|
||||
}
|
||||
this.closed = true;
|
||||
}
|
||||
}
|
||||
}),
|
||||
|
||||
Circle: PathItem.extend({
|
||||
initialize: function() {
|
||||
this.base();
|
||||
var center, radius;
|
||||
if(arguments.length == 3) {
|
||||
center = new Point(arguments[0], arguments[1]);
|
||||
radius = arguments[2];
|
||||
} else {
|
||||
center = new Point(arguments[0]);
|
||||
radius = arguments[1];
|
||||
}
|
||||
var left = center.subtract(radius, 0);
|
||||
this.moveTo(left);
|
||||
this.arcTo(center.add(radius, 0), true);
|
||||
this.arcTo(left, true);
|
||||
var last = this.segments.pop();
|
||||
this.segments[0].handleIn = last.handleIn;
|
||||
this.closed = true;
|
||||
}
|
||||
}),
|
||||
|
||||
Arc: PathItem.extend({
|
||||
initialize: function(from, through, to) {
|
||||
this.base();
|
||||
this.moveTo(from);
|
||||
this.arcTo(through, to);
|
||||
}
|
||||
})
|
||||
}
|
||||
});
|
377
src/PathItem.js
Normal file
377
src/PathItem.js
Normal file
|
@ -0,0 +1,377 @@
|
|||
PathItem = Item.extend(new function() {
|
||||
var styleNames = {
|
||||
fillColor: 'fillStyle',
|
||||
strokeColor: 'strokeStyle',
|
||||
strokeWidth: 'lineWidth',
|
||||
strokeJoin: 'lineJoin',
|
||||
strokeCap: 'lineCap',
|
||||
miterLimit: 'miterLimit'
|
||||
};
|
||||
|
||||
/**
|
||||
* Solves a tri-diagonal system for one of coordinates (x or y) of first
|
||||
* bezier control points.
|
||||
*
|
||||
* @param rhs right hand side vector.
|
||||
* @return Solution vector.
|
||||
*/
|
||||
var getFirstControlPoints = function(rhs) {
|
||||
var n = rhs.length;
|
||||
var x = []; // Solution vector.
|
||||
var tmp = []; // Temporary workspace.
|
||||
var b = 2;
|
||||
x[0] = rhs[0] / b;
|
||||
// Decomposition and forward substitution.
|
||||
for (var i = 1; i < n; i++) {
|
||||
tmp[i] = 1 / b;
|
||||
b = (i < n - 1 ? 4.0 : 2.0) - tmp[i];
|
||||
x[i] = (rhs[i] - x[i - 1]) / b;
|
||||
}
|
||||
// Back-substitution.
|
||||
for (var i = 1; i < n; i++) {
|
||||
x[n - i - 1] -= tmp[n - i] * x[n - i];
|
||||
}
|
||||
|
||||
return x;
|
||||
};
|
||||
|
||||
return {
|
||||
initialize: function() {
|
||||
this.closed = false;
|
||||
this.segments = [];//new SegmentList(this);
|
||||
this.bounds = new Rectangle();
|
||||
for(var i = 0, l = arguments.length; i < l; i++) {
|
||||
var segment = new Segment(arguments[i]);
|
||||
this.addSegment(segment);
|
||||
}
|
||||
},
|
||||
|
||||
addSegment: function(segment) {
|
||||
segment.path = this;
|
||||
this.segments.push(segment);
|
||||
},
|
||||
|
||||
add: function() {
|
||||
var segment = Segment.read(arguments);
|
||||
if(segment)
|
||||
this.addSegment(segment);
|
||||
},
|
||||
|
||||
|
||||
moveTo: function() {
|
||||
var segment = Segment.read(arguments);
|
||||
if(segment && !this.segments.length)
|
||||
this.addSegment(segment);
|
||||
},
|
||||
|
||||
lineTo: function() {
|
||||
var segment = Segment.read(arguments);
|
||||
if(segment && this.segments.length)
|
||||
this.addSegment(segment);
|
||||
},
|
||||
|
||||
/**
|
||||
* Adds a cubic bezier curve to the path, defined by two handles and a to
|
||||
* point.
|
||||
*/
|
||||
cubicCurveTo: function(handle1, handle2, to) {
|
||||
// First modify the current segment:
|
||||
var current = getCurrentSegment();
|
||||
// Convert to relative values:
|
||||
current.handleOut.set(
|
||||
handle1.x - current.point.x,
|
||||
handle1.y - current.point.y);
|
||||
// And add the new segment, with handleIn set to c2
|
||||
this.segments.push(
|
||||
new Segment(to, handle2.subtract(to), new Point())
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Adds a quadratic bezier curve to the path, defined by a handle and a to
|
||||
* point.
|
||||
*/
|
||||
quadraticCurveTo: function(handle, to) {
|
||||
// This is exact:
|
||||
// If we have the three quad points: A E D,
|
||||
// and the cubic is A B C D,
|
||||
// B = E + 1/3 (A - E)
|
||||
// C = E + 1/3 (D - E)
|
||||
var current = this.segments[this.segments.length - 1];
|
||||
var x1 = current.point.x;
|
||||
var y1 = current.point.y;
|
||||
cubicCurveTo(
|
||||
handle.add(current.point.subtract(handle).multiply(1/3)),
|
||||
handle.add(to.subtract(handle).multiply(1/3)),
|
||||
to
|
||||
);
|
||||
},
|
||||
|
||||
curveTo: function(through, to, parameter) {
|
||||
through = new Point(through);
|
||||
to = new Point(to);
|
||||
if(parameter == null)
|
||||
parameter = 0.5;
|
||||
var current = this.segments[this.segments.length - 1];
|
||||
// handle = (through - (1 - t)^2 * current - t^2 * to) / (2 * (1 - t) * t)
|
||||
var t1 = 1 - parameter;
|
||||
var handle = through.subtract(
|
||||
current.multiply(t1 * t1)).subtract(
|
||||
to.multiply(parameter * parameter)).divide(
|
||||
2.0 * parameter * t1);
|
||||
if (handle.isNaN())
|
||||
throw new Error(
|
||||
"Cannot put a curve through points with parameter="
|
||||
+ parameter);
|
||||
this.quadraticCurveTo(handle, to);
|
||||
},
|
||||
|
||||
arcTo: function(to, clockwise) {
|
||||
var through, to;
|
||||
if(arguments[1] && typeof arguments[1] != 'boolean') {
|
||||
through = new Point(arguments[0]);
|
||||
to = new Point(arguments[1]);
|
||||
} else {
|
||||
if(clockwise === null)
|
||||
clockwise = true;
|
||||
var current = this.segments[this.segments.length - 1].point;
|
||||
var middle = current.add(to).divide(2);
|
||||
var step = middle.subtract(current);
|
||||
through = clockwise
|
||||
? middle.subtract(-step.y, step.x)
|
||||
: middle.add(-step.y, step.x);
|
||||
}
|
||||
|
||||
// Get the start point:
|
||||
var current = this.segments[this.segments.length - 1];
|
||||
var x1 = current.point.x, x2 = through.x, x3 = to.x;
|
||||
var y1 = current.point.y, y2 = through.y, y3 = to.y;
|
||||
|
||||
var f = x3 * x3 - x3 * x2 - x1 * x3 + x1 * x2 + y3 * y3 - y3 * y2
|
||||
- y1 * y3 + y1 * y2;
|
||||
var g = x3 * y1 - x3 * y2 + x1 * y2 - x1 * y3 + x2 * y3 - x2 * y1;
|
||||
var m = g == 0 ? 0 : f / g;
|
||||
|
||||
var c = (m * y2) - x2 - x1 - (m * y1);
|
||||
var d = (m * x1) - y1 - y2 - (x2 * m);
|
||||
var e = (x1 * x2) + (y1 * y2) - (m * x1 * y2) + (m * x2 * y1);
|
||||
|
||||
var centerX = -c / 2;
|
||||
var centerY = -d / 2;
|
||||
var radius = Math.sqrt(centerX * centerX + centerY * centerY - e);
|
||||
|
||||
// Note: reversing the Y equations negates the angle to adjust
|
||||
// for the upside down coordinate system.
|
||||
var angle = Math.atan2(centerY - y1, x1 - centerX);
|
||||
var middle = Math.atan2(centerY - y2, x2 - centerX);
|
||||
var extent = Math.atan2(centerY - y3, x3 - centerX);
|
||||
|
||||
var diff = middle - angle;
|
||||
if (diff < -Math.PI)
|
||||
diff += Math.PI * 2;
|
||||
else if (diff > Math.PI)
|
||||
diff -= Math.PI * 2;
|
||||
|
||||
extent -= angle;
|
||||
if (extent <= 0.0)
|
||||
extent += Math.PI * 2;
|
||||
|
||||
if (diff < 0) extent = Math.PI * 2 - extent;
|
||||
else extent = -extent;
|
||||
angle = -angle;
|
||||
|
||||
var ext = Math.abs(extent);
|
||||
var arcSegs;
|
||||
if (ext >= 2 * Math.PI) arcSegs = 4;
|
||||
else arcSegs = Math.ceil(ext * 2 / Math.PI);
|
||||
|
||||
var inc = extent;
|
||||
if (inc > 2 * Math.PI) inc = 2 * Math.PI;
|
||||
else if (inc < -2 * Math.PI) inc = -2 * Math.PI;
|
||||
inc /= arcSegs;
|
||||
|
||||
var halfInc = inc / 2;
|
||||
var z = 4 / 3 * Math.sin(halfInc) / (1 + Math.cos(halfInc));
|
||||
|
||||
for (var i = 0; i <= arcSegs; i++) {
|
||||
var relx = Math.cos(angle);
|
||||
var rely = Math.sin(angle);
|
||||
var pt = new Point(centerX + relx * radius,
|
||||
centerY + rely * radius);
|
||||
var out;
|
||||
if (i == arcSegs) out = null;
|
||||
else out = new Point(centerX + (relx - z * rely) * radius - pt.x,
|
||||
centerY + (rely + z * relx) * radius - pt.y);
|
||||
if (i == 0) {
|
||||
// Modify startSegment
|
||||
current.handleOut = out;
|
||||
} else {
|
||||
// Add new Segment
|
||||
var inPoint = new Point(
|
||||
centerX + (relx + z * rely) * radius - pt.x,
|
||||
centerY + (rely - z * relx) * radius - pt.y);
|
||||
this.segments.push(new Segment(pt, inPoint, out));
|
||||
}
|
||||
angle += inc;
|
||||
}
|
||||
},
|
||||
|
||||
lineBy: function() {
|
||||
var vector = Point.read(arguments);
|
||||
if(vector) {
|
||||
var current = this.segments[this.segments.length - 1];
|
||||
this.lineTo(current.point.add(vector));
|
||||
}
|
||||
},
|
||||
|
||||
smooth: function() {
|
||||
var segments = this.segments;
|
||||
|
||||
// This code is based on the work by Oleg V. Polikarpotchkin,
|
||||
// http://ov-p.spaces.live.com/blog/cns!39D56F0C7A08D703!147.entry
|
||||
// It was extended to support closed paths by averaging overlapping
|
||||
// beginnings and ends. The result of this approach is very close to
|
||||
// Polikarpotchkin's closed curve solution, but reuses the same
|
||||
// algorithm as for open paths, and is probably executing faster as
|
||||
// well, so it is preferred.
|
||||
var size = segments.length;
|
||||
if (size <= 2)
|
||||
return;
|
||||
|
||||
var n = size;
|
||||
// Add overlapping ends for averaging handles in closed paths
|
||||
var overlap;
|
||||
if (this.closed) {
|
||||
// Overlap up to 4 points since averaging beziers affect the 4
|
||||
// neighboring points
|
||||
overlap = Math.min(size, 4);
|
||||
n += Math.min(size, overlap) * 2;
|
||||
} else {
|
||||
overlap = 0;
|
||||
}
|
||||
var knots = [];
|
||||
for (var i = 0; i < size; i++)
|
||||
knots[i + overlap] = segments[i].point;
|
||||
if (this.closed) {
|
||||
// If we're averaging, add the 4 last points again at the beginning,
|
||||
// and the 4 first ones at the end.
|
||||
for (var i = 0; i < overlap; i++) {
|
||||
knots[i] = segments[i + size - overlap].point;
|
||||
knots[i + size + overlap] = segments[i].point;
|
||||
}
|
||||
} else {
|
||||
n--;
|
||||
}
|
||||
// Calculate first Bezier control points
|
||||
// Right hand side vector
|
||||
var rhs = [];
|
||||
|
||||
// Set right hand side X values
|
||||
for (var i = 1; i < n - 1; i++)
|
||||
rhs[i] = 4 * knots[i].x + 2 * knots[i + 1].x;
|
||||
rhs[0] = knots[0].x + 2 * knots[1].x;
|
||||
rhs[n - 1] = 3 * knots[n - 1].x;
|
||||
// Get first control points X-values
|
||||
var x = getFirstControlPoints(rhs);
|
||||
|
||||
// Set right hand side Y values
|
||||
for (var i = 1; i < n - 1; i++)
|
||||
rhs[i] = 4 * knots[i].y + 2 * knots[i + 1].y;
|
||||
rhs[0] = knots[0].y + 2 * knots[1].y;
|
||||
rhs[n - 1] = 3 * knots[n - 1].y;
|
||||
// Get first control points Y-values
|
||||
var y = getFirstControlPoints(rhs);
|
||||
|
||||
if (this.closed) {
|
||||
// Do the actual averaging simply by linearly fading between the
|
||||
// overlapping values.
|
||||
for (var i = 0, j = size; i < overlap; i++, j++) {
|
||||
var f1 = (i / overlap);
|
||||
var f2 = 1 - f1;
|
||||
// Beginning
|
||||
x[j] = x[i] * f1 + x[j] * f2;
|
||||
y[j] = y[i] * f1 + y[j] * f2;
|
||||
// End
|
||||
var ie = i + overlap, je = j + overlap;
|
||||
x[je] = x[ie] * f2 + x[je] * f1;
|
||||
y[je] = y[ie] * f2 + y[je] * f1;
|
||||
}
|
||||
n--;
|
||||
}
|
||||
var handleIn = null;
|
||||
// Now set the calculated handles
|
||||
for (var i = overlap; i <= n - overlap; i++) {
|
||||
var segment = segments[i - overlap];
|
||||
if (handleIn != null)
|
||||
segment.handleIn = handleIn.subtract(segment.point);
|
||||
if (i < n) {
|
||||
segment.handleOut =
|
||||
new Point(x[i], y[i]).subtract(segment.point);
|
||||
if (i < n - 1)
|
||||
handleIn = new Point(
|
||||
2 * knots[i + 1].x - x[i + 1],
|
||||
2 * knots[i + 1].y - y[i + 1]);
|
||||
else
|
||||
handleIn = new Point(
|
||||
(knots[n].x + x[n - 1]) / 2,
|
||||
(knots[n].y + y[n - 1]) / 2);
|
||||
}
|
||||
}
|
||||
if (closed && handleIn != null) {
|
||||
var segment = get(0);
|
||||
segment.handleIn = handleIn.subtract(segment.point);
|
||||
}
|
||||
},
|
||||
|
||||
curveBy: function(throughVector, toVector, parameter) {
|
||||
throughVector = Point.read(throughVector);
|
||||
toVector = Point.read(toVector);
|
||||
var current = this.segments[this.segments.length - 1].point;
|
||||
this.curveTo(current.add(throughVector), current.add(toVector), parameter);
|
||||
},
|
||||
|
||||
arcBy: function(throughVector, toVector) {
|
||||
throughVector = Point.read(throughVector);
|
||||
toVector = Point.read(toVector);
|
||||
var current = this.segments[this.segments.length - 1].point;
|
||||
this.arcBy(current.add(throughVector), current.add(toVector));
|
||||
},
|
||||
|
||||
setCtxStyles: function(ctx) {
|
||||
for(var i in styleNames) {
|
||||
var style;
|
||||
if(style = this[i])
|
||||
ctx[styleNames[i]] = style;
|
||||
}
|
||||
},
|
||||
|
||||
draw: function(ctx) {
|
||||
ctx.beginPath();
|
||||
var cp1;
|
||||
for(var i = 0, l = this.segments.length; i < l; i++) {
|
||||
var segment = this.segments[i];
|
||||
var point = segment.point;
|
||||
var handleIn = segment.handleIn ? segment.handleIn.add(point) : point;
|
||||
var handleOut = segment.handleOut ? segment.handleOut.add(point) : point;
|
||||
if(i == 0) {
|
||||
ctx.moveTo(point.x, point.y);
|
||||
} else {
|
||||
ctx.bezierCurveTo(cp1.x, cp1.y, handleIn.x, handleIn.y,
|
||||
point.x, point.y);
|
||||
}
|
||||
cp1 = handleOut;
|
||||
}
|
||||
if(this.closed) {
|
||||
var segment = this.segments[0];
|
||||
var point = segment.point;
|
||||
var handleIn = segment.handleIn ? segment.handleIn.add(point) : point;
|
||||
ctx.bezierCurveTo(cp1.x, cp1.y, handleIn.x, handleIn.y,
|
||||
point.x, point.y);
|
||||
ctx.closePath();
|
||||
}
|
||||
this.setCtxStyles(ctx);
|
||||
if(this.fillColor) ctx.fill();
|
||||
if(this.strokeColor) ctx.stroke();
|
||||
}
|
||||
};
|
||||
});
|
297
src/Point.js
Normal file
297
src/Point.js
Normal file
|
@ -0,0 +1,297 @@
|
|||
var Point = Base.extend({
|
||||
initialize: function() {
|
||||
if(arguments.length == 2) {
|
||||
this.x = arguments[0];
|
||||
this.y = arguments[1];
|
||||
} else if(arguments.length == 1) {
|
||||
var first = arguments[0];
|
||||
if(first == null) {
|
||||
this.x = this.y = 0;
|
||||
} else if(first.x !== undefined) {
|
||||
this.x = first.x;
|
||||
this.y = first.y;
|
||||
this.angle = first.angle;
|
||||
} else if(first.width !== undefined) {
|
||||
this.x = first.width;
|
||||
this.y = first.height;
|
||||
this.angle = null;
|
||||
} else if(first.length !== undefined) {
|
||||
this.x = first[0];
|
||||
this.y = first.length > 1 ? first[1] : first[0];
|
||||
} else if(typeof first === 'number') {
|
||||
this.x = this.y = first;
|
||||
this.angle = null;
|
||||
} else {
|
||||
this.x = this.y = 0;
|
||||
}
|
||||
} else {
|
||||
this.x = this.y = 0;
|
||||
}
|
||||
},
|
||||
|
||||
clone: function() {
|
||||
return new Point(this.x, this.y);
|
||||
},
|
||||
|
||||
add: function() {
|
||||
var point = Point.read(arguments);
|
||||
return new Point(this.x + point.x, this.y + point.y);
|
||||
},
|
||||
|
||||
subtract: function() {
|
||||
var point = Point.read(arguments);
|
||||
return new Point(this.x - point.x, this.y - point.y);
|
||||
},
|
||||
|
||||
multiply: function() {
|
||||
var point = Point.read(arguments);
|
||||
return new Point(this.x * point.x, this.y * point.y);
|
||||
},
|
||||
|
||||
divide: function() {
|
||||
var point = Point.read(arguments);
|
||||
return new Point(this.x / point.x, this.y / point.y);
|
||||
},
|
||||
|
||||
modulo: function() {
|
||||
var point = Point.read(arguments);
|
||||
return new Point(this.x % point.x, this.y % point.y);
|
||||
},
|
||||
|
||||
negate: function() {
|
||||
return new Point(-this.x, -this.y);
|
||||
},
|
||||
|
||||
equals: function() {
|
||||
var point = Point.read(arguments);
|
||||
return this.x == point.x && this.y == point.y;
|
||||
},
|
||||
|
||||
getDistance: function() {
|
||||
var point = Point.read(arguments);
|
||||
var px = point.x - this.x;
|
||||
var py = point.y - this.y;
|
||||
return Math.sqrt(px * px + py * py);
|
||||
},
|
||||
|
||||
getDistanceSquared: function() {
|
||||
var point = Point.read(arguments);
|
||||
var px = point.x - this.x;
|
||||
var py = point.y - this.y;
|
||||
return px * px + py * py;
|
||||
},
|
||||
|
||||
getLength: function() {
|
||||
var point = Point.read(arguments);
|
||||
return Math.sqrt(this.x * this.x + this.y * this.y);
|
||||
},
|
||||
|
||||
setLength: function(length) {
|
||||
if (this.isZero()) {
|
||||
if (this.angle != null) {
|
||||
var a = this.angle;
|
||||
this.x = Math.cos(a) * length;
|
||||
this.y = Math.sin(a) * length;
|
||||
} else {
|
||||
// Assume angle = 0
|
||||
this.x = length;
|
||||
// y is already 0
|
||||
}
|
||||
} else {
|
||||
var scale = length / this.getLength();
|
||||
if (scale == 0.0) {
|
||||
// Calculate angle now, so it will be preserved even when
|
||||
// x and y are 0
|
||||
this.getAngle();
|
||||
}
|
||||
this.x *= scale;
|
||||
this.y *= scale;
|
||||
}
|
||||
},
|
||||
|
||||
normalize: function(length) {
|
||||
if (length === null)
|
||||
length = 1;
|
||||
var len = this.getLength();
|
||||
var scale = len != 0 ? length / len : 0;
|
||||
var res = new Point(this.x * scale, this.y * scale);
|
||||
// Preserve angle.
|
||||
res.angle = this.angle;
|
||||
return res;
|
||||
},
|
||||
|
||||
getAngleInRadians: function() {
|
||||
return Math.atan2(this.y, this.x);
|
||||
},
|
||||
|
||||
getAngleInDegrees: function() {
|
||||
return Math.atan2(this.y, this.x) * 180 / Math.PI;
|
||||
},
|
||||
|
||||
|
||||
getQuadrant: function() {
|
||||
if (this.x >= 0) {
|
||||
if (this.y >= 0) {
|
||||
return 1;
|
||||
} else {
|
||||
return 4;
|
||||
}
|
||||
} else {
|
||||
if (this.y >= 0) {
|
||||
return 2;
|
||||
} else {
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
setAngle: function(angle) {
|
||||
angle = this.angle = angle * Math.PI / 180;
|
||||
if(!this.isZero()) {
|
||||
var length = this.getLength();
|
||||
this.x = Math.cos(angle) * length;
|
||||
this.y = Math.sin(angle) * length;
|
||||
}
|
||||
},
|
||||
|
||||
getAngle: function() {
|
||||
var angle;
|
||||
if(arguments.length) {
|
||||
var point = Point.read(arguments);
|
||||
var div = this.getLength() * point.getLength();
|
||||
if(div == 0) {
|
||||
return NaN;
|
||||
} else {
|
||||
angle = Math.acos(this.dot(point) / div);
|
||||
}
|
||||
} else {
|
||||
angle = this.angle = Math.atan2(this.y, this.x);
|
||||
}
|
||||
return angle * 180 / Math.PI;
|
||||
},
|
||||
|
||||
getDirectedAngle: function() {
|
||||
var point = Point.read(arguments);
|
||||
var angle = this.getAngle() - point.getAngle();
|
||||
var bounds = 180;
|
||||
if(angle < - bounds) {
|
||||
return angle + bounds * 2;
|
||||
} else if (angle > bounds) {
|
||||
return angle - bounds * 2;
|
||||
} else {
|
||||
return angle;
|
||||
}
|
||||
},
|
||||
|
||||
rotate: function(angle) {
|
||||
angle = angle * Math.PI / 180;
|
||||
var s = Math.sin(angle);
|
||||
var c = Math.cos(angle);
|
||||
return new Point(
|
||||
this.x * c - this.y * s,
|
||||
this.y * c + this.x * s
|
||||
);
|
||||
},
|
||||
|
||||
rotateAround: function(angle, center) {
|
||||
center = new Point(center);
|
||||
return this.subtract(center).rotate(angle).add(this);
|
||||
},
|
||||
|
||||
interpolate: function(point, t) {
|
||||
return new Point(
|
||||
this.x * (1 - t) + point.x * t,
|
||||
this.y * (1 - t) + point.y * t
|
||||
);
|
||||
},
|
||||
|
||||
// Need to adapt Rectangle.java first
|
||||
// isInside: function(rect) {
|
||||
// return rect.contains(this);
|
||||
// },
|
||||
|
||||
isClose: function(point, tolerance) {
|
||||
point = new Point(point);
|
||||
return this.getDistance(point) < tolerance;
|
||||
},
|
||||
|
||||
isParallel: function(point) {
|
||||
return Math.abs(this.x / point.x - this.y / point.y) < 0.00001;
|
||||
},
|
||||
|
||||
isZero: function() {
|
||||
return this.x == 0 && this.y == 0;
|
||||
},
|
||||
|
||||
isNaN: function() {
|
||||
return isNaN(this.x) || isNaN(this.y);
|
||||
},
|
||||
|
||||
round: function() {
|
||||
return new Point(Math.round(this.x), Math.round(this.y));
|
||||
},
|
||||
|
||||
ceil: function() {
|
||||
return new Point(Math.ceil(this.x), Math.ceil(this.y));
|
||||
},
|
||||
|
||||
floor: function() {
|
||||
return new Point(Math.floor(this.x), Math.floor(this.y));
|
||||
},
|
||||
|
||||
abs: function() {
|
||||
return new Point(Math.abs(this.x), Math.abs(this.y));
|
||||
},
|
||||
|
||||
dot: function() {
|
||||
var point = Point.read(arguments);
|
||||
return this.x * point.x + this.y * point.y;
|
||||
},
|
||||
|
||||
cross: function() {
|
||||
var point = Point.read(arguments);
|
||||
return this.x * point.y - this.y - point.x;
|
||||
},
|
||||
|
||||
project: function() {
|
||||
var point = Point.read(arguments);
|
||||
if(point.isZero()) {
|
||||
return new Point(0, 0);
|
||||
} else {
|
||||
var scale = this.dot(point) / point.dot(point);
|
||||
return new Point(
|
||||
point.x * scale,
|
||||
point.y * scale
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
toString: function() {
|
||||
return '{ x: ' + this.x + ', y: ' + this.y + ' }';
|
||||
},
|
||||
|
||||
statics: {
|
||||
read: function(args) {
|
||||
if(args.length) {
|
||||
var point = new Point();
|
||||
point.initialize.apply(point, args);
|
||||
return point;
|
||||
}
|
||||
},
|
||||
min: function(point1, point2) {
|
||||
return new Point(
|
||||
Math.min(point1.x, point2.x),
|
||||
Math.min(point1.y, point2.y));
|
||||
},
|
||||
|
||||
max: function(point1, point2) {
|
||||
return new Point(
|
||||
Math.max(point1.x, point2.x),
|
||||
Math.max(point1.y, point2.y));
|
||||
},
|
||||
|
||||
random: function() {
|
||||
return new Point(Math.random(), Math.random());
|
||||
}
|
||||
}
|
||||
});
|
287
src/Rectangle.js
Normal file
287
src/Rectangle.js
Normal file
|
@ -0,0 +1,287 @@
|
|||
Rectangle = Base.extend({
|
||||
initialize: function() {
|
||||
if(arguments.length == 1) {
|
||||
var rect = arguments[0];
|
||||
this.x = rect.x;
|
||||
this.y = rect.y;
|
||||
this.width = rect.width;
|
||||
this.height = rect.height;
|
||||
} else if(arguments.length == 2) {
|
||||
if(arguments[1].x !== undefined) {
|
||||
// new Rectangle(point1, point2)
|
||||
var point1 = new Point(arguments[0]);
|
||||
var point2 = new Point(arguments[1]);
|
||||
this.x = point1.x;
|
||||
this.y = point1.y;
|
||||
this.width = point2.x - point1.x;
|
||||
this.height = point2.y - point1.y;
|
||||
if(this.width < 0) {
|
||||
this.x = point2.x;
|
||||
this.width = -this.width;
|
||||
}
|
||||
if(this.height < 0) {
|
||||
this.y = point2.y;
|
||||
this.height = -this.height;
|
||||
}
|
||||
} else {
|
||||
// new Rectangle(point, size)
|
||||
var point = new Point(arguments[0]);
|
||||
var size = new Size(arguments[1]);
|
||||
this.x = point.x;
|
||||
this.y = point.y;
|
||||
this.width = size.width;
|
||||
this.height = size.height;
|
||||
}
|
||||
} else if(arguments.length == 4) {
|
||||
// new Rectangle(x, y, width, height)
|
||||
this.x = arguments[0];
|
||||
this.y = arguments[1];
|
||||
this.width = arguments[2];
|
||||
this.height = arguments[3];
|
||||
} else {
|
||||
// new Rectangle()
|
||||
this.x = this.y = this.width = this.height = 0;
|
||||
}
|
||||
},
|
||||
|
||||
getPoint: function() {
|
||||
return new Point(this.x, this.y);
|
||||
},
|
||||
|
||||
setPoint: function() {
|
||||
var point = Point.read(arguments);
|
||||
this.x = point.x;
|
||||
this.y = point.y;
|
||||
},
|
||||
|
||||
getSize: function() {
|
||||
return new Size(this.width, this.height);
|
||||
},
|
||||
|
||||
setSize: function() {
|
||||
var size = Size.read(arguments);
|
||||
this.width = size.width;
|
||||
this.height = size.height;
|
||||
},
|
||||
|
||||
getLeft: function() {
|
||||
return this.x;
|
||||
},
|
||||
|
||||
setLeft: function(left) {
|
||||
// right should not move
|
||||
this.width -= left - this.x;
|
||||
this.x = left;
|
||||
},
|
||||
|
||||
getTop: function() {
|
||||
return this.y;
|
||||
},
|
||||
|
||||
setTop: function(top) {
|
||||
this.height -= top - this.y;
|
||||
this.y = top;
|
||||
},
|
||||
|
||||
getRight: function() {
|
||||
return this.x + this.width;
|
||||
},
|
||||
|
||||
setRight: function(right) {
|
||||
this.width = right - this.x;
|
||||
},
|
||||
|
||||
getBottom: function() {
|
||||
return this.y + this.height;
|
||||
},
|
||||
|
||||
setBottom: function(bottom) {
|
||||
this.height = bottom - this.y;
|
||||
},
|
||||
|
||||
getCenterX: function() {
|
||||
return this.x + this.width * 0.5;
|
||||
},
|
||||
|
||||
setCenterX: function(x) {
|
||||
this.x = x - this.width * 0.5;
|
||||
},
|
||||
|
||||
getCenterY: function() {
|
||||
return this.y + this.height * 0.5;
|
||||
},
|
||||
|
||||
setCenterY: function(y) {
|
||||
this.y = y - this.height * 0.5;
|
||||
},
|
||||
|
||||
getCenter: function() {
|
||||
return new Point(this.x - this.width / 2, this.y - this.height / 2);
|
||||
},
|
||||
|
||||
setCenter: function() {
|
||||
var center = Point.read(arguments);
|
||||
this.x = center.x - this.width / 2;
|
||||
this.y = center.y - this.height / 2;
|
||||
},
|
||||
|
||||
getTopLeft: function() {
|
||||
return new Point(this.getLeft(), this.getTop());
|
||||
},
|
||||
|
||||
setTopLeft: function() {
|
||||
var topLeft = Point.read(arguments);
|
||||
this.setLeft(topLeft.x);
|
||||
this.setTop(topLeft.y);
|
||||
},
|
||||
|
||||
getTopRight: function() {
|
||||
return new Point(this.getRight(), this.getTop());
|
||||
},
|
||||
|
||||
setTopRight: function() {
|
||||
var topRight = Point.read(arguments);
|
||||
this.setRight(topRight.x);
|
||||
this.setTop(topRight.y);
|
||||
},
|
||||
|
||||
getBottomLeft: function() {
|
||||
return new Point(this.getLeft(), this.getBottom());
|
||||
},
|
||||
|
||||
setBottomLeft: function() {
|
||||
var bottomLeft = Point.read(arguments);
|
||||
this.setLeft(bottomLeft.x);
|
||||
this.setBottom(bottomLeft.y);
|
||||
},
|
||||
|
||||
getBottomRight: function() {
|
||||
return new Point(this.getRight(), this.getBottom());
|
||||
},
|
||||
|
||||
setBottomRight: function() {
|
||||
var bottomRight = Point.read(arguments);
|
||||
this.setBottom(bottomRight.y);
|
||||
this.setRight(bottomRight.x);
|
||||
},
|
||||
|
||||
getLeftCenter: function() {
|
||||
return new Point(this.getLeft(), this.getCenterY());
|
||||
},
|
||||
|
||||
setLeftCenter: function() {
|
||||
var leftCenter = Point.read(arguments);
|
||||
this.setLeft(leftCenter.x);
|
||||
this.setCenterY(leftCenter.y);
|
||||
},
|
||||
|
||||
getTopCenter: function() {
|
||||
return new Point(this.getCenterX(), this.getTop());
|
||||
},
|
||||
|
||||
setTopCenter: function() {
|
||||
var topCenter = Point.read(arguments);
|
||||
this.setCenterX(topCenter.x);
|
||||
this.setTop(topCenter.y);
|
||||
},
|
||||
|
||||
getRightCenter: function() {
|
||||
return new Point(this.getRight(), this.getCenterY());
|
||||
},
|
||||
|
||||
setRightCenter: function() {
|
||||
var rightCenter = Point.read(arguments);
|
||||
this.setRight(rightCenter.x);
|
||||
this.setCenterY(rightCenter.y);
|
||||
},
|
||||
|
||||
getBottomCenter: function() {
|
||||
return new Point(this.getCenterX(), this.getBottom());
|
||||
},
|
||||
|
||||
setBottomCenter: function() {
|
||||
var bottomCenter = Point.read(arguments);
|
||||
this.setBottom(bottomCenter.y);
|
||||
this.setCenterX(bottomCenter.x);
|
||||
},
|
||||
|
||||
clone: function() {
|
||||
return new Rectangle(this);
|
||||
},
|
||||
|
||||
equals: function() {
|
||||
var rect = Rectangle.read(arguments);
|
||||
return this.x == rect.x && this.y == rect.y
|
||||
&& this.width == rect.width && this.height == rect.height;
|
||||
},
|
||||
|
||||
isEmpty: function() {
|
||||
return this.width == 0 || this.height == 0;
|
||||
},
|
||||
|
||||
contains: function(rect) {
|
||||
if(rect.width !== undefined) {
|
||||
return rect.x >= this.x && rect.y >= this.y
|
||||
&& rect.x + rect.width <= this.x + this.width
|
||||
&& rect.y + rect.height <= this.y + this.height;
|
||||
} else {
|
||||
var point = Point.read(arguments);
|
||||
return point.x >= this.x && point.y >= this.y
|
||||
&& point.x <= this.x + this.width
|
||||
&& point.y <= this.y + this.height;
|
||||
}
|
||||
},
|
||||
|
||||
intersects: function() {
|
||||
var rect = Rectangle.read(arguments);
|
||||
return rect.x + rect.width > this.x
|
||||
&& rect.y + rect.height > this.y
|
||||
&& rect.x < this.x + this.width
|
||||
&& rect.y < this.y + this.height;
|
||||
},
|
||||
|
||||
intersect: function() {
|
||||
var rect = Rectangle.read(arguments);
|
||||
var x1 = Math.max(this.x, rect.x);
|
||||
var y1 = Math.max(this.y, rect.y);
|
||||
var x2 = Math.min(this.x + this.width, rect.x + rect.width);
|
||||
var y2 = Math.min(this.y + this.height, rect.y + rect.height);
|
||||
return new Rectangle(x1, y1, x2 - x1, y2 - y1);
|
||||
},
|
||||
|
||||
unite: function() {
|
||||
var rect = Rectangle.read(arguments);
|
||||
var x1 = Math.min(this.x, rect.x);
|
||||
var y1 = Math.min(this.y, rect.y);
|
||||
var x2 = Math.max(this.x + this.width, rect.x + rect.width);
|
||||
var y2 = Math.max(this.y + this.height, rect.y + rect.height);
|
||||
return new Rectangle(x1, y1, x2 - x1, y2 - y1);
|
||||
},
|
||||
|
||||
include: function() {
|
||||
var point = Point.read(arguments);
|
||||
var x1 = Math.min(this.x, point.x);
|
||||
var y1 = Math.min(this.y, point.y);
|
||||
var x2 = Math.max(this.x + this.width, point.x);
|
||||
var y2 = Math.max(this.y + this.height, point.y);
|
||||
return new Rectangle(x1, y1, x2 - x1, y2 - y1);
|
||||
},
|
||||
|
||||
toString: function() {
|
||||
return '{ x: ' + this.x
|
||||
+ ', y: ' + this.y
|
||||
+ ', width: ' + this.width
|
||||
+ ', height: ' + this.height
|
||||
+ ' }';
|
||||
},
|
||||
|
||||
statics: {
|
||||
read: function(args) {
|
||||
if(args.length) {
|
||||
var rect = new Rectangle();
|
||||
rect.initialize.apply(rect, args);
|
||||
return rect;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
138
src/Segment.js
Normal file
138
src/Segment.js
Normal file
|
@ -0,0 +1,138 @@
|
|||
Segment = Base.extend({
|
||||
initialize: function() {
|
||||
if(arguments.length == 0) {
|
||||
this.point = new Point();
|
||||
} else if(arguments.length == 1) {
|
||||
if(arguments[0].point) {
|
||||
var segment = arguments[0];
|
||||
this.point = new Point(segment.point);
|
||||
if(segment.handleIn)
|
||||
this.handleIn = new Point(segment.handleIn);
|
||||
if(segment.handleOut)
|
||||
this.handleOut = new Point(segment.handleOut);
|
||||
} else {
|
||||
this.point = new Point(arguments[0]);
|
||||
}
|
||||
} else if(arguments.length < 6) {
|
||||
if(arguments.length == 2 && !arguments[1].x) {
|
||||
this.point = new Point(arguments[0], arguments[1]);
|
||||
} else {
|
||||
this.point = new Point(arguments[0]);
|
||||
if(arguments[1])
|
||||
this.handleIn = new Point(arguments[1]);
|
||||
if(arguments[2])
|
||||
this.handleOut = new Point(arguments[2]);
|
||||
}
|
||||
} else if(arguments.length == 6) {
|
||||
this.point = new Point(arguments[0], arguments[1]);
|
||||
this.handleIn = new Point(arguments[2], arguments[3]);
|
||||
this.handleOut = new Point(arguments[4], arguments[5]);
|
||||
}
|
||||
},
|
||||
|
||||
insert: function() {
|
||||
if(this.segments && this.segments.path) {
|
||||
var path = this.segments.path;
|
||||
path.checkValid();
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
getPoint: function() {
|
||||
return this.point;
|
||||
},
|
||||
|
||||
setPoint: function() {
|
||||
var point = Point.read(arguments);
|
||||
this.point = point;
|
||||
},
|
||||
|
||||
getHandleIn: function() {
|
||||
return this.handleIn;
|
||||
},
|
||||
|
||||
setHandleIn: function() {
|
||||
var point = Point.read(arguments);
|
||||
this.handleIn = point;
|
||||
},
|
||||
|
||||
getHandleOut: function() {
|
||||
return this.handleOut;
|
||||
},
|
||||
|
||||
setHandleOut: function() {
|
||||
var point = Point.read(arguments);
|
||||
this.handleOut = point;
|
||||
this.corner = !handleIn.isParallel(handleOut);
|
||||
},
|
||||
|
||||
getIndex: function() {
|
||||
var segments = this.path.segments;
|
||||
for(var i = 0, l = segments.length; i < l; i++) {
|
||||
if(segments[i] == this)
|
||||
return i;
|
||||
}
|
||||
},
|
||||
|
||||
getPath: function() {
|
||||
return this.path;
|
||||
},
|
||||
|
||||
// todo
|
||||
// getCurve: function() {
|
||||
// if(this.segments && this.segments.path) {
|
||||
// var curves = this.segments.path.getCurves();
|
||||
// // The curves list handles closing curves, so the curves.size
|
||||
// // is adjusted accordingly. just check to be in the boundaries here:
|
||||
// return index < curves.length ? curves[index] : null;
|
||||
// }
|
||||
// },
|
||||
|
||||
getNext: function() {
|
||||
var index = this.getIndex();
|
||||
return this.path && index < this.path.segments.length - 1
|
||||
? this.path.segments[index + 1] : null;
|
||||
},
|
||||
|
||||
getPrevious: function() {
|
||||
return this.path != null && index > 0 ? this.segments[this.getIndex() - 1] : null;
|
||||
},
|
||||
|
||||
// todo
|
||||
// isSelected: function() {
|
||||
//
|
||||
// }
|
||||
//
|
||||
// setSelected: function(pt, selected)
|
||||
|
||||
reverse: function() {
|
||||
return new Segment(this.point, this.handleOut, this.handleIn);
|
||||
},
|
||||
|
||||
clone: function() {
|
||||
return new Segment(this);
|
||||
},
|
||||
|
||||
remove: function() {
|
||||
if(this.segments)
|
||||
return this.path.segments.unshift(this.getIndex(), 1);
|
||||
return false;
|
||||
},
|
||||
|
||||
toString: function() {
|
||||
return '{ point: ' + this.point.toString()
|
||||
+ ', handleIn '+ this.handleIn.toString()
|
||||
+ ', handleOut ' + this.handleOut.toString()
|
||||
+ ' }';
|
||||
},
|
||||
|
||||
statics: {
|
||||
read: function(args) {
|
||||
if(args.length && args[0] != null) {
|
||||
var segment = new Segment();
|
||||
segment.initialize.apply(segment, args);
|
||||
return segment;
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
10
src/SegmentList.js
Normal file
10
src/SegmentList.js
Normal file
|
@ -0,0 +1,10 @@
|
|||
SegmentList = Array.extend({
|
||||
initialize: function(path) {
|
||||
this.length = 0;
|
||||
this.path = path;
|
||||
},
|
||||
push: function() {
|
||||
this.base.apply(this, arguments);
|
||||
this.path.listChanged();
|
||||
}
|
||||
});
|
113
src/Size.js
Normal file
113
src/Size.js
Normal file
|
@ -0,0 +1,113 @@
|
|||
var Size = Base.extend({
|
||||
initialize: function() {
|
||||
if(arguments.length == 2) {
|
||||
this.width = arguments[0];
|
||||
this.height = arguments[1];
|
||||
} else if(arguments.length == 1) {
|
||||
var first = arguments[0];
|
||||
if(first.width !== undefined || first.height !== undefined) {
|
||||
this.width = first.width ? first.width : 0;
|
||||
this.height = first.height ? first.height : 0;
|
||||
} else if(first.x !== undefined || first.y !== undefined) {
|
||||
this.width = first.x ? first.x : 0;
|
||||
this.height = first.y ? first.y : 0;
|
||||
} else if(first.length !== undefined) {
|
||||
this.width = first[0];
|
||||
this.height = first.length > 1 ? first[1] : first[0];
|
||||
} else if(typeof first === 'number') {
|
||||
this.width = this.height = first;
|
||||
} else {
|
||||
this.width = this.height = 0;
|
||||
}
|
||||
} else {
|
||||
this.width = this.height = 0;
|
||||
}
|
||||
},
|
||||
|
||||
add: function() {
|
||||
var size = Size.read(arguments);
|
||||
return new Size(this.width + size.width, this.height + size.height);
|
||||
},
|
||||
|
||||
subtract: function() {
|
||||
var size = Size.read(arguments);
|
||||
return new Size(this.width - size.width, this.height - size.height);
|
||||
},
|
||||
|
||||
multiply: function() {
|
||||
var size = Size.read(arguments);
|
||||
return new Size(this.width * size.width, this.height * size.height);
|
||||
},
|
||||
|
||||
divide: function() {
|
||||
var size = Size.read(arguments);
|
||||
return new Size(this.width / size.width, this.height / size.height);
|
||||
},
|
||||
|
||||
modulo: function() {
|
||||
var size = Size.read(arguments);
|
||||
return new Size(this.width % size.width, this.height % size.height);
|
||||
},
|
||||
|
||||
negate: function() {
|
||||
return new Size(-this.width, -this.height);
|
||||
},
|
||||
|
||||
equals: function() {
|
||||
var size = Size.read(arguments);
|
||||
return this.width == size.width && this.height == size.height;
|
||||
},
|
||||
|
||||
isNaN: function() {
|
||||
return isNaN(this.width) || isNaN(this.height);
|
||||
},
|
||||
|
||||
round: function() {
|
||||
return new Size(Math.round(this.width), Math.round(this.height));
|
||||
},
|
||||
|
||||
ceil: function() {
|
||||
return new Size(Math.ceil(this.width), Math.ceil(this.height));
|
||||
},
|
||||
|
||||
floor: function() {
|
||||
return new Size(Math.floor(this.width), Math.floor(this.height));
|
||||
},
|
||||
|
||||
abs: function() {
|
||||
return new Size(Math.abs(this.width), Math.abs(this.height));
|
||||
},
|
||||
|
||||
dot: function(Size) {
|
||||
return this.width * size.width + this.height * size.height;
|
||||
},
|
||||
|
||||
toString: function() {
|
||||
return '{ x: ' + this.width + ', y: ' + this.height + ' }';
|
||||
},
|
||||
|
||||
statics: {
|
||||
read: function(args) {
|
||||
if(args.length) {
|
||||
var size = new Size();
|
||||
size.initialize.apply(size, args);
|
||||
return size;
|
||||
}
|
||||
},
|
||||
min: function(Size1, Size2) {
|
||||
return new Size(
|
||||
Math.min(Size1.width, Size2.width),
|
||||
Math.min(Size1.height, Size2.height));
|
||||
},
|
||||
|
||||
max: function(Size1, Size2) {
|
||||
return new Size(
|
||||
Math.max(Size1.width, Size2.width),
|
||||
Math.max(Size1.height, Size2.height));
|
||||
},
|
||||
|
||||
random: function() {
|
||||
return new Size(Math.random(), Math.random());
|
||||
}
|
||||
}
|
||||
});
|
39
test/index.html
Normal file
39
test/index.html
Normal file
|
@ -0,0 +1,39 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>QUnit Test Suite</title>
|
||||
<link rel="stylesheet" href="qunit/qunit.css" type="text/css" media="screen">
|
||||
<!-- Libraries -->
|
||||
<script type="text/javascript" src="../src/Bootstrap.js"></script>
|
||||
<script type="text/javascript" src="../src/Item.js"></script>
|
||||
<script type="text/javascript" src="../src/PathItem.js"></script>
|
||||
<script type="text/javascript" src="../src/Point.js"></script>
|
||||
<script type="text/javascript" src="../src/Rectangle.js"></script>
|
||||
<script type="text/javascript" src="../src/Size.js"></script>
|
||||
<script type="text/javascript" src="../src/Segment.js"></script>
|
||||
<script type="text/javascript" src="../src/PathItem.js"></script>
|
||||
<script type="text/javascript" src="../src/Path.js"></script>
|
||||
<script type="text/javascript" src="../src/SegmentList.js"></script>
|
||||
<script type="text/javascript" src="../src/Doc.js"></script>
|
||||
<script type="text/javascript" src="qunit/qunit.js"></script>
|
||||
|
||||
<!-- Test Helpers -->
|
||||
<script type="text/javascript" src="test_functions.js"></script>
|
||||
|
||||
<!-- Tests -->
|
||||
<script type="text/javascript" src="tests_Point.js"></script>
|
||||
<script type="text/javascript" src="tests_Size.js"></script>
|
||||
<script type="text/javascript" src="tests_Rectangle.js"></script>
|
||||
<script type="text/javascript" src="tests_Segment.js"></script>
|
||||
<script type="text/javascript" src="tests_Path_Shapes.js"></script>
|
||||
<script type="text/javascript" src="tests_Path_Drawing_Commands.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<h1 id="qunit-header">QUnit Test Suite</h1>
|
||||
<h2 id="qunit-banner"></h2>
|
||||
<div id="qunit-testrunner-toolbar"></div>
|
||||
<h2 id="qunit-userAgent"></h2>
|
||||
<ol id="qunit-tests"></ol>
|
||||
<div id="qunit-fixture">test markup</div>
|
||||
</body>
|
||||
</html>
|
197
test/qunit/qunit.css
Normal file
197
test/qunit/qunit.css
Normal file
|
@ -0,0 +1,197 @@
|
|||
/** Font Family and Sizes */
|
||||
|
||||
#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
|
||||
font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial;
|
||||
}
|
||||
|
||||
#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
|
||||
#qunit-tests { font-size: smaller; }
|
||||
|
||||
|
||||
/** Resets */
|
||||
|
||||
#qunit-tests, #qunit-tests ol, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
|
||||
/** Header */
|
||||
|
||||
#qunit-header {
|
||||
padding: 0.5em 0 0.5em 1em;
|
||||
|
||||
color: #8699a4;
|
||||
background-color: #0d3349;
|
||||
|
||||
font-size: 1.5em;
|
||||
line-height: 1em;
|
||||
font-weight: normal;
|
||||
|
||||
border-radius: 15px 15px 0 0;
|
||||
-moz-border-radius: 15px 15px 0 0;
|
||||
-webkit-border-top-right-radius: 15px;
|
||||
-webkit-border-top-left-radius: 15px;
|
||||
}
|
||||
|
||||
#qunit-header a {
|
||||
text-decoration: none;
|
||||
color: #c2ccd1;
|
||||
}
|
||||
|
||||
#qunit-header a:hover,
|
||||
#qunit-header a:focus {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
#qunit-banner {
|
||||
height: 5px;
|
||||
}
|
||||
|
||||
#qunit-testrunner-toolbar {
|
||||
padding: 0.5em 0 0.5em 2em;
|
||||
color: #5E740B;
|
||||
background-color: #eee;
|
||||
}
|
||||
|
||||
#qunit-userAgent {
|
||||
padding: 0.5em 0 0.5em 2.5em;
|
||||
background-color: #2b81af;
|
||||
color: #fff;
|
||||
text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
|
||||
}
|
||||
|
||||
|
||||
/** Tests: Pass/Fail */
|
||||
|
||||
#qunit-tests {
|
||||
list-style-position: inside;
|
||||
}
|
||||
|
||||
#qunit-tests li {
|
||||
padding: 0.4em 0.5em 0.4em 2.5em;
|
||||
border-bottom: 1px solid #fff;
|
||||
list-style-position: inside;
|
||||
}
|
||||
|
||||
#qunit-tests li strong {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#qunit-tests ol {
|
||||
margin-top: 0.5em;
|
||||
padding: 0.5em;
|
||||
|
||||
background-color: #fff;
|
||||
|
||||
border-radius: 15px;
|
||||
-moz-border-radius: 15px;
|
||||
-webkit-border-radius: 15px;
|
||||
|
||||
box-shadow: inset 0px 2px 13px #999;
|
||||
-moz-box-shadow: inset 0px 2px 13px #999;
|
||||
-webkit-box-shadow: inset 0px 2px 13px #999;
|
||||
}
|
||||
|
||||
#qunit-tests table {
|
||||
border-collapse: collapse;
|
||||
margin-top: .2em;
|
||||
}
|
||||
|
||||
#qunit-tests th {
|
||||
text-align: right;
|
||||
vertical-align: top;
|
||||
padding: 0 .5em 0 0;
|
||||
}
|
||||
|
||||
#qunit-tests td {
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
#qunit-tests pre {
|
||||
margin: 0;
|
||||
white-space: pre-wrap;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
#qunit-tests del {
|
||||
background-color: #e0f2be;
|
||||
color: #374e0c;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
#qunit-tests ins {
|
||||
background-color: #ffcaca;
|
||||
color: #500;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
/*** Test Counts */
|
||||
|
||||
#qunit-tests b.counts { color: black; }
|
||||
#qunit-tests b.passed { color: #5E740B; }
|
||||
#qunit-tests b.failed { color: #710909; }
|
||||
|
||||
#qunit-tests li li {
|
||||
margin: 0.5em;
|
||||
padding: 0.4em 0.5em 0.4em 0.5em;
|
||||
background-color: #fff;
|
||||
border-bottom: none;
|
||||
list-style-position: inside;
|
||||
}
|
||||
|
||||
/*** Passing Styles */
|
||||
|
||||
#qunit-tests li li.pass {
|
||||
color: #5E740B;
|
||||
background-color: #fff;
|
||||
border-left: 26px solid #C6E746;
|
||||
}
|
||||
|
||||
#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
|
||||
#qunit-tests .pass .test-name { color: #366097; }
|
||||
|
||||
#qunit-tests .pass .test-actual,
|
||||
#qunit-tests .pass .test-expected { color: #999999; }
|
||||
|
||||
#qunit-banner.qunit-pass { background-color: #C6E746; }
|
||||
|
||||
/*** Failing Styles */
|
||||
|
||||
#qunit-tests li li.fail {
|
||||
color: #710909;
|
||||
background-color: #fff;
|
||||
border-left: 26px solid #EE5757;
|
||||
}
|
||||
|
||||
#qunit-tests .fail { color: #000000; background-color: #EE5757; }
|
||||
#qunit-tests .fail .test-name,
|
||||
#qunit-tests .fail .module-name { color: #000000; }
|
||||
|
||||
#qunit-tests .fail .test-actual { color: #EE5757; }
|
||||
#qunit-tests .fail .test-expected { color: green; }
|
||||
|
||||
#qunit-banner.qunit-fail { background-color: #EE5757; }
|
||||
|
||||
|
||||
/** Footer */
|
||||
|
||||
#qunit-testresult {
|
||||
padding: 0.5em 0.5em 0.5em 2.5em;
|
||||
|
||||
color: #2b81af;
|
||||
background-color: #D2E0E6;
|
||||
|
||||
border-radius: 0 0 15px 15px;
|
||||
-moz-border-radius: 0 0 15px 15px;
|
||||
-webkit-border-bottom-right-radius: 15px;
|
||||
-webkit-border-bottom-left-radius: 15px;
|
||||
}
|
||||
|
||||
/** Fixture */
|
||||
|
||||
#qunit-fixture {
|
||||
position: absolute;
|
||||
top: -10000px;
|
||||
left: -10000px;
|
||||
}
|
1415
test/qunit/qunit.js
Normal file
1415
test/qunit/qunit.js
Normal file
File diff suppressed because it is too large
Load diff
22
test/test_functions.js
Normal file
22
test/test_functions.js
Normal file
|
@ -0,0 +1,22 @@
|
|||
function compareSegmentLists(list1, list2) {
|
||||
equal(list1.length, list2.length, 'segment count');
|
||||
if(list1.length == list2.length) {
|
||||
for(var i = 0, l = list1.length; i < l; i++) {
|
||||
compareSegments(list1[i], list2[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function compareSegments(segment1, segment2) {
|
||||
var points = ['point', 'handleIn', 'handleOut'];
|
||||
for(var i = 0; i < 3; i++) {
|
||||
equals(!!segment1[points[i]], !!segment2[points[i]], 'have ' + points[i]);
|
||||
if(segment1[points[i]] && segment2[points[i]])
|
||||
comparePoints(segment1[points[i]], segment2[points[i]], points[i]);
|
||||
}
|
||||
}
|
||||
|
||||
function comparePoints(point1, point2, message) {
|
||||
equals(Math.round(point1.x * 100), Math.round(point2.x * 100), message + ' x');
|
||||
equals(Math.round(point1.y * 100), Math.round(point2.y * 100), message + ' y');
|
||||
}
|
17
test/tests_Path_Drawing_Commands.js
Normal file
17
test/tests_Path_Drawing_Commands.js
Normal file
|
@ -0,0 +1,17 @@
|
|||
module('Path Drawing Commands');
|
||||
|
||||
test('path.lineTo(point);', function() {
|
||||
var path = new Path();
|
||||
path.moveTo([50, 50]);
|
||||
path.lineTo([100, 100]);
|
||||
var expectedSegments = [{ point: { x: 50, y: 50 } }, { point: { x: 100, y: 100 } }];
|
||||
compareSegmentLists(path.segments, expectedSegments);
|
||||
});
|
||||
|
||||
test('path.arcTo(from, through, to);', function() {
|
||||
var path = new Path();
|
||||
path.moveTo([50, 50]);
|
||||
path.arcTo([100, 100], [75, 75]);
|
||||
var expectedSegments = [{ point: { x: 50, y: 50 }, handleOut: { x: 10.11156, y: -10.11156 } }, { point: { x: 88.5299, y: 42.33593 }, handleIn: { x: -13.21138, y: -5.47233 }, handleOut: { x: 13.21138, y: 5.47233 } }, { point: { x: 110.35534, y: 75 }, handleIn: { x: 0, y: -14.2999 } }];
|
||||
compareSegmentLists(path.segments, expectedSegments);
|
||||
});
|
40
test/tests_Path_Shapes.js
Normal file
40
test/tests_Path_Shapes.js
Normal file
|
@ -0,0 +1,40 @@
|
|||
module('Predefined Path Shapes');
|
||||
|
||||
test('new Path.Rectangle([50, 50], [100, 100])', function() {
|
||||
var path = new Path.Rectangle([50, 50], [100, 100]);
|
||||
var expectedSegments = [new Segment(new Point(50, 150)), new Segment(new Point(50, 50)), new Segment(new Point(150, 50)), new Segment(new Point(150, 150))];
|
||||
compareSegmentLists(path.segments, expectedSegments);
|
||||
});
|
||||
|
||||
test('new Path.Circle([100, 100], 50)', function() {
|
||||
var path = new Path.Circle([100, 100], 50);
|
||||
var expectedSegments = [new Segment(new Point(50, 100), new Point(0, 27.6142578125), new Point(0, -27.6142578125)), new Segment(new Point(100, 50), new Point(-27.6142578125, 0), new Point(27.6142578125, 0)), new Segment(new Point(150, 100), new Point(0, -27.6142578125), new Point(0, 27.6142578125)), new Segment(new Point(100, 150), new Point(27.6142578125, 0), new Point(-27.6142578125, 0))];
|
||||
compareSegmentLists(path.segments, expectedSegments);
|
||||
});
|
||||
|
||||
test('new Path.Oval(rect)', function() {
|
||||
var rect = new Rectangle([500, 500], [1000, 750])
|
||||
var path = new Path.Oval(rect);
|
||||
var expectedSegments = [{ point: { x: 500, y: 875 }, handleIn: { x: 0, y: 207.10645 }, handleOut: { x: 0, y: -207.10645 } }, { point: { x: 1000, y: 500 }, handleIn: { x: -276.14258, y: 0 }, handleOut: { x: 276.14258, y: 0 } }, { point: { x: 1500, y: 875 }, handleIn: { x: 0, y: -207.10645 }, handleOut: { x: 0, y: 207.10645 } }, { point: { x: 1000, y: 1250 }, handleIn: { x: 276.14258, y: 0 }, handleOut: { x: -276.14258, y: 0 } }];
|
||||
compareSegmentLists(path.segments, expectedSegments);
|
||||
});
|
||||
|
||||
test('new Path.RoundRectangle(rect, size)', function() {
|
||||
var rect = new Rectangle([50, 50], [200, 100])
|
||||
var path = new Path.RoundRectangle(rect, 20);
|
||||
var expectedSegments = [{ point: { x: 70, y: 150 }, handleOut: { x: -11.0459, y: 0 } }, { point: { x: 50, y: 130 }, handleIn: { x: 0, y: 11.0459 } }, { point: { x: 50, y: 70 }, handleOut: { x: 0, y: -11.0459 } }, { point: { x: 70, y: 50 }, handleIn: { x: -11.0459, y: 0 } }, { point: { x: 230, y: 50 }, handleOut: { x: 11.0459, y: 0 } }, { point: { x: 250, y: 70 }, handleIn: { x: 0, y: -11.0459 } }, { point: { x: 250, y: 130 }, handleOut: { x: 0, y: 11.0459 } }, { point: { x: 230, y: 150 }, handleIn: { x: 11.0459, y: 0 } }];
|
||||
compareSegmentLists(path.segments, expectedSegments);
|
||||
});
|
||||
|
||||
test('new Path.RoundRectangle(rect, size) - too large size', function() {
|
||||
var rect = new Rectangle([50, 50], [200, 100])
|
||||
var path = new Path.RoundRectangle(rect, 200);
|
||||
var expectedSegments = [{ point: { x: 150, y: 150 }, handleOut: { x: -55.22852, y: 0 } }, { point: { x: 50, y: 100 }, handleIn: { x: 0, y: 27.61426 } }, { point: { x: 50, y: 100 }, handleOut: { x: 0, y: -27.61426 } }, { point: { x: 150, y: 50 }, handleIn: { x: -55.22852, y: 0 } }, { point: { x: 150, y: 50 }, handleOut: { x: 55.22852, y: 0 } }, { point: { x: 250, y: 100 }, handleIn: { x: 0, y: -27.61426 } }, { point: { x: 250, y: 100 }, handleOut: { x: 0, y: 27.61426 } }, { point: { x: 150, y: 150 }, handleIn: { x: 55.22852, y: 0 } }];
|
||||
compareSegmentLists(path.segments, expectedSegments);
|
||||
});
|
||||
|
||||
test('new Path.Arc(from, through, to)', function() {
|
||||
var path = new Path.Arc([50, 50], [100, 100], [75, 75]);
|
||||
var expectedSegments = [{ point: { x: 50, y: 50 }, handleOut: { x: 10.11156, y: -10.11156 } }, { point: { x: 88.5299, y: 42.33593 }, handleIn: { x: -13.21138, y: -5.47233 }, handleOut: { x: 13.21138, y: 5.47233 } }, { point: { x: 110.35534, y: 75 }, handleIn: { x: 0, y: -14.2999 } }];
|
||||
compareSegmentLists(path.segments, expectedSegments);
|
||||
});
|
78
test/tests_Point.js
Normal file
78
test/tests_Point.js
Normal file
|
@ -0,0 +1,78 @@
|
|||
module('Point');
|
||||
test('new Point(10, 20)', function(){
|
||||
var point = new Point(10, 20);
|
||||
equals(point.x, 10);
|
||||
equals(point.y, 20);
|
||||
});
|
||||
|
||||
test('new Point([10, 20])', function(){
|
||||
var point = new Point([10, 20]);
|
||||
equals(point.x, 10);
|
||||
equals(point.y, 20);
|
||||
});
|
||||
|
||||
test('new Point({x: 10, y: 20})', function(){
|
||||
var point = new Point({x: 10, y: 20});
|
||||
equals(point.x, 10);
|
||||
equals(point.y, 20);
|
||||
});
|
||||
|
||||
test('new Point(new Size(10, 20))', function(){
|
||||
var point = new Point(new Size(10, 20));
|
||||
equals(point.x, 10);
|
||||
equals(point.y, 20);
|
||||
});
|
||||
|
||||
test('new Point({ width: 10, height: 20})', function(){
|
||||
var point = new Point({width: 10, height: 20});
|
||||
equals(point.x, 10);
|
||||
equals(point.y, 20);
|
||||
});
|
||||
|
||||
module('Point vector operations');
|
||||
|
||||
test('new Point(0, 10).normalize(20)', function(){
|
||||
var point = new Point(0, 10).normalize(20)
|
||||
equals(point.x, 0);
|
||||
equals(point.y, 20);
|
||||
});
|
||||
|
||||
test('new Point(0, 10).setLength(20)', function(){
|
||||
var point = new Point(0, 10);
|
||||
point.setLength(20)
|
||||
equals(point.x, 0);
|
||||
equals(point.y, 20);
|
||||
});
|
||||
|
||||
test('new Point(0, 10).getAngle()', function(){
|
||||
var angle = new Point(0, 10).getAngle();
|
||||
equals(angle, 90);
|
||||
});
|
||||
|
||||
test('new Point(0, 10).getAngle([10, 10])', function(){
|
||||
var angle = new Point(0, 10).getAngle([10, 10]);
|
||||
equals(Math.round(angle), 45);
|
||||
});
|
||||
|
||||
test('new Point(100, 50).rotate(90)', function(){
|
||||
var point = new Point(100, 50).rotate(90);
|
||||
equals(Math.round(point.x), -50);
|
||||
equals(Math.round(point.y), 100);
|
||||
});
|
||||
|
||||
test('setAngle(20)', function(){
|
||||
var point = new Point(10, 20);
|
||||
point.setAngle(92);
|
||||
equals(point.getAngle(), 92);
|
||||
});
|
||||
|
||||
test('setAngle(20)', function(){
|
||||
var point = new Point(10, 20);
|
||||
point.setAngle(92);
|
||||
equals(point.getAngle(), 92);
|
||||
});
|
||||
|
||||
test('new Point().getDirectedAngle(new Point(10, 10))', function() {
|
||||
var angle = new Point().getDirectedAngle(new Point(10, 10));
|
||||
equals(angle, -45);
|
||||
});
|
231
test/tests_Rectangle.js
Normal file
231
test/tests_Rectangle.js
Normal file
|
@ -0,0 +1,231 @@
|
|||
module('Rectangle');
|
||||
test('new Rectangle(new Point(10, 20), new Size(30, 40));', function(){
|
||||
var rect = new Rectangle(new Point(10, 20), new Size(30, 40));
|
||||
equals(rect.x, 10);
|
||||
equals(rect.y, 20);
|
||||
equals(rect.width, 30);
|
||||
equals(rect.height, 40);
|
||||
});
|
||||
|
||||
test('new Rectangle([10, 20], [30, 40]);', function(){
|
||||
var rect = new Rectangle([10, 20], [30, 40]);
|
||||
equals(rect.x, 10);
|
||||
equals(rect.y, 20);
|
||||
equals(rect.width, 30);
|
||||
equals(rect.height, 40);
|
||||
});
|
||||
|
||||
test('new Rectangle(new Point(10, 20), new Point(30, 40));', function(){
|
||||
var rect = new Rectangle(new Point(10, 20), new Point(30, 40));
|
||||
equals(rect.x, 10);
|
||||
equals(rect.y, 20);
|
||||
equals(rect.width, 20);
|
||||
equals(rect.height, 20);
|
||||
});
|
||||
|
||||
test('new Rectangle(10, 20, 30, 40);', function(){
|
||||
var rect = new Rectangle(10, 20, 30, 40);
|
||||
equals(rect.x, 10);
|
||||
equals(rect.y, 20);
|
||||
equals(rect.width, 30);
|
||||
equals(rect.height, 40);
|
||||
});
|
||||
|
||||
test('new Rectangle({x: 10, y: 20, width: 30, height: 40});', function(){
|
||||
var rect = new Rectangle({x: 10, y: 20, width: 30, height: 40});
|
||||
equals(rect.x, 10);
|
||||
equals(rect.y, 20);
|
||||
equals(rect.width, 30);
|
||||
equals(rect.height, 40);
|
||||
});
|
||||
|
||||
test('getSize()', function(){
|
||||
var rect = new Rectangle(10, 10, 20, 30);
|
||||
equals(rect.getSize().equals([20, 30]), true);
|
||||
});
|
||||
|
||||
test('setSize()', function(){
|
||||
var rect = new Rectangle(10, 10, 20, 20);
|
||||
rect.setSize(new Size(30, 30))
|
||||
equals(rect.width, 30);
|
||||
equals(rect.height, 30);
|
||||
});
|
||||
|
||||
test('getTopLeft()', function(){
|
||||
var rect = new Rectangle(10, 10, 20, 20);
|
||||
var point = rect.getTopLeft();
|
||||
equals(point.x, 10);
|
||||
equals(point.y, 10);
|
||||
});
|
||||
|
||||
test('setTopLeft()', function(){
|
||||
var rect = new Rectangle(10, 10, 20, 20);
|
||||
rect.setTopLeft(10, 15);
|
||||
var point = rect.getTopLeft();
|
||||
equals(point.x, 10);
|
||||
equals(point.y, 15);
|
||||
});
|
||||
|
||||
test('getTopRight()', function(){
|
||||
var rect = new Rectangle(10, 10, 20, 20);
|
||||
var point = rect.getTopRight();
|
||||
equals(point.x, 30);
|
||||
equals(point.y, 10);
|
||||
});
|
||||
|
||||
test('setTopRight()', function(){
|
||||
var rect = new Rectangle(10, 10, 20, 20);
|
||||
rect.setTopRight(10, 15);
|
||||
var point = rect.getTopRight();
|
||||
equals(point.x, 10);
|
||||
equals(point.y, 15);
|
||||
});
|
||||
|
||||
test('getBottomLeft()', function(){
|
||||
var rect = new Rectangle(10, 10, 20, 20);
|
||||
var point = rect.getBottomLeft();
|
||||
equals(point.x, 10);
|
||||
equals(point.y, 30);
|
||||
});
|
||||
|
||||
test('setBottomLeft()', function(){
|
||||
var rect = new Rectangle(10, 10, 20, 20);
|
||||
rect.setBottomLeft(10, 15);
|
||||
var point = rect.getBottomLeft();
|
||||
equals(point.x, 10);
|
||||
equals(point.y, 15);
|
||||
});
|
||||
|
||||
test('getBottomRight()', function(){
|
||||
var rect = new Rectangle(10, 10, 20, 20);
|
||||
var point = rect.getBottomRight();
|
||||
equals(point.x, 30);
|
||||
equals(point.y, 30);
|
||||
});
|
||||
|
||||
test('setBottomRight()', function(){
|
||||
var rect = new Rectangle(10, 10, 20, 20);
|
||||
rect.setBottomRight(10, 15);
|
||||
var point = rect.getBottomRight();
|
||||
equals(point.x, 10);
|
||||
equals(point.y, 15);
|
||||
});
|
||||
|
||||
test('getBottomCenter()', function(){
|
||||
var rect = new Rectangle(10, 10, 20, 20);
|
||||
var point = rect.getBottomCenter();
|
||||
equals(point.x, 20);
|
||||
equals(point.y, 30);
|
||||
});
|
||||
|
||||
test('setBottomCenter()', function(){
|
||||
var rect = new Rectangle(10, 10, 20, 20);
|
||||
rect.setBottomCenter(10, 15);
|
||||
var point = rect.getBottomCenter();
|
||||
equals(point.x, 10);
|
||||
equals(point.y, 15);
|
||||
});
|
||||
|
||||
test('getTopCenter()', function(){
|
||||
var rect = new Rectangle(10, 10, 20, 20);
|
||||
var point = rect.getTopCenter();
|
||||
equals(point.x, 20);
|
||||
equals(point.y, 10);
|
||||
});
|
||||
|
||||
test('setTopCenter()', function(){
|
||||
var rect = new Rectangle(10, 10, 20, 20);
|
||||
rect.setTopCenter(10, 15);
|
||||
var point = rect.getTopCenter();
|
||||
equals(point.x, 10);
|
||||
equals(point.y, 15);
|
||||
});
|
||||
|
||||
test('getLeftCenter()', function(){
|
||||
var rect = new Rectangle(10, 10, 20, 20);
|
||||
var point = rect.getLeftCenter();
|
||||
equals(point.x, 10);
|
||||
equals(point.y, 20);
|
||||
});
|
||||
|
||||
test('setLeftCenter()', function(){
|
||||
var rect = new Rectangle(10, 10, 20, 20);
|
||||
rect.setLeftCenter(10, 15);
|
||||
var point = rect.getLeftCenter();
|
||||
equals(point.x, 10);
|
||||
equals(point.y, 15);
|
||||
});
|
||||
|
||||
test('getRightCenter()', function(){
|
||||
var rect = new Rectangle(10, 10, 20, 20);
|
||||
var point = rect.getRightCenter();
|
||||
equals(point.x, 30);
|
||||
equals(point.y, 20);
|
||||
});
|
||||
|
||||
test('setRightCenter()', function(){
|
||||
var rect = new Rectangle(10, 10, 20, 20);
|
||||
rect.setRightCenter(10, 15);
|
||||
var point = rect.getRightCenter();
|
||||
equals(point.x, 10);
|
||||
equals(point.y, 15);
|
||||
});
|
||||
|
||||
test('intersects(rect)', function() {
|
||||
var rect1 = new Rectangle({ x: 160, y: 270, width: 20, height: 20 });
|
||||
var rect2 = { x: 195, y: 301, width: 19, height: 19 };
|
||||
equals(rect1.intersects(rect2), false);
|
||||
|
||||
rect1 = new Rectangle({ x: 160, y: 270, width: 20, height: 20 });
|
||||
rect2 = { x: 170.5, y: 280.5, width: 19, height: 19 };
|
||||
equals(rect1.intersects(rect2), true);
|
||||
});
|
||||
|
||||
test('contains(rect)', function() {
|
||||
var rect1 = new Rectangle({ x: 160, y: 270, width: 20, height: 20 });
|
||||
var rect2 = { x: 195, y: 301, width: 19, height: 19 };
|
||||
equals(rect1.contains(rect2), false);
|
||||
|
||||
rect1 = new Rectangle({ x: 160, y: 270, width: 20, height: 20 });
|
||||
rect2 = new Rectangle({ x: 170.5, y: 280.5, width: 19, height: 19 });
|
||||
equals(rect1.contains(rect2), false);
|
||||
|
||||
rect1 = new Rectangle({ x: 299, y: 161, width: 137, height: 129 });
|
||||
rect2 = new Rectangle({ x: 340, y: 197, width: 61, height: 61 });
|
||||
equals(rect1.contains(rect2), true);
|
||||
equals(rect2.contains(rect1), false);
|
||||
});
|
||||
|
||||
test('contains(point)', function() {
|
||||
var rect = new Rectangle({ x: 160, y: 270, width: 20, height: 20 });
|
||||
var point = new Point(166, 280);
|
||||
equals(rect.contains(point), true);
|
||||
|
||||
var point = new Point(30, 30);
|
||||
equals(rect.contains(point), false);
|
||||
});
|
||||
|
||||
test('intersect(rect)', function() {
|
||||
var rect1 = new Rectangle({ x: 160, y: 270, width: 20, height: 20 });
|
||||
var rect2 = { x: 170.5, y: 280.5, width: 19, height: 19 };
|
||||
var intersected = rect1.intersect(rect2);
|
||||
equals(intersected.equals({ x: 170.5, y: 280.5, width: 9.5, height: 9.5 }), true);
|
||||
});
|
||||
|
||||
test('unite(rect)', function() {
|
||||
var rect1 = new Rectangle({ x: 160, y: 270, width: 20, height: 20 });
|
||||
var rect2 = { x: 170.5, y: 280.5, width: 19, height: 19 };
|
||||
var united = rect1.unite(rect2);
|
||||
equals(united.equals({ x: 160, y: 270, width: 29.5, height: 29.5 }), true);
|
||||
});
|
||||
|
||||
test('include(point)', function() {
|
||||
var rect1 = new Rectangle({ x: 95, y: 151, width: 20, height: 20 });
|
||||
var included = rect1.include([50, 50]);
|
||||
equals(included.equals({ x: 50, y: 50, width: 65, height: 121 }), true);
|
||||
});
|
||||
|
||||
test('toString()', function() {
|
||||
var string = new Rectangle(10, 20, 30, 40).toString();
|
||||
equals(string, '{ x: 10, y: 20, width: 30, height: 40 }');
|
||||
});
|
44
test/tests_Segment.js
Normal file
44
test/tests_Segment.js
Normal file
|
@ -0,0 +1,44 @@
|
|||
module('Segment');
|
||||
test('new Segment(point)', function(){
|
||||
var segment = new Segment(new Point(10, 10));
|
||||
var expected = { point: { x: 10, y: 10 } };
|
||||
compareSegments(segment, expected);
|
||||
});
|
||||
|
||||
test('new Segment(x, y)', function(){
|
||||
var segment = new Segment(10, 10);
|
||||
var expected = { point: { x: 10, y: 10 } };
|
||||
compareSegments(segment, expected);
|
||||
});
|
||||
|
||||
test('new Segment(object)', function(){
|
||||
var segment = new Segment({ point: { x: 10, y: 10 }, handleIn: { x: 5, y: 5 }, handleOut: { x: 15, y: 15 } });
|
||||
var expected = { point: { x: 10, y: 10 }, handleIn: { x: 5, y: 5 }, handleOut: { x: 15, y: 15 } };
|
||||
compareSegments(segment, expected);
|
||||
});
|
||||
|
||||
test('new Segment(point, handleIn, handleOut)', function(){
|
||||
var segment = new Segment(new Point(10, 10), new Point(5, 5), new Point(15, 15));
|
||||
var expected = { point: { x: 10, y: 10 }, handleIn: { x: 5, y: 5 }, handleOut: { x: 15, y: 15 } };
|
||||
compareSegments(segment, expected);
|
||||
});
|
||||
|
||||
test('new Segment(x, y, inX, inY, outX, outY)', function(){
|
||||
var segment = new Segment(10, 10, 5, 5, 15, 15);
|
||||
var expected = { point: { x: 10, y: 10 }, handleIn: { x: 5, y: 5 }, handleOut: { x: 15, y: 15 } };
|
||||
compareSegments(segment, expected);
|
||||
});
|
||||
|
||||
test('segment.reverse()', function(){
|
||||
var segment = new Segment(new Point(10, 10), new Point(5, 5), new Point(15, 15));
|
||||
segment = segment.reverse();
|
||||
var expected = { point: { x: 10, y: 10 }, handleIn: { x: 15, y: 15 }, handleOut: { x: 5, y: 5 } };
|
||||
compareSegments(segment, expected);
|
||||
});
|
||||
|
||||
test('segment.clone()', function(){
|
||||
var segment = new Segment(new Point(10, 10), new Point(5, 5), new Point(15, 15));
|
||||
var clone = segment.clone();
|
||||
equals(segment == clone, false);
|
||||
compareSegments(segment, clone);
|
||||
});
|
30
test/tests_Size.js
Normal file
30
test/tests_Size.js
Normal file
|
@ -0,0 +1,30 @@
|
|||
module('Size');
|
||||
test('new Size(10, 20)', function(){
|
||||
var size = new Size(10, 20);
|
||||
equals(size.width, 10);
|
||||
equals(size.height, 20);
|
||||
});
|
||||
|
||||
test('new Size([10, 20])', function(){
|
||||
var size = new Size([10, 20]);
|
||||
equals(size.width, 10);
|
||||
equals(size.height, 20);
|
||||
});
|
||||
|
||||
test('new Size({width: 10, height: 20})', function(){
|
||||
var size = new Size({width: 10, height: 20});
|
||||
equals(size.width, 10);
|
||||
equals(size.height, 20);
|
||||
});
|
||||
|
||||
test('new Size(new Point(10, 20))', function(){
|
||||
var size = new Size(new Point(10, 20));
|
||||
equals(size.width, 10);
|
||||
equals(size.height, 20);
|
||||
});
|
||||
|
||||
test('new Size({ x: 10, y: 20})', function(){
|
||||
var size = new Size({x: 10, y: 20});
|
||||
equals(size.width, 10);
|
||||
equals(size.height, 20);
|
||||
});
|
Loading…
Reference in a new issue