fabric
Version:
Object model for HTML5 canvas, and SVG-to-canvas parser. Backed by jsdom and node-canvas.
266 lines (221 loc) • 8.28 kB
text/typescript
import { describe, expect, it } from 'vitest';
import { Circle } from './Circle';
import { FabricObject } from './Object/FabricObject';
import { version } from '../../fabric';
import { createReferenceObject, createSVGElement } from '../../test/utils';
const REFERENCE_CIRCLE = createReferenceObject('Circle', {
radius: 0,
startAngle: 0,
endAngle: 360,
counterClockwise: false,
});
describe('Circle', () => {
it('constructor', () => {
const circle = new Circle();
expect(circle, 'should inherit from fabric.Circle').toBeInstanceOf(Circle);
expect(circle, 'should inherit from fabric.Object').toBeInstanceOf(
FabricObject,
);
// @ts-expect-error -- it is a constructor not an ordinary function
expect(circle.constructor.type).toBe('Circle');
});
it('constructor with radius', () => {
const circle = new Circle({ radius: 20 });
expect(circle.width, 'width is set').toBe(40);
expect(circle.height, 'height is set').toBe(40);
});
it('getRadiusX, getRadiusY', () => {
const circle = new Circle({ radius: 10 });
expect(circle.getRadiusX, 'getRadiusX should exist').toBeTypeOf('function');
expect(circle.getRadiusY, 'getRadiusY should exist').toBeTypeOf('function');
expect(circle.getRadiusX()).toBe(10);
expect(circle.getRadiusY()).toBe(10);
circle.scale(2);
expect(circle.getRadiusX()).toBe(20);
expect(circle.getRadiusY()).toBe(20);
circle.set('scaleX', 3);
expect(circle.getRadiusX()).toBe(30);
expect(circle.getRadiusY()).toBe(20);
circle.set('scaleY', 4);
expect(circle.getRadiusX()).toBe(30);
expect(circle.getRadiusY()).toBe(40);
});
it('setRadius', () => {
const circle = new Circle({ radius: 10, strokeWidth: 0 });
expect(circle.setRadius).toBeTypeOf('function');
expect(circle.getRadiusX()).toBe(10);
expect(circle.getRadiusY()).toBe(10);
expect(circle.width).toBe(20);
expect(circle.height).toBe(20);
circle.setRadius(20);
expect(circle.getRadiusX()).toBe(20);
expect(circle.getRadiusY()).toBe(20);
expect(circle.width).toBe(40);
expect(circle.height).toBe(40);
});
it('set radius', () => {
const circle = new Circle({ strokeWidth: 0 });
circle.set('radius', 20);
expect(circle.getRadiusX()).toBe(20);
expect(circle.getRadiusY()).toBe(20);
expect(circle.width).toBe(40);
expect(circle.height).toBe(40);
});
it('complexity', () => {
const circle = new Circle();
expect(circle.complexity).toBeTypeOf('function');
expect(circle.complexity()).toBe(1);
});
it('toObject', () => {
const circle = new Circle();
expect(circle.toObject).toBeTypeOf('function');
expect(circle.toObject()).toStrictEqual(REFERENCE_CIRCLE);
circle.set('left', 100);
circle.set('top', 200);
circle.set('radius', 15);
expect(circle.toObject()).toStrictEqual({
...REFERENCE_CIRCLE,
left: 100,
top: 200,
width: 30,
height: 30,
radius: 15,
});
});
it('toObject without defaults', () => {
const circle = new Circle({
includeDefaultValues: false,
});
expect(circle.toObject()).toStrictEqual({
type: 'Circle',
version: version,
left: 0,
top: 0,
});
});
it('toSVG with full circle', () => {
const circle = new Circle({
width: 100,
height: 100,
radius: 10,
left: 10.5,
top: 10.5,
});
const svg = circle.toSVG();
const svgClipPath = circle.toClipPathSVG();
expect(svg).toBe(
'<g transform="matrix(1 0 0 1 10.5 10.5)" >\n<circle style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(0,0,0); fill-rule: nonzero; opacity: 1;" cx="0" cy="0" r="10" />\n</g>\n',
);
expect(svgClipPath, 'circle as clipPath').toBe(
'\t<circle transform="matrix(1 0 0 1 10.5 10.5)" cx="0" cy="0" r="10" />\n',
);
});
it('toSVG with half circle', () => {
const circle = new Circle({
width: 100,
height: 100,
radius: 10,
left: 10.5,
top: 10.5,
endAngle: 180,
});
const svg = circle.toSVG();
const svgClipPath = circle.toClipPathSVG();
expect(svg).toBe(
'<g transform="matrix(1 0 0 1 10.5 10.5)" >\n<path d="M 10 0 A 10 10 0 0 1 -10 0" style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(0,0,0); fill-rule: nonzero; opacity: 1;" />\n</g>\n',
);
expect(svgClipPath, 'half circle as clipPath').toBe(
'\t<path d="M 10 0 A 10 10 0 0 1 -10 0" transform="matrix(1 0 0 1 10.5 10.5)" />\n',
);
});
it('toSVG with counterclockwise half circle', () => {
const circle = new Circle({
width: 100,
height: 100,
radius: 10,
left: 10.5,
top: 10.5,
endAngle: 180,
counterClockwise: true,
});
const svg = circle.toSVG();
const svgClipPath = circle.toClipPathSVG();
expect(svg).toBe(
'<g transform="matrix(1 0 0 1 10.5 10.5)" >\n<path d="M 10 0 A 10 10 0 0 0 -10 0" style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(0,0,0); fill-rule: nonzero; opacity: 1;" />\n</g>\n',
);
expect(svgClipPath, 'half circle as clipPath').toBe(
'\t<path d="M 10 0 A 10 10 0 0 0 -10 0" transform="matrix(1 0 0 1 10.5 10.5)" />\n',
);
});
it('fromElement', async () => {
expect(Circle.fromElement).toBeTypeOf('function');
const elCircle = createSVGElement('circle', {
r: 10,
cx: 12,
cy: 15,
fill: 'ff5555',
opacity: 0.5,
'stroke-width': 2,
'stroke-dasharray': '5, 2',
'stroke-linecap': 'round',
'stroke-linejoin': 'bevel',
'stroke-miterlimit': 5,
});
// @ts-expect-error -- svg circle element is not an HTMLElement
const oCircle = await Circle.fromElement(elCircle, {});
expect(oCircle).toBeInstanceOf(Circle);
expect(oCircle.get('radius')).toBe(10);
expect(oCircle.get('left')).toBe(2);
expect(oCircle.get('top')).toBe(5);
expect(oCircle.get('fill')).toBe('ff5555');
expect(oCircle.get('opacity')).toBe(0.5);
expect(oCircle.get('strokeWidth')).toBe(2);
expect(oCircle.get('strokeDashArray')).toStrictEqual([5, 2]);
expect(oCircle.get('strokeLineCap')).toBe('round');
expect(oCircle.get('strokeLineJoin')).toBe('bevel');
expect(oCircle.get('strokeMiterLimit')).toBe(5);
{
const elFaultyCircle = createSVGElement('circle', { r: -10 });
// @ts-expect-error -- svg circle element is not an HTMLElement
const circle = await Circle.fromElement(elFaultyCircle, {});
expect(circle.radius, 'radius will default to -10').toBe(-10);
}
{
const elFaultyCircle = createSVGElement('circle');
// @ts-expect-error -- svg circle element is not an HTMLElement
const circle = await Circle.fromElement(elFaultyCircle, {});
expect(circle.radius, 'radius will default to 0').toBe(0);
}
});
it('fromObject', async () => {
expect(Circle.fromObject).toBeTypeOf('function');
const left = 112,
top = 234,
radius = 13.45,
fill = 'ff5555';
const circle = await Circle.fromObject({
left: left,
top: top,
radius: radius,
fill: fill,
});
expect(circle).toBeInstanceOf(Circle);
expect(circle.get('left')).toBe(left);
expect(circle.get('top')).toBe(top);
expect(circle.get('radius')).toBe(radius);
expect(circle.get('fill')).toBe(fill);
const expected = circle.toObject();
const actual = await Circle.fromObject(expected);
expect(actual.toObject()).toStrictEqual(expected);
});
it('cloning and radius, width, height', async () => {
const circle = new Circle({ radius: 10, strokeWidth: 0 });
circle.scale(2);
const clone = await circle.clone();
expect(clone.width).toBe(20);
expect(clone.getScaledWidth()).toBe(40);
expect(clone.height).toBe(20);
expect(clone.getScaledHeight()).toBe(40);
expect(clone.radius).toBe(10);
});
});