- Fix router import path in main.js - Handle Django REST Framework pagination format in API calls - Add getTemplates function to project API - Restart frontend development server
510 lines
15 KiB
TypeScript
510 lines
15 KiB
TypeScript
import { describe, it, expect } from 'vitest';
|
|
import { Point } from '../Point';
|
|
import { Polygon } from './Polygon';
|
|
import { Polyline } from './Polyline';
|
|
import { FabricObject } from './Object/FabricObject';
|
|
import { createReferenceObject, createSVGElement } from '../../test/utils';
|
|
|
|
function getPoints() {
|
|
return [
|
|
{ x: 10, y: 12 },
|
|
{ x: 20, y: 22 },
|
|
];
|
|
}
|
|
|
|
const REFERENCE_OBJECT = createReferenceObject('Polygon', {
|
|
left: 15,
|
|
top: 17,
|
|
width: 10,
|
|
height: 10,
|
|
points: getPoints(),
|
|
});
|
|
|
|
const REFERENCE_EMPTY_OBJECT = {
|
|
points: [],
|
|
width: 0,
|
|
height: 0,
|
|
top: 0,
|
|
left: 0,
|
|
};
|
|
|
|
describe('Polygon', () => {
|
|
it('constructor', () => {
|
|
expect(Polygon, 'Polygon class should exist').toBeTruthy();
|
|
|
|
const polygon = new Polygon(getPoints());
|
|
|
|
expect(polygon, 'should be instance of Polygon').toBeInstanceOf(Polygon);
|
|
expect(polygon, 'should be instance of Polyline').toBeInstanceOf(Polyline);
|
|
expect(polygon, 'should be instance of FabricObject').toBeInstanceOf(
|
|
FabricObject,
|
|
);
|
|
|
|
expect(polygon.constructor, 'type should be Polygon').toHaveProperty(
|
|
'type',
|
|
'Polygon',
|
|
);
|
|
expect(polygon.get('points'), 'points should match input').toEqual([
|
|
{ x: 10, y: 12 },
|
|
{ x: 20, y: 22 },
|
|
]);
|
|
});
|
|
|
|
it('constructor, with strokeWidth top-left and origins top-left', () => {
|
|
const polygon = new Polygon(getPoints(), {
|
|
strokeWidth: 2,
|
|
originX: 'left',
|
|
originY: 'top',
|
|
});
|
|
|
|
expect(polygon.left, 'left should be 9').toBe(9);
|
|
expect(polygon.top, 'top should be 11').toBe(11);
|
|
});
|
|
|
|
it('constructor, with strokeWidth top-left and origins center-center', () => {
|
|
const polygon = new Polygon(getPoints(), {
|
|
strokeWidth: 2,
|
|
originX: 'center',
|
|
originY: 'center',
|
|
});
|
|
|
|
expect(polygon.left, 'left should be 15').toBe(15);
|
|
expect(polygon.top, 'top should be 17').toBe(17);
|
|
});
|
|
|
|
it('constructor, with strokeWidth top-left and origins bottom-right', () => {
|
|
const polygon = new Polygon(getPoints(), {
|
|
strokeWidth: 2,
|
|
originX: 'right',
|
|
originY: 'bottom',
|
|
});
|
|
|
|
expect(polygon.left, 'left should be 21').toBe(21);
|
|
expect(polygon.top, 'top should be 23').toBe(23);
|
|
});
|
|
|
|
it('polygon with exactBoundingBox false', () => {
|
|
const polygon = new Polygon(
|
|
[
|
|
{ x: 10, y: 10 },
|
|
{ x: 20, y: 10 },
|
|
{ x: 20, y: 100 },
|
|
],
|
|
{
|
|
// @ts-expect-error -- TODO: are types wrong for Polygon? seems like it doesn't accept exactBoundingBox property
|
|
exactBoundingBox: false,
|
|
strokeWidth: 60,
|
|
},
|
|
);
|
|
|
|
const dimensions = polygon._getNonTransformedDimensions();
|
|
|
|
expect(dimensions.x, 'x dimension should be 70').toBe(70);
|
|
expect(dimensions.y, 'y dimension should be 150').toBe(150);
|
|
});
|
|
|
|
it('polygon with exactBoundingBox true', () => {
|
|
const polygon = new Polygon(
|
|
[
|
|
{ x: 10, y: 10 },
|
|
{ x: 10, y: 10 },
|
|
{ x: 20, y: 10 },
|
|
{ x: 20, y: 10 },
|
|
{
|
|
x: 20,
|
|
y: 10,
|
|
},
|
|
{ x: 20, y: 100 },
|
|
{ x: 10, y: 10 },
|
|
],
|
|
{
|
|
// @ts-expect-error -- TODO: are types wrong for Polygon? seems like it doesn't accept exactBoundingBox property
|
|
exactBoundingBox: true,
|
|
strokeWidth: 60,
|
|
stroke: 'blue',
|
|
},
|
|
);
|
|
|
|
const limitedMiter = polygon._getNonTransformedDimensions();
|
|
|
|
expect(Math.round(limitedMiter.x), 'limited miter x').toBe(74);
|
|
expect(Math.round(limitedMiter.y), 'limited miter y').toBe(123);
|
|
expect(polygon._getTransformedDimensions(), 'dims should match').toEqual(
|
|
limitedMiter,
|
|
);
|
|
|
|
polygon.set('strokeMiterLimit', 999);
|
|
const miter = polygon._getNonTransformedDimensions();
|
|
|
|
expect(Math.round(miter.x), 'miter x').toBe(74);
|
|
expect(Math.round(miter.y), 'miter y').toBe(662);
|
|
expect(polygon._getTransformedDimensions(), 'dims should match').toEqual(
|
|
miter,
|
|
);
|
|
|
|
polygon.set('strokeLineJoin', 'bevel');
|
|
const bevel = polygon._getNonTransformedDimensions();
|
|
|
|
expect(Math.round(limitedMiter.x), 'bevel x').toBe(74);
|
|
expect(Math.round(limitedMiter.y), 'bevel y').toBe(123);
|
|
expect(polygon._getTransformedDimensions(), 'dims should match').toEqual(
|
|
bevel,
|
|
);
|
|
|
|
polygon.set('strokeLineJoin', 'round');
|
|
const round = polygon._getNonTransformedDimensions();
|
|
|
|
expect(Math.round(round.x), 'round x').toBe(70);
|
|
expect(Math.round(round.y), 'round y').toBe(150);
|
|
expect(polygon._getTransformedDimensions(), 'dims should match').toEqual(
|
|
round,
|
|
);
|
|
});
|
|
|
|
it.todo('polygon with exactBoundingBox true and skew', () => {
|
|
const polygon = new Polygon(
|
|
[
|
|
{ x: 10, y: 10 },
|
|
{ x: 20, y: 10 },
|
|
{ x: 20, y: 100 },
|
|
],
|
|
{
|
|
// @ts-expect-error -- TODO: are types wrong for Polygon? seems like it doesn't accept exactBoundingBox property
|
|
exactBoundingBox: true,
|
|
strokeWidth: 60,
|
|
stroke: 'blue',
|
|
skewX: 30,
|
|
skewY: 45,
|
|
},
|
|
);
|
|
|
|
const limitedMiter = polygon._getNonTransformedDimensions();
|
|
|
|
expect(Math.round(limitedMiter.x), 'limited miter x').toBe(185);
|
|
expect(Math.round(limitedMiter.y), 'limited miter y').toBe(194);
|
|
expect(polygon._getTransformedDimensions(), 'dims should match').toEqual(
|
|
limitedMiter,
|
|
);
|
|
|
|
polygon.set('strokeMiterLimit', 999);
|
|
const miter = polygon._getNonTransformedDimensions();
|
|
|
|
expect(Math.round(miter.x), 'miter x').toBe(498);
|
|
expect(Math.round(miter.y), 'miter y').toBe(735);
|
|
expect(polygon._getTransformedDimensions(), 'dims should match').toEqual(
|
|
miter,
|
|
);
|
|
|
|
polygon.set('strokeLineJoin', 'bevel');
|
|
const bevel = polygon._getNonTransformedDimensions();
|
|
|
|
expect(Math.round(limitedMiter.x), 'bevel x').toBe(185);
|
|
expect(Math.round(limitedMiter.y), 'bevel y').toBe(194);
|
|
expect(polygon._getTransformedDimensions(), 'dims should match').toEqual(
|
|
bevel,
|
|
);
|
|
|
|
polygon.set('strokeLineJoin', 'round');
|
|
const round = polygon._getNonTransformedDimensions();
|
|
|
|
// WRONG value! was buggy when writing test
|
|
expect(Math.round(round.x), 'round x').toBe(170);
|
|
expect(Math.round(round.y), 'round y').toBe(185);
|
|
expect(polygon._getTransformedDimensions(), 'dims should match').toEqual(
|
|
round,
|
|
);
|
|
});
|
|
|
|
it('complexity', () => {
|
|
const polygon = new Polygon(getPoints());
|
|
|
|
expect(polygon.complexity, 'complexity should be a function').toBeTypeOf(
|
|
'function',
|
|
);
|
|
});
|
|
|
|
it('toObject', () => {
|
|
const polygon = new Polygon(getPoints());
|
|
|
|
expect(polygon.toObject, 'toObject should be a function').toBeTypeOf(
|
|
'function',
|
|
);
|
|
|
|
expect(
|
|
{
|
|
...polygon.toObject(),
|
|
points: getPoints(),
|
|
},
|
|
'polygon object should match reference',
|
|
).toEqual(REFERENCE_OBJECT);
|
|
});
|
|
|
|
it('toSVG', () => {
|
|
const polygon = new Polygon(getPoints(), { fill: 'red', stroke: 'blue' });
|
|
|
|
expect(polygon.toSVG, 'toSVG should be a function').toBeTypeOf('function');
|
|
|
|
const EXPECTED_SVG =
|
|
'<g transform="matrix(1 0 0 1 15 17)" >\n<polygon style="stroke: rgb(0,0,255); stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(255,0,0); fill-rule: nonzero; opacity: 1;" points="-5,-5 5,5" />\n</g>\n';
|
|
|
|
expect(polygon.toSVG(), 'SVG output should match expected').toBe(
|
|
EXPECTED_SVG,
|
|
);
|
|
});
|
|
|
|
it('fromObject', async () => {
|
|
expect(Polygon.fromObject, 'fromObject should be a function').toBeTypeOf(
|
|
'function',
|
|
);
|
|
|
|
const polygon = await Polygon.fromObject(REFERENCE_OBJECT);
|
|
|
|
expect(polygon, 'should be instance of Polygon').toBeInstanceOf(Polygon);
|
|
expect(polygon.toObject(), 'polygon object should match reference').toEqual(
|
|
REFERENCE_OBJECT,
|
|
);
|
|
});
|
|
|
|
it('fromElement without points', async () => {
|
|
expect(Polygon.fromElement, 'fromElement should be a function').toBeTypeOf(
|
|
'function',
|
|
);
|
|
|
|
const elPolygonWithoutPoints = createSVGElement('polygon', {
|
|
'stroke-width': 0,
|
|
});
|
|
|
|
const polygon = await Polygon.fromElement(elPolygonWithoutPoints);
|
|
|
|
expect(polygon.toObject(), 'polygon object should match reference').toEqual(
|
|
{
|
|
...REFERENCE_OBJECT,
|
|
...REFERENCE_EMPTY_OBJECT,
|
|
strokeWidth: 0,
|
|
},
|
|
);
|
|
});
|
|
|
|
it('fromElement without points but strokeWidth', async () => {
|
|
const elPolygonWithoutPoints = createSVGElement('polygon');
|
|
|
|
const polygon = await Polygon.fromElement(elPolygonWithoutPoints);
|
|
|
|
expect(polygon.toObject(), 'polygon object should match reference').toEqual(
|
|
{
|
|
...REFERENCE_OBJECT,
|
|
...REFERENCE_EMPTY_OBJECT,
|
|
left: 0,
|
|
top: 0,
|
|
},
|
|
);
|
|
});
|
|
|
|
it('fromElement with empty points', async () => {
|
|
const elPolygonWithEmptyPoints = createSVGElement('polygon', {
|
|
points: '',
|
|
});
|
|
|
|
const polygon = await Polygon.fromElement(elPolygonWithEmptyPoints);
|
|
|
|
expect(polygon.toObject(), 'polygon object should match reference').toEqual(
|
|
{
|
|
...REFERENCE_OBJECT,
|
|
...REFERENCE_EMPTY_OBJECT,
|
|
left: 0,
|
|
top: 0,
|
|
},
|
|
);
|
|
});
|
|
|
|
it('fromElement with points', async () => {
|
|
const elPolygon = createSVGElement('polygon', { points: '10,12 20,22' });
|
|
|
|
const polygon = await Polygon.fromElement(elPolygon);
|
|
|
|
expect(polygon, 'should be instance of Polygon').toBeInstanceOf(Polygon);
|
|
expect(polygon.toObject(), 'polygon object should match reference').toEqual(
|
|
{
|
|
...REFERENCE_OBJECT,
|
|
points: [
|
|
{ x: 10, y: 12 },
|
|
{ x: 20, y: 22 },
|
|
],
|
|
left: 15,
|
|
top: 17,
|
|
},
|
|
);
|
|
});
|
|
|
|
it('fromElement with points no strokewidth', async () => {
|
|
const elPolygon = createSVGElement('polygon', {
|
|
points: '10,12 20,22',
|
|
'stroke-width': 0,
|
|
});
|
|
|
|
const polygon = await Polygon.fromElement(elPolygon);
|
|
|
|
expect(polygon, 'should be instance of Polygon').toBeInstanceOf(Polygon);
|
|
expect(polygon.toObject(), 'polygon object should match reference').toEqual(
|
|
{
|
|
...REFERENCE_OBJECT,
|
|
strokeWidth: 0,
|
|
points: [
|
|
{ x: 10, y: 12 },
|
|
{ x: 20, y: 22 },
|
|
],
|
|
left: 15,
|
|
top: 17,
|
|
},
|
|
);
|
|
});
|
|
|
|
it('fromElement with points and custom attributes', async () => {
|
|
const elPolygonWithAttrs = createSVGElement('polygon', {
|
|
points: '10,10 20,20 30,30 10,10',
|
|
fill: 'rgb(255,255,255)',
|
|
opacity: 0.34,
|
|
'stroke-width': 3,
|
|
stroke: 'blue',
|
|
transform: 'translate(-10,-20) scale(2)',
|
|
'stroke-dasharray': '5, 2',
|
|
'stroke-linecap': 'round',
|
|
'stroke-linejoin': 'bevel',
|
|
'stroke-miterlimit': 5,
|
|
});
|
|
|
|
const polygonWithAttrs = await Polygon.fromElement(elPolygonWithAttrs);
|
|
|
|
const expectedPoints = [
|
|
{ x: 10, y: 10 },
|
|
{ x: 20, y: 20 },
|
|
{ x: 30, y: 30 },
|
|
{ x: 10, y: 10 },
|
|
];
|
|
|
|
expect(
|
|
polygonWithAttrs.toObject(),
|
|
'polygon object should match reference',
|
|
).toEqual({
|
|
...REFERENCE_OBJECT,
|
|
width: 20,
|
|
height: 20,
|
|
fill: 'rgb(255,255,255)',
|
|
stroke: 'blue',
|
|
strokeWidth: 3,
|
|
strokeDashArray: [5, 2],
|
|
strokeLineCap: 'round',
|
|
strokeLineJoin: 'bevel',
|
|
strokeMiterLimit: 5,
|
|
opacity: 0.34,
|
|
points: expectedPoints,
|
|
top: 20,
|
|
left: 20,
|
|
});
|
|
});
|
|
|
|
it('_calcDimensions with object options', () => {
|
|
const polygon = new Polygon(getPoints(), {
|
|
scaleX: 2,
|
|
scaleY: 3,
|
|
skewX: 20,
|
|
skewY: 30,
|
|
strokeWidth: 20,
|
|
strokeMiterLimit: 10,
|
|
strokeUniform: false,
|
|
strokeLineJoin: 'miter',
|
|
// @ts-expect-error -- TODO: are types wrong for Polygon? seems like it doesn't accept exactBoundingBox property
|
|
exactBoundingBox: true,
|
|
});
|
|
|
|
const { left, top, width, height, pathOffset, strokeOffset, strokeDiff } =
|
|
polygon._calcDimensions();
|
|
|
|
// Types
|
|
expect(typeof left, 'left should be a number').toBe('number');
|
|
expect(typeof top, 'top should be a number').toBe('number');
|
|
expect(typeof width, 'width should be a number').toBe('number');
|
|
expect(typeof height, 'height should be a number').toBe('number');
|
|
expect(pathOffset, 'pathOffset should be a Point').toBeInstanceOf(Point);
|
|
expect(strokeOffset, 'strokeOffset should be a Point').toBeInstanceOf(
|
|
Point,
|
|
);
|
|
expect(strokeDiff, 'strokeDiff should be a Point').toBeInstanceOf(Point);
|
|
|
|
// Values
|
|
expect(left, 'left should match expected value').toBe(10.485714075442775);
|
|
expect(top, 'top should match expected value').toBe(14.784917784669414);
|
|
expect(width, 'width should match expected value').toBe(27.707709196083425);
|
|
expect(height, 'height should match expected value').toBe(
|
|
21.750672506349947,
|
|
);
|
|
expect(pathOffset, 'pathOffset should match expected value').toEqual(
|
|
new Point(14.999999999999998, 17.000000000000004),
|
|
);
|
|
expect(strokeOffset, 'strokeOffset should match expected value').toEqual(
|
|
new Point(11.966623726115365, 8.965754721680533),
|
|
);
|
|
expect(strokeDiff, 'strokeDiff should match expected value').toEqual(
|
|
new Point(23.933247452230738, 17.931509443361065),
|
|
);
|
|
});
|
|
|
|
it('_calcDimensions with custom options', () => {
|
|
const polygon = new Polygon(getPoints(), {
|
|
scaleX: 2,
|
|
scaleY: 3,
|
|
skewX: 20,
|
|
skewY: 30,
|
|
strokeWidth: 20,
|
|
strokeMiterLimit: 10,
|
|
strokeUniform: false,
|
|
strokeLineJoin: 'miter',
|
|
// @ts-expect-error -- TODO: are types wrong for Polygon? seems like it doesn't accept exactBoundingBox property
|
|
exactBoundingBox: true,
|
|
});
|
|
|
|
const customOptions = {
|
|
scaleX: 4,
|
|
scaleY: 2,
|
|
skewX: 0,
|
|
skewY: 20,
|
|
strokeWidth: 10,
|
|
strokeMiterLimit: 20,
|
|
strokeUniform: true,
|
|
strokeLineJoin: 'miter',
|
|
exactBoundingBox: true,
|
|
} as const;
|
|
|
|
const { left, top, width, height, pathOffset, strokeOffset, strokeDiff } =
|
|
polygon._calcDimensions(customOptions);
|
|
|
|
// Types
|
|
expect(typeof left, 'left should be a number').toBe('number');
|
|
expect(typeof top, 'top should be a number').toBe('number');
|
|
expect(typeof width, 'width should be a number').toBe('number');
|
|
expect(typeof height, 'height should be a number').toBe('number');
|
|
expect(pathOffset, 'pathOffset should be a Point').toBeInstanceOf(Point);
|
|
expect(strokeOffset, 'strokeOffset should be a Point').toBeInstanceOf(
|
|
Point,
|
|
);
|
|
expect(strokeDiff, 'strokeDiff should be a Point').toBeInstanceOf(Point);
|
|
|
|
// Values
|
|
expect(left, 'left should match expected value').toBe(9.440983005625053);
|
|
expect(top, 'top should match expected value').toBe(13.60709991156367);
|
|
expect(width, 'width should match expected value').toBe(11.118033988749893);
|
|
expect(height, 'height should match expected value').toBe(
|
|
17.704907204858728,
|
|
);
|
|
expect(pathOffset, 'pathOffset should match expected value').toEqual(
|
|
new Point(6.825391045997646, 18.518912156261834),
|
|
);
|
|
expect(strokeOffset, 'strokeOffset should match expected value').toEqual(
|
|
new Point(1.1180339887498931, 6.097807293295057),
|
|
);
|
|
expect(strokeDiff, 'strokeDiff should match expected value').toEqual(
|
|
new Point(2.2360679774997863, 12.195614586590114),
|
|
);
|
|
});
|
|
});
|