614 lines
20 KiB
JavaScript
614 lines
20 KiB
JavaScript
describe("Element methods", function () {
|
|
var s;
|
|
beforeEach(function () {
|
|
s = Savage(100, 100);
|
|
});
|
|
afterEach(function () {
|
|
s.remove();
|
|
});
|
|
|
|
/*
|
|
DOM manipulation:
|
|
- add/append
|
|
- prepend
|
|
- after
|
|
- insertAfter
|
|
- before
|
|
- insertBefore
|
|
- clone
|
|
- parent
|
|
- remove
|
|
*/
|
|
it("Element.add (for Element)", function () {
|
|
var rect = s.rect(10, 20, 30, 40);
|
|
var result = s.add(rect);
|
|
expect(rect.node.parentNode).to.be(s.node);
|
|
expect(s.node.lastChild).to.be(rect.node);
|
|
expect(result).to.be(s);
|
|
});
|
|
it("Element.add (for Set)", function () {
|
|
var rect1 = s.rect(10, 20, 30, 40);
|
|
var rect2 = s.rect(10, 20, 30, 40);
|
|
var set = Savage.set(rect1, rect2);
|
|
var result = s.add(set);
|
|
expect(rect1.node.parentNode).to.be(s.node);
|
|
expect(rect2.node.parentNode).to.be(s.node);
|
|
expect(result).to.be(s);
|
|
});
|
|
it("Element.append (for Element)", function () {
|
|
var rect = s.rect(10, 20, 30, 40);
|
|
var result = s.append(rect);
|
|
expect(rect.node.parentNode).to.be(s.node);
|
|
expect(s.node.lastChild).to.be(rect.node);
|
|
expect(result).to.be(s);
|
|
});
|
|
it("Element.append (for Set)", function () {
|
|
var rect1 = s.rect(10, 20, 30, 40);
|
|
var rect2 = s.rect(10, 20, 30, 40);
|
|
var set = Savage.set(rect1, rect2);
|
|
var result = s.append(set);
|
|
expect(rect1.node.parentNode).to.be(s.node);
|
|
expect(rect2.node.parentNode).to.be(s.node);
|
|
expect(result).to.be(s);
|
|
});
|
|
it("Element.after", function() {
|
|
var circle = s.circle(10, 20, 30);
|
|
var rect = s.rect(10, 20, 30, 40);
|
|
var result = circle.after(rect);
|
|
expect(circle.node.nextSibling).to.be(rect.node);
|
|
expect(result).to.be(circle);
|
|
});
|
|
it("Element.prepend", function() {
|
|
var rect = s.rect(10, 20, 30, 40);
|
|
var circle = s.circle(10, 20, 30);
|
|
var group = s.group();
|
|
s.append(group);
|
|
var result = group.prepend(rect);
|
|
expect(group.node.firstChild).to.be(rect.node);
|
|
expect(result).to.be(group);
|
|
result = group.prepend(circle);
|
|
expect(group.node.firstChild).to.be(circle.node);
|
|
expect(result).to.be(group);
|
|
});
|
|
it("Element.insertAfter", function() {
|
|
var circle = s.circle(10, 20, 30);
|
|
var rect = s.rect(10, 20, 30, 40);
|
|
var result = rect.insertAfter(circle);
|
|
expect(circle.node.nextSibling).to.be(rect.node);
|
|
expect(result).to.be(rect);
|
|
});
|
|
it("Element.before", function() {
|
|
var circle = s.circle(10, 20, 30);
|
|
var rect = s.rect(10, 20, 30, 40);
|
|
var result = circle.before(rect);
|
|
expect(circle.node.previousSibling).to.be(rect.node);
|
|
expect(result).to.be(circle);
|
|
});
|
|
it("Element.insertBefore", function() {
|
|
var circle = s.circle(10, 20, 30);
|
|
var rect = s.rect(10, 20, 30, 40);
|
|
var result = rect.insertBefore(circle);
|
|
expect(circle.node.previousSibling).to.be(rect.node);
|
|
expect(result).to.be(rect);
|
|
});
|
|
it("Element.clone", function() {
|
|
var circle = s.circle(10, 20, 30);
|
|
s.append(circle);
|
|
var clone = circle.clone();
|
|
expect(circle.node).not.to.be(clone.node);
|
|
// NOTE: These assume a cloneNode copy, not a <use> element
|
|
expect(clone.node.getAttribute("cx")).to.be("10");
|
|
expect(clone.node.getAttribute("cy")).to.be("20");
|
|
expect(clone.node.getAttribute("r")).to.be("30");
|
|
});
|
|
it("Element.parent", function() {
|
|
var circle = s.circle(10, 20, 30);
|
|
s.append(circle);
|
|
var parent = circle.parent();
|
|
expect(parent.node).to.be(s.node);
|
|
});
|
|
it("Element.remove", function() {
|
|
var rect = s.rect(10, 20, 30, 40);
|
|
expect(rect.node.parentNode).to.be(s.node);
|
|
var result = rect.remove();
|
|
expect(rect.node.parentNode).to.be(null);
|
|
// NOTE: docs say it does not return anything, but perhaps it should?
|
|
// expect(result).to.be(rect);
|
|
});
|
|
|
|
/*
|
|
Set/get data:
|
|
Element.attr()
|
|
Element.data()
|
|
Element.removeData()
|
|
Element.asPX()
|
|
Element.getBBox()
|
|
Element.getPointAtLength()
|
|
Element.getSubpath()
|
|
Element.getTotalLength()
|
|
*/
|
|
|
|
it("Element.attr - get", function() {
|
|
var circle = s.circle(10, 20, 30);
|
|
var r = circle.attr("r");
|
|
expect(r).to.be("30");
|
|
});
|
|
it("Element.attr - set", function() {
|
|
var circle = s.circle(10, 20, 30);
|
|
circle.attr({
|
|
cx: 1,
|
|
cy: 2,
|
|
r: 3
|
|
});
|
|
var cx = circle.node.getAttribute("cx");
|
|
var cy = circle.node.getAttribute("cy");
|
|
var r = circle.node.getAttribute("r");
|
|
expect(cx).to.be("1");
|
|
expect(cy).to.be("2");
|
|
expect(r).to.be("3");
|
|
});
|
|
it("Element.data", function() {
|
|
var circle = s.circle(10, 20, 30);
|
|
circle.data("foo", "bar");
|
|
var data = circle.data("foo");
|
|
expect(data).to.be("bar");
|
|
var myObject = {};
|
|
circle.data("my-object", myObject);
|
|
data = circle.data("my-object");
|
|
expect(data).to.be(myObject);
|
|
});
|
|
it("Element.removeData", function() {
|
|
var circle = s.circle(10, 20, 30);
|
|
var myObject = {};
|
|
circle.data("my-object", myObject);
|
|
var data = circle.data("my-object");
|
|
expect(data).to.be(myObject);
|
|
circle.removeData("my-object");
|
|
data = circle.data("my-object");
|
|
expect(data).to.be(undefined);
|
|
});
|
|
it("Element.asPX - from %", function() {
|
|
s.attr({width: "200"}); // NOTE: This is only working with "200" as string, fails as number
|
|
var rect = s.rect(0, 0, '100%', 10);
|
|
var widthAsPx = rect.asPX("width");
|
|
expect(widthAsPx).to.be(200);
|
|
});
|
|
it("Element.asPX - from em", function() {
|
|
var rect = s.rect(0, 0, 10, '10em');
|
|
var heightAsPx = rect.asPX("height");
|
|
expect(heightAsPx).to.be(160); // assumes 1em = 16px, is this safe?
|
|
});
|
|
it("Element.getBBox", function() {
|
|
var rect = s.rect(10, 20, 30, 40);
|
|
var bbox = rect.getBBox();
|
|
|
|
expect(bbox.x).to.eql(10);
|
|
expect(bbox.y).to.eql(20);
|
|
expect(bbox.w).to.eql(30);
|
|
expect(bbox.width).to.eql(30);
|
|
expect(bbox.h).to.eql(40);
|
|
expect(bbox.height).to.eql(40);
|
|
expect(bbox.x2).to.eql(10 + 30);
|
|
expect(bbox.cx).to.eql(10 + 30 / 2);
|
|
expect(bbox.cy).to.eql(20 + 40 / 2);
|
|
expect(bbox.y2).to.eql(20 + 40);
|
|
});
|
|
|
|
it("Element.getPointAtLength", function() {
|
|
var path = s.path("M0,0 100,0");
|
|
expect(path.getPointAtLength(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("Element.getSubpath", function() {
|
|
var path = s.path("M0,0 100,0");
|
|
expect(path.getSubpath(10, 90)).to.be("M9.995,0C29.153,0,70.839,0,90,0");
|
|
});
|
|
it("Element.getTotalLength", function() {
|
|
var path = s.path("M0,0 100,0");
|
|
expect(+path.getTotalLength("M0,0 100,0").toFixed(2)).to.be(100);
|
|
});
|
|
|
|
/*
|
|
Misc:
|
|
|
|
Element.select()
|
|
Element.selectAll()
|
|
Element.animate()
|
|
Element.inAnim()
|
|
Element.stop()
|
|
Element.marker()
|
|
Element.pattern()
|
|
Element.use()
|
|
Element.transform()
|
|
|
|
*/
|
|
|
|
it("Element.select", function() {
|
|
var group1 = s.group();
|
|
var group2 = s.group();
|
|
var group3 = s.group();
|
|
var circle1 = s.circle(10, 20, 30).attr({
|
|
'class': 'circle-one'
|
|
});
|
|
var circle2 = s.circle(5, 10, 25).attr({
|
|
'class': 'circle-two'
|
|
});
|
|
group1.add(group2);
|
|
group2.add(group3);
|
|
group2.add(circle1);
|
|
group3.add(circle2);
|
|
var c1 = group1.select('.circle-one');
|
|
expect(circle1).to.be(c1);
|
|
var c2 = group1.select('.circle-two');
|
|
expect(circle2).to.be(c2);
|
|
});
|
|
it("Element.selectAll", function() {
|
|
var group1 = s.group();
|
|
var group2 = s.group();
|
|
var group3 = s.group();
|
|
var circle1 = s.circle(10, 20, 30).attr({
|
|
'class': 'circle-one'
|
|
});
|
|
var circle2 = s.circle(5, 10, 25).attr({
|
|
'class': 'circle-two'
|
|
});
|
|
group1.add(group2);
|
|
group2.add(group3);
|
|
group2.add(circle1);
|
|
group3.add(circle2);
|
|
var circles = group1.selectAll('circle');
|
|
expect(circles.length).to.be(2);
|
|
expect(circles).to.contain(circle1);
|
|
expect(circles).to.contain(circle2);
|
|
});
|
|
it("Element.animate", function(done) {
|
|
var circle = s.circle(10, 20, 30);
|
|
var result = circle.animate({r: 50}, 10);
|
|
setTimeout(function() {
|
|
var r = circle.attr("r");
|
|
expect(r).to.be("50");
|
|
done();
|
|
}, 50);
|
|
expect(result).to.be(circle);
|
|
});
|
|
it("Element.animate - with callback", function(done) {
|
|
var circle = s.circle(10, 20, 30);
|
|
var result = circle.animate({r: 50}, 10, function() {
|
|
var r = circle.attr("r");
|
|
expect(r).to.be("50");
|
|
done();
|
|
});
|
|
expect(result).to.be(circle);
|
|
});
|
|
it("Element.animate - with easing", function(done) {
|
|
var circle = s.circle(10, 20, 30);
|
|
var result = circle.animate({r: 50}, 10, mina.easein);
|
|
setTimeout(function() {
|
|
var r = circle.attr("r");
|
|
expect(r).to.be("50");
|
|
done();
|
|
}, 50);
|
|
expect(result).to.be(circle);
|
|
});
|
|
it("Element.animate - with callback & easing", function(done) {
|
|
var circle = s.circle(10, 20, 30);
|
|
var result = circle.animate({r: 50}, 10, mina.easeout, function() {
|
|
var r = circle.attr("r");
|
|
expect(r).to.be("50");
|
|
done();
|
|
});
|
|
expect(result).to.be(circle);
|
|
});
|
|
it("Element.inAnim", function(done) {
|
|
var circle = s.circle(10, 20, 30);
|
|
circle.animate({r: 50}, 100);
|
|
circle.animate({cx: 100}, 100);
|
|
setTimeout(function() {
|
|
var inAnimArr = circle.inAnim();
|
|
expect(inAnimArr).to.be.an('array');
|
|
expect(inAnimArr.length).to.be(2);
|
|
expect(inAnimArr[0].anim).to.be.an('object');
|
|
expect(inAnimArr[0].curStatus).to.be.a('number');
|
|
expect(inAnimArr[0].curStatus).to.be.within(0.01, 0.99);
|
|
expect(inAnimArr[0].status).to.be.a('function');
|
|
expect(inAnimArr[0].stop).to.be.a('function');
|
|
done();
|
|
}, 50);
|
|
});
|
|
it("Element.stop", function(done) {
|
|
var circle = s.circle(10, 20, 30);
|
|
circle.animate({r: 50}, 100);
|
|
setTimeout(function() {
|
|
var inAnimArr = circle.inAnim();
|
|
expect(inAnimArr.length).to.be(1);
|
|
var result = circle.stop();
|
|
inAnimArr = circle.inAnim();
|
|
expect(inAnimArr.length).to.be(0);
|
|
var r = circle.attr("r");
|
|
expect(r).to.be.lessThan(50);
|
|
expect(result).to.be(circle);
|
|
done();
|
|
}, 50);
|
|
});
|
|
it("Element.marker", function() {
|
|
var line = s.line(0, 0, 10, 10);
|
|
var marker = line.marker(0, 0, 5, 5, 0, 0);
|
|
expect(marker.node.nodeName).to.be('marker');
|
|
});
|
|
it("Element.pattern", function() {
|
|
var circle = s.circle(10, 20, 30);
|
|
var pattern = circle.pattern(0, 0, 50, 50);
|
|
expect(pattern.node.nodeName).to.be('pattern');
|
|
});
|
|
it("Element.transform", function() {
|
|
var circle = s.circle(10, 20, 30);
|
|
var result = circle.transform("translate(10,10)");
|
|
var matrix = {
|
|
a: 1, b: 0, c: 0, d: 1, e: 10, f: 10
|
|
};
|
|
var transform = circle.transform();
|
|
expect(transform.string).to.be.a('string');
|
|
expect(transform.global).to.be.a('string');
|
|
expect(transform.globalMatrix).to.be.an('object');
|
|
expect(transform.globalMatrix).to.eql(matrix);
|
|
expect(transform.local).to.be.a('string');
|
|
expect(transform.localMatrix).to.be.an('object');
|
|
expect(transform.localMatrix).to.eql(matrix);
|
|
circle.transform("rotate(90)");
|
|
transform = circle.transform();
|
|
expect(transform.local).to.be("r90,0,0");
|
|
expect(result).to.be(circle);
|
|
});
|
|
it("Element.use", function() {
|
|
var circle = s.circle(10, 20, 30);
|
|
var use = circle.use();
|
|
expect(use.node.nodeName).to.be('use');
|
|
});
|
|
|
|
|
|
/*
|
|
Event binding & unbinding:
|
|
|
|
Element.click()
|
|
Element.dblclick()
|
|
Element.mousedown()
|
|
Element.mousemove()
|
|
Element.mouseout()
|
|
Element.mouseover()
|
|
Element.mouseup()
|
|
Element.touchcancel()
|
|
Element.touchend()
|
|
Element.touchmove()
|
|
Element.touchstart()
|
|
Element.unclick()
|
|
Element.undblclick()
|
|
Element.unmousedown()
|
|
Element.unmousemove()
|
|
Element.unmouseout()
|
|
Element.unmouseover()
|
|
Element.unmouseup()
|
|
Element.untouchcancel()
|
|
Element.untouchend()
|
|
Element.untouchmove()
|
|
Element.untouchstart()
|
|
|
|
Element.drag()
|
|
Element.undrag()
|
|
Element.hover()
|
|
Element.unhover()
|
|
|
|
TODO:
|
|
Element.onDragOver()
|
|
*/
|
|
|
|
// Helper function to simulate event triggering
|
|
var triggerEvent = function(savageEl, eventType) {
|
|
var event = document.createEvent("HTMLEvents");
|
|
event.initEvent(eventType, true, true);
|
|
savageEl.node.dispatchEvent(event);
|
|
};
|
|
|
|
// Generate tests for all standard DOM events
|
|
(function() {
|
|
var elementEvents = [
|
|
"click",
|
|
"dblclick",
|
|
"mousedown",
|
|
"mousemove",
|
|
"mouseout",
|
|
"mouseover",
|
|
"mouseup",
|
|
"touchcancel",
|
|
"touchend",
|
|
"touchmove",
|
|
"touchstart"
|
|
];
|
|
|
|
var makeEventTest = function(eventName) {
|
|
return function() {
|
|
// Add event, trigger event, remove event, trigger again
|
|
var circle = s.circle(10, 20, 30);
|
|
var n = 0;
|
|
var fn = function() {
|
|
n++;
|
|
};
|
|
var result1 = circle[eventName](fn);
|
|
expect(n).to.be(0);
|
|
triggerEvent(circle, eventName);
|
|
expect(n).to.be(1);
|
|
var result2 = circle["un" + eventName](fn);
|
|
triggerEvent(circle, eventName);
|
|
expect(n).to.be(1);
|
|
expect(result1).to.be(circle);
|
|
expect(result2).to.be(circle);
|
|
};
|
|
}
|
|
|
|
for (var i = 0; i < elementEvents.length; i++) {
|
|
var eventName = elementEvents[i];
|
|
var testName = "Element." + eventName + ", Element.un" + eventName;
|
|
var testFunc = makeEventTest(eventName);
|
|
it(testName, testFunc);
|
|
}
|
|
}());
|
|
it("Element.drag, Element.undrag - no contexts", function() {
|
|
var circle = s.circle(10, 20, 30);
|
|
var moved = 0;
|
|
var started = 0;
|
|
var ended = 0;
|
|
var result1 = circle.drag(function(dx, dy, x, y, event) {
|
|
moved++;
|
|
expect(dx).to.be.a('number');
|
|
expect(dy).to.be.a('number');
|
|
expect(x).to.be.a('number');
|
|
expect(y).to.be.a('number');
|
|
expect(event).to.be.an('object');
|
|
}, function(x, y, event) {
|
|
started++;
|
|
expect(x).to.be.a('number');
|
|
expect(y).to.be.a('number');
|
|
expect(event).to.be.an('object');
|
|
}, function(event) {
|
|
ended++;
|
|
expect(event).to.be.an('object');
|
|
});
|
|
|
|
expect(started).to.be(0);
|
|
triggerEvent(circle, 'mousedown');
|
|
expect(started).to.be(1);
|
|
expect(moved).to.be(0);
|
|
triggerEvent(circle, 'mousemove');
|
|
expect(moved).to.be(1);
|
|
expect(ended).to.be(0);
|
|
triggerEvent(circle, 'mouseup');
|
|
expect(ended).to.be(1);
|
|
expect(result1).to.be(circle);
|
|
|
|
var result2 = circle.undrag();
|
|
triggerEvent(circle, 'mousedown');
|
|
expect(started).to.be(1);
|
|
triggerEvent(circle, 'mousemove');
|
|
expect(moved).to.be(1);
|
|
triggerEvent(circle, 'mouseup');
|
|
expect(ended).to.be(1);
|
|
// expect(result2).to.be(circle); // TODO: Make undrag return element
|
|
});
|
|
it("Element.drag - with contexts", function() {
|
|
var circle = s.circle(10, 20, 30);
|
|
var moved = 0;
|
|
var started = 0;
|
|
var ended = 0;
|
|
var result = circle.drag(function(dx, dy, x, y, event) {
|
|
moved++;
|
|
expect(dx).to.be.a('number');
|
|
expect(dy).to.be.a('number');
|
|
expect(x).to.be.a('number');
|
|
expect(y).to.be.a('number');
|
|
expect(event).to.be.an('object');
|
|
expect(this.moveContext).to.be(true);
|
|
}, function(x, y, event) {
|
|
started++;
|
|
expect(x).to.be.a('number');
|
|
expect(y).to.be.a('number');
|
|
expect(event).to.be.an('object');
|
|
expect(this.startContext).to.be(true);
|
|
}, function(event) {
|
|
ended++;
|
|
expect(event).to.be.an('object');
|
|
expect(this.endContext).to.be(true);
|
|
}, {moveContext: true}, {startContext: true}, {endContext: true});
|
|
|
|
expect(started).to.be(0);
|
|
triggerEvent(circle, 'mousedown');
|
|
expect(started).to.be(1);
|
|
expect(moved).to.be(0);
|
|
triggerEvent(circle, 'mousemove');
|
|
expect(moved).to.be(1);
|
|
expect(ended).to.be(0);
|
|
triggerEvent(circle, 'mouseup');
|
|
expect(ended).to.be(1);
|
|
expect(result).to.be(circle);
|
|
|
|
var result2 = circle.undrag();
|
|
triggerEvent(circle, 'mousedown');
|
|
expect(started).to.be(1);
|
|
triggerEvent(circle, 'mousemove');
|
|
expect(moved).to.be(1);
|
|
triggerEvent(circle, 'mouseup');
|
|
expect(ended).to.be(1);
|
|
// expect(result2).to.be(circle); // TODO: Make undrag return element
|
|
});
|
|
it("Element.hover, Element.unhover - no contexts", function() {
|
|
var circle = s.circle(10, 20, 30);
|
|
var eventIn = 0;
|
|
var eventOut = 0;
|
|
var result1 = circle.hover(function() {
|
|
eventIn++;
|
|
}, function() {
|
|
eventOut++;
|
|
});
|
|
|
|
expect(eventIn).to.be(0);
|
|
triggerEvent(circle, 'mouseover');
|
|
expect(eventIn).to.be(1);
|
|
expect(eventOut).to.be(0);
|
|
triggerEvent(circle, 'mouseout');
|
|
expect(eventOut).to.be(1);
|
|
expect(result1).to.be(circle);
|
|
|
|
var result2 = circle.unhover();
|
|
triggerEvent(circle, 'mouseover');
|
|
expect(eventIn).to.be(1);
|
|
triggerEvent(circle, 'mouseout');
|
|
expect(eventOut).to.be(1);
|
|
// expect(result2).to.be(circle); // TODO: Make unhover return element
|
|
});
|
|
it("Element.hover, Element.unhover - with contexts", function() {
|
|
var circle = s.circle(10, 20, 30);
|
|
var eventIn = 0;
|
|
var eventOut = 0;
|
|
var result1 = circle.hover(function() {
|
|
eventIn++;
|
|
expect(this.inContext).to.be(true);
|
|
}, function() {
|
|
eventOut++;
|
|
expect(this.outContext).to.be(true);
|
|
}, {inContext: true}, {outContext: true});
|
|
|
|
expect(eventIn).to.be(0);
|
|
triggerEvent(circle, 'mouseover');
|
|
expect(eventIn).to.be(1);
|
|
expect(eventOut).to.be(0);
|
|
triggerEvent(circle, 'mouseout');
|
|
expect(eventOut).to.be(1);
|
|
expect(result1).to.be(circle);
|
|
|
|
var result2 = circle.unhover();
|
|
triggerEvent(circle, 'mouseover');
|
|
expect(eventIn).to.be(1);
|
|
triggerEvent(circle, 'mouseout');
|
|
expect(eventOut).to.be(1);
|
|
// expect(result2).to.be(circle); // TODO: Make unhover return element
|
|
});
|
|
|
|
});
|