extjs-gpl
Version:
GPL licensed version of Sencha Ext JS
559 lines (477 loc) • 21.2 kB
JavaScript
describe('Ext.draw.sprite.Sprite', function () {
describe('transformation matrix calculation', function () {
describe('default centers of scaling and rotation', function () {
it('should apply transformation in the following order: scale, rotate, translate', function () {
var theta = Math.PI / 2,
sin = Math.sin(theta),
cos = Math.cos(theta),
left = 100,
top = 100,
width = 100,
height = 100,
sx = 2,
sy = 0.5,
tx = 100,
ty = 50,
centerX = left + width / 2,
centerY = top + height / 2;
var rect = new Ext.draw.sprite.Rect({
x: left,
y: top,
width: width,
height: height,
rotationRads: theta,
scalingX: sx,
scalingY: sy,
translationX: tx,
translationY: ty
});
var referenceMatrix = [
cos * sx, sin * sx,
-sin * sy, cos * sy,
cos * (centerX * (1 - sx) - centerX) - sin * (centerY * (1 - sy) - centerY) + centerX + tx,
sin * (centerX * (1 - sx) - centerX) + cos * (centerY * (1 - sy) - centerY) + centerY + ty
];
rect.applyTransformations(true);
expect(rect.attr.matrix.elements).toEqual(referenceMatrix);
});
});
describe('custom centers of scaling and rotation', function () {
it('should apply transformation in the following order: scale, rotate, translate', function () {
var theta = Math.PI / 2,
sin = Math.sin(theta),
cos = Math.cos(theta),
left = 100,
top = 100,
width = 100,
height = 100,
sx = 2,
sy = 0.5,
tx = 100,
ty = 50,
scalingCenterX = 50,
scalingCenterY = 50,
rotationCenterX = 150,
rotationCenterY = 150;
var rect = new Ext.draw.sprite.Rect({
x: left,
y: top,
width: width,
height: height,
rotationRads: theta,
scalingX: sx,
scalingY: sy,
translationX: tx,
translationY: ty,
rotationCenterX: rotationCenterX,
rotationCenterY: rotationCenterY,
scalingCenterX: scalingCenterX,
scalingCenterY: scalingCenterY
});
var referenceMatrix = [
cos * sx, sin * sx,
-sin * sy, cos * sy,
cos * (scalingCenterX * (1 - sx) - rotationCenterX) - sin * (scalingCenterY * (1 - sy) - rotationCenterY) + rotationCenterX + tx,
sin * (scalingCenterX * (1 - sx) - rotationCenterX) + cos * (scalingCenterY * (1 - sy) - rotationCenterY) + rotationCenterY + ty
];
rect.applyTransformations(true);
expect(rect.attr.matrix.elements).toEqual(referenceMatrix);
});
});
});
describe('setTransform', function () {
// This is a result of scaling by (2.5, 7.5), rotating by Math.PI/4 and translating by (3,4).
var elements = [1.76776695, 1.76776695, -5.30330086, 5.30330086, 3, 4],
sprite;
beforeEach(function () {
sprite = new Ext.draw.sprite.Rect();
});
afterEach(function () {
Ext.destroy(sprite);
});
it("should use the given elements for the transformation matrix of the sprite", function () {
sprite.setTransform(elements);
var matrixElements = sprite.attr.matrix.elements;
expect(matrixElements).toEqual(elements);
});
it("should mark the sprite and its parent as dirty", function () {
var drawContainer = new Ext.draw.Container({
renderTo: Ext.getBody(),
width: 200,
height: 200
});
var surface = drawContainer.getSurface();
expect(surface.getDirty()).toBe(false);
surface.add(sprite);
expect(surface.getDirty()).toBe(true);
surface.renderFrame();
expect(surface.getDirty()).toBe(false);
sprite.setTransform(elements);
expect(sprite.attr.dirty).toBe(true);
expect(sprite.getParent().getDirty()).toBe(true);
drawContainer.destroy();
});
it("should properly calculate the inverse matrix from the given matrix", function () {
sprite.setTransform(elements);
var inverseMatrixElements = sprite.attr.inverseMatrix.elements,
precision = 8;
expect(inverseMatrixElements[0]).toBeCloseTo(0.28284271, precision);
expect(inverseMatrixElements[1]).toBeCloseTo(-0.0942809, precision);
expect(inverseMatrixElements[2]).toBeCloseTo(0.28284271, precision);
expect(inverseMatrixElements[3]).toBeCloseTo(0.0942809, precision);
expect(inverseMatrixElements[4]).toBeCloseTo(-1.97989899, precision);
expect(inverseMatrixElements[5]).toBeCloseTo(-0.0942809, precision);
});
it("should mark bbox transform as dirty", function () {
sprite.setTransform(elements);
expect(sprite.attr.bbox.transform.dirty).toBe(true);
});
it("should not update the transformation attributes by default", function () {
var attr = sprite.attr,
rotationRads = attr.rotationRads,
rotationCenterX = attr.rotationCenterX,
rotationCenterY = attr.rotationCenterY,
scalingX = attr.scalingX,
scalingY = attr.scalingY,
scalingCenterX = attr.scalingCenterX,
scalingCenterY = attr.scalingCenterY,
translationX = attr.translationX,
translationY = attr.translationY;
sprite.setTransform(elements);
expect(attr.rotationRads).toEqual(rotationRads);
expect(attr.rotationCenterX).toEqual(rotationCenterX);
expect(attr.rotationCenterY).toEqual(rotationCenterY);
expect(attr.scalingX).toEqual(scalingX);
expect(attr.scalingY).toEqual(scalingY);
expect(attr.scalingCenterX).toEqual(scalingCenterX);
expect(attr.scalingCenterY).toEqual(scalingCenterY);
expect(attr.translationX).toEqual(translationX);
expect(attr.translationY).toEqual(translationY);
});
it("should update the transformation attributes, if explicitly asked", function () {
var attr = sprite.attr,
precision = 8;
sprite.setTransform(elements, true);
expect(attr.rotationRads).toBeCloseTo(Math.PI / 4, precision);
expect(attr.rotationCenterX).toEqual(0);
expect(attr.rotationCenterY).toEqual(0);
expect(attr.scalingX).toBeCloseTo(2.5, precision);
expect(attr.scalingY).toBeCloseTo(7.5, precision);
expect(attr.scalingCenterX).toEqual(0);
expect(attr.scalingCenterY).toEqual(0);
expect(attr.translationX).toEqual(3);
expect(attr.translationY).toEqual(4);
});
it("should not modify the given array", function () {
sprite.setTransform(elements);
sprite.attr.matrix.rotate(Math.PI / 4);
expect(elements).toEqual([1.76776695, 1.76776695, -5.30330086, 5.30330086, 3, 4]);
});
it("should return the sprite itself", function () {
var result = sprite.transform([1, 0, 0, 1, 100, 100]);
expect(result).toEqual(sprite);
});
});
describe('resetTransform', function () {
var spriteConfig = {
type: 'rect',
x: 0,
y: 0,
width: 100,
height: 100,
rotationCenterX: 0,
rotationCenterY: 0,
rotationRads: Math.PI / 3,
scalingCenterX: 0,
scalingCenterY: 0,
scalingX: 2,
scalingY: 3,
translationX: 50,
translationY: 50
};
it("should mark the sprite and its parent as dirty", function () {
var drawContainer = new Ext.draw.Container({
renderTo: Ext.getBody(),
width: 200,
height: 200
});
var surface = drawContainer.getSurface();
expect(surface.getDirty()).toBe(false);
var sprite = surface.add(spriteConfig);
expect(surface.getDirty()).toBe(true);
surface.renderFrame();
expect(surface.getDirty()).toBe(false);
sprite.resetTransform();
expect(sprite.attr.dirty).toBe(true);
expect(sprite.getParent().getDirty()).toBe(true);
drawContainer.destroy();
});
it("should reset the transformation matrix and its reverse to the identity matrix", function () {
var sprite = new Ext.draw.sprite.Rect(spriteConfig),
identityMatrixElements = [1, 0, 0, 1, 0, 0];
sprite.applyTransformations(true);
expect(sprite.attr.matrix.elements).not.toEqual(identityMatrixElements);
sprite.resetTransform();
expect(sprite.attr.matrix.elements).toEqual(identityMatrixElements);
expect(sprite.attr.inverseMatrix.elements).toEqual(identityMatrixElements);
sprite.destroy();
});
it("should return the sprite itself", function () {
var sprite = new Ext.draw.sprite.Rect(),
result = sprite.transform([1, 0, 0, 1, 100, 100]);
expect(result).toEqual(sprite);
sprite.destroy();
});
});
describe('transform', function () {
it("should multiply the given matrix with the current transformation matrix", function () {
var sprite = new Ext.draw.sprite.Rect(),
precision = 12;
sprite.attr.matrix.elements = [1, 2, 3, 4, 5, 6];
sprite.transform([1, 2, 3, 4, 5, 6]);
expect(sprite.attr.matrix.elements).toEqual([7, 10, 15, 22, 28, 40]);
var inverseMatrixElements = sprite.attr.inverseMatrix.elements;
expect(inverseMatrixElements[0]).toBeCloseTo(5.5, precision);
expect(inverseMatrixElements[1]).toBeCloseTo(-2.5, precision);
expect(inverseMatrixElements[2]).toBeCloseTo(-3.75, precision);
expect(inverseMatrixElements[3]).toBeCloseTo(1.75, precision);
expect(inverseMatrixElements[4]).toBeCloseTo(-4, precision);
expect(inverseMatrixElements[5]).toBeCloseTo(0, precision);
});
it("should pre-multiply the current matrix with the given matrix", function () {
var sprite = new Ext.draw.sprite.Rect(),
scale = [2, 0, 0, 3, 0, 0],
translate = [1, 0, 0, 1, 100, 100],
p = [2, 4],
tp;
// Initially, sprite's matrix is identity matrix.
// First scale the grid, then translate.
// S * T * I = identity.prepend(translate).prepend(scale)
sprite.transform(translate).transform(scale);
expect(sprite.attr.matrix.elements).toEqual([2, 0, 0, 3, 200, 300]);
tp = sprite.attr.matrix.transformPoint(p);
// Transformed point in original grid coordinates.
expect(tp).toEqual([204, 312]);
sprite.resetTransform();
// First translate the grid, then scale.
// T * S * I = identity.prepend(scale).prepend(translate)
sprite.transform(scale).transform(translate);
expect(sprite.attr.matrix.elements).toEqual([2, 0, 0, 3, 100, 100]);
tp = sprite.attr.matrix.transformPoint(p);
expect(tp).toEqual([104, 112]);
sprite.destroy();
});
it("should return the sprite itself", function () {
var sprite = new Ext.draw.sprite.Rect(),
result = sprite.transform([1, 0, 0, 1, 100, 100]);
expect(result).toEqual(sprite);
sprite.destroy();
});
});
describe('remove', function () {
it("should remove itself from the surface, returning itself or null (if already removed)", function () {
var surface = new Ext.draw.Surface({}),
sprite = new Ext.draw.sprite.Rect({}),
id = sprite.getId(),
result;
surface.add(sprite);
result = sprite.remove();
expect(surface.getItems().length).toBe(0);
expect(surface.get(id)).toBe(undefined);
expect(result).toEqual(sprite);
result = sprite.remove(); // sprite with no surface, expect not to throw
expect(result).toBe(null);
sprite.destroy();
surface.destroy();
});
});
describe('destroy', function () {
it("should remove itself from the surface", function () {
var surface = new Ext.draw.Surface({}),
sprite = new Ext.draw.sprite.Rect({}),
id = sprite.getId();
surface.add(sprite);
sprite.destroy();
expect(surface.getItems().length).toBe(0);
expect(surface.get(id)).toBe(undefined);
surface.destroy();
});
});
describe("isVisible", function () {
var none = 'none',
rgba_none = 'rgba(0,0,0,0)',
sprite, surface, container;
beforeEach(function () {
container = new Ext.draw.Container({
renderTo: Ext.getBody()
});
surface = new Ext.draw.Surface();
sprite = new Ext.draw.sprite.Rect({
hidden: false,
globalAlpha: 1,
fillOpacity: 1,
strokeOpacity: 1,
fillStyle: 'red',
strokeStyle: 'red'
});
surface.add(sprite);
container.add(surface);
});
afterEach(function () {
Ext.destroy(sprite, surface, container);
});
it("should return true if the sprite belongs to a visible parent, false otherwise", function () {
expect(sprite.isVisible()).toBe(true);
surface.remove(sprite);
expect(sprite.isVisible()).toBe(false);
var instancing = new Ext.draw.sprite.Instancing({
template: sprite
});
surface.add(instancing);
expect(sprite.isVisible()).toBe(true);
instancing.destroy();
});
it("should return false if the sprite belongs to a parent that doesn't belong to a surface", function () {
var instancing = new Ext.draw.sprite.Instancing({
template: sprite
});
expect(sprite.isVisible()).toBe(false);
});
it("should return false in case the sprite is hidden", function () {
sprite.hide();
expect(sprite.isVisible()).toBe(false);
});
it("should return false in case the sprite has no fillStyle and strokeStyle, true otherwise", function () {
sprite.setAttributes({
fillStyle: none
});
expect(sprite.isVisible()).toBe(true);
sprite.setAttributes({
fillStyle: rgba_none
});
expect(sprite.isVisible()).toBe(true);
sprite.setAttributes({
fillStyle: 'red',
strokeStyle: none
});
expect(sprite.isVisible()).toBe(true);
sprite.setAttributes({
strokeStyle: rgba_none
});
expect(sprite.isVisible()).toBe(true);
sprite.setAttributes({
fillStyle: none,
strokeStyle: none
});
expect(sprite.isVisible()).toBe(false);
sprite.setAttributes({
fillStyle: none,
strokeStyle: rgba_none
});
expect(sprite.isVisible()).toBe(false);
sprite.setAttributes({
fillStyle: rgba_none,
strokeStyle: none
});
expect(sprite.isVisible()).toBe(false);
sprite.setAttributes({
fillStyle: rgba_none,
strokeStyle: rgba_none
});
expect(sprite.isVisible()).toBe(false);
});
it("should return false if the globalAlpha attribute is zero", function () {
sprite.setAttributes({
globalAlpha: 0
});
expect(sprite.isVisible()).toBe(false);
});
it("should return false if both fill and stroke are completely transparent, true otherwise", function () {
sprite.setAttributes({
fillOpacity: 0,
strokeOpacity: 0
});
expect(sprite.isVisible()).toBe(false);
sprite.setAttributes({
fillOpacity: 0,
strokeOpacity: 0.01
});
expect(sprite.isVisible()).toBe(true);
sprite.setAttributes({
fillOpacity: 0.01,
strokeOpacity: 0
});
expect(sprite.isVisible()).toBe(true);
});
});
describe("hitTest", function () {
var sprite, surface, container;
beforeEach(function () {
container = new Ext.draw.Container({
renderTo: Ext.getBody()
});
surface = new Ext.draw.Surface();
sprite = new Ext.draw.sprite.Circle({
hidden: false,
globalAlpha: 1,
fillOpacity: 1,
strokeOpacity: 1,
fillStyle: 'red',
strokeStyle: 'red',
r: 100,
cx: 100,
cy: 100
});
surface.add(sprite);
container.add(surface);
});
afterEach(function () {
Ext.destroy(sprite, surface, container);
});
it("should return an object with the 'sprite' property set to the sprite itself, " +
"if the sprite is visible and its bounding box is hit", function () {
// Testing hitTest method of the abstract Sprite class.
// Even though, (10,10) is not inside the circle, it's inside it's bounding box.
var result = Ext.draw.sprite.Sprite.prototype.hitTest.call(sprite, [10, 10]);
expect(result && result.sprite).toBe(sprite);
});
it("should return null, if the sprite's bounding box is hit, but the sprite is not visible", function () {
var originalMethod = sprite.isVisible;
sprite.isVisible = function () { return false; };
var result = Ext.draw.sprite.Sprite.prototype.hitTest.call(sprite, [10, 10]);
expect(result).toBe(null);
sprite.isVisible = originalMethod;
});
it("should return null, if the sprite is visible, but it's bounding box is not hit", function () {
var result = Ext.draw.sprite.Sprite.prototype.hitTest.call(sprite, [210, 210]);
expect(result).toBe(null);
});
});
describe("getAnimation", function () {
it("should return the stored reference to the sprite's animation modifier", function () {
var sprite = new Ext.draw.sprite.Rect();
expect(sprite.getAnimation()).toEqual(sprite.fx);
});
});
describe("setAnimation", function () {
it("should set the config of the Animation modifier of a sprite", function () {
var sprite = new Ext.draw.sprite.Rect();
var config = {
duration: 2000,
easing: 'bounceOut',
customEasings: {
x: 'linear'
},
customDurations: {
y: 1000
}
};
sprite.setAnimation(config);
var actualConfig = sprite.fx.getInitialConfig();
expect(actualConfig.duration).toEqual(config.duration);
expect(actualConfig.easing).toEqual(config.easing);
expect(actualConfig.customEasings).toEqual(config.customEasings);
expect(actualConfig.customDurations).toEqual(config.customDurations);
});
});
});